AssistantMessage.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import React from "react";
  2. import { Button, Space } from "antd";
  3. import {
  4. RedoOutlined,
  5. LikeOutlined,
  6. DislikeOutlined,
  7. CopyOutlined,
  8. ShareAltOutlined,
  9. } from "@ant-design/icons";
  10. import { AssistantMessageProps } from "../../types/chat";
  11. import Marked from "../general/Marked";
  12. const AssistantMessage = ({
  13. messages,
  14. onRefresh,
  15. onEdit,
  16. isPending,
  17. onLike,
  18. onDislike,
  19. onCopy,
  20. onShare,
  21. }: AssistantMessageProps) => {
  22. const mainMessage = messages.find((m) => m.role === "assistant" && m.content);
  23. const toolMessages = messages.filter((m) => m.role === "tool");
  24. const handleCopy = () => {
  25. if (mainMessage?.content && onCopy) {
  26. onCopy(mainMessage.uid);
  27. }
  28. };
  29. const handleShare = async () => {
  30. if (mainMessage && onShare) {
  31. try {
  32. const shareUrl = await onShare(mainMessage.uid);
  33. // 可以显示分享链接或复制到剪贴板
  34. navigator.clipboard.writeText(shareUrl);
  35. } catch (err) {
  36. console.error("分享失败:", err);
  37. }
  38. }
  39. };
  40. return (
  41. <div className="assistant-message">
  42. <div className="message-header">
  43. <span className="role-label">
  44. {mainMessage?.model_id && (
  45. <span className="model-info">{mainMessage.model_id}</span>
  46. )}
  47. </span>
  48. </div>
  49. <div className="message-content" style={{ backgroundColor: "unset" }}>
  50. {/* Tool calls 显示 */}
  51. {toolMessages.length > 0 && (
  52. <div className="tool-calls">
  53. {toolMessages.map((toolMsg, index) => (
  54. <div key={toolMsg.uid} className="tool-result">
  55. <span className="tool-label">Tool {index + 1}</span>
  56. <div className="tool-content">{toolMsg.content}</div>
  57. </div>
  58. ))}
  59. </div>
  60. )}
  61. {/* 主要回答内容 */}
  62. {mainMessage?.content && (
  63. <div className="message-text">
  64. <Marked text={mainMessage.content} />
  65. {isPending && (
  66. <span className="status-indicator pending">生成中...</span>
  67. )}
  68. </div>
  69. )}
  70. {/* Token 使用信息 */}
  71. {mainMessage?.metadata?.token_usage && (
  72. <div className="token-info">
  73. Token: {mainMessage.metadata.token_usage.total_tokens}
  74. </div>
  75. )}
  76. </div>
  77. {!isPending && (
  78. <div className="message-actions">
  79. <Space size="small">
  80. <Button
  81. size="small"
  82. type="text"
  83. icon={<CopyOutlined />}
  84. onClick={handleCopy}
  85. />
  86. <Button
  87. size="small"
  88. type="text"
  89. icon={<LikeOutlined />}
  90. onClick={() => mainMessage && onLike && onLike(mainMessage.uid)}
  91. />
  92. <Button
  93. size="small"
  94. type="text"
  95. icon={<DislikeOutlined />}
  96. onClick={() =>
  97. mainMessage && onDislike && onDislike(mainMessage.uid)
  98. }
  99. />
  100. <Button
  101. size="small"
  102. type="text"
  103. icon={<ShareAltOutlined />}
  104. onClick={handleShare}
  105. />
  106. <Button
  107. size="small"
  108. type="text"
  109. icon={<RedoOutlined />}
  110. onClick={onRefresh}
  111. />
  112. </Space>
  113. </div>
  114. )}
  115. </div>
  116. );
  117. };
  118. export default AssistantMessage;