MsgAssistant.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import { Button, Dropdown, message, Space, Tooltip, Typography } from "antd";
  2. import type { Message } from "./AiChat";
  3. import {
  4. CopyOutlined,
  5. ReloadOutlined,
  6. LeftOutlined,
  7. RightOutlined,
  8. } from "@ant-design/icons";
  9. import type { IAiModel } from "../../api/ai";
  10. import { useEffect, useState } from "react";
  11. import type { MenuProps } from "antd/es/menu";
  12. import Marked from "../general/Marked";
  13. import MsgContainer from "./MsgContainer";
  14. const { Text } = Typography;
  15. interface IWidget {
  16. msg?: Message;
  17. models?: IAiModel[];
  18. onRefresh?: (modelId: string) => void;
  19. }
  20. const MsgAssistant = ({ msg, models, onRefresh }: IWidget) => {
  21. const [currentVersion, setCurrentVersion] = useState(0);
  22. useEffect(() => {
  23. if (msg) {
  24. setCurrentVersion(msg?.versions.length - 1);
  25. }
  26. }, [msg]);
  27. const switchMessageVersion = (direction: "prev" | "next"): void => {
  28. if (msg && msg.versions) {
  29. const maxIndex = msg.versions.length - 1;
  30. let newIndex = currentVersion;
  31. if (direction === "prev" && currentVersion > 0) {
  32. newIndex = currentVersion - 1;
  33. } else if (direction === "next" && currentVersion < maxIndex) {
  34. newIndex = currentVersion + 1;
  35. }
  36. setCurrentVersion(newIndex);
  37. }
  38. };
  39. const refreshMenu: MenuProps = {
  40. onClick: ({ key }) => {
  41. if (key === "refresh" && msg) {
  42. onRefresh && onRefresh(msg.versions[currentVersion].model);
  43. }
  44. },
  45. items: [
  46. {
  47. key: "refresh",
  48. label: "重新生成",
  49. },
  50. {
  51. type: "divider",
  52. },
  53. {
  54. key: "model-submenu",
  55. label: "选择模型重新生成",
  56. children: models?.map((model, _id) => ({
  57. key: model.uid,
  58. label: model.name,
  59. onClick: () => {
  60. onRefresh && onRefresh(model.uid);
  61. },
  62. })),
  63. },
  64. ],
  65. };
  66. return (
  67. <MsgContainer>
  68. <div
  69. style={{
  70. fontSize: "14px",
  71. fontWeight: 500,
  72. marginBottom: "4px",
  73. }}
  74. >
  75. {msg?.versions[currentVersion].model
  76. ? models?.find((m) => m.uid === msg.versions[currentVersion].model)
  77. ?.name
  78. : "AI助手"}
  79. </div>
  80. <div>
  81. <Marked text={msg?.versions[currentVersion].content} />
  82. </div>
  83. <div>
  84. <Space>
  85. {msg?.versions && msg.versions.length > 1 && (
  86. <div style={{ marginBottom: "8px" }}>
  87. <Space size="small">
  88. <Button
  89. size="small"
  90. type="text"
  91. icon={<LeftOutlined />}
  92. disabled={currentVersion === 0}
  93. onClick={() => switchMessageVersion("prev")}
  94. />
  95. <Text
  96. style={{
  97. fontSize: "12px",
  98. color:
  99. msg.type === "user" ? "rgba(255,255,255,0.7)" : "#666",
  100. }}
  101. >
  102. {(currentVersion || 0) + 1}/{msg.versions.length}
  103. </Text>
  104. <Button
  105. size="small"
  106. type="text"
  107. icon={<RightOutlined />}
  108. disabled={currentVersion === msg.versions.length - 1}
  109. onClick={() => switchMessageVersion("next")}
  110. />
  111. </Space>
  112. </div>
  113. )}
  114. <div>
  115. <Space size="small">
  116. <Tooltip title="复制">
  117. <Button
  118. size="small"
  119. type="text"
  120. icon={<CopyOutlined />}
  121. onClick={() => {
  122. msg &&
  123. navigator.clipboard
  124. .writeText(msg.versions[currentVersion].content)
  125. .then((_value) => message.success("已复制到剪贴板"))
  126. .catch((reason: any) => {
  127. console.error("复制失败:", reason);
  128. message.error("复制失败");
  129. });
  130. }}
  131. />
  132. </Tooltip>
  133. <Dropdown menu={refreshMenu} trigger={["hover"]}>
  134. <Button size="small" type="text" icon={<ReloadOutlined />} />
  135. </Dropdown>
  136. </Space>
  137. </div>
  138. </Space>
  139. </div>
  140. </MsgContainer>
  141. );
  142. };
  143. export default MsgAssistant;