MessageBubble.tsx 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. import { useTranslation } from "react-i18next";
  2. import { cn } from "@/lib/utils";
  3. import type { Message } from "@/types";
  4. export function MessageBubble({ message }: { message: Message }) {
  5. const { t } = useTranslation();
  6. const isUser = message.role === "user";
  7. const isSystem = message.role === "system";
  8. const content = readableContent(message, t);
  9. return (
  10. <div className={cn("flex min-w-0", isUser ? "justify-end" : isSystem ? "justify-center" : "justify-start")}>
  11. <div
  12. className={cn(
  13. "min-w-0 max-w-[82%] rounded-md border px-3 py-2 text-sm",
  14. isUser && "border-primary/30 bg-primary text-primary-foreground",
  15. !isUser && !isSystem && "border-border bg-surface-elevated",
  16. isSystem && "max-w-[90%] border-border bg-muted/50 text-muted-foreground")}
  17. >
  18. {!isSystem ? (
  19. <div className={cn("mb-0.5 text-[11px] font-medium uppercase tracking-wide", isUser ? "text-primary-foreground/70" : "text-muted-foreground")}>
  20. {isUser ? t("sessions.roleUser") : t("sessions.roleAssistant")}
  21. </div>
  22. ) : null}
  23. <p className="whitespace-pre-wrap break-words leading-6 [overflow-wrap:anywhere]">{content}</p>
  24. </div>
  25. </div>
  26. );
  27. }
  28. function readableContent(message: Message, t: (key: string, options?: Record<string, unknown>) => string) {
  29. const text = message.content_text?.trim();
  30. if (text) return text;
  31. const payload = message.content_json;
  32. if (!payload) return t("sessions.noTextContent");
  33. if (typeof payload === "string") return payload;
  34. if (Array.isArray(payload)) return t("sessions.structuredItems", { count: payload.length });
  35. if (typeof payload === "object") {
  36. const record = payload as Record<string, unknown>;
  37. for (const key of ["text", "message", "answer", "output", "result", "content"]) {
  38. const value = record[key];
  39. if (typeof value === "string" && value.trim()) return value;
  40. }
  41. return t("sessions.structuredMessage");
  42. }
  43. return String(payload);
  44. }