"use client"; import { Bot, Check, CircleAlert, FileImage, FileText, Loader2, MessageSquare, Paperclip, Send, Sparkles, Upload } from "lucide-react"; import { useRef, useState, type ChangeEvent, type DragEvent } from "react"; import { ComposerPrimitive, MessagePrimitive, ThreadPrimitive, useAui, useAuiState } from "@assistant-ui/react"; import type { CadAttachment } from "@/lib/cad-types"; import { CadErrorPart, CadProgressPart, CadResultPart, TextPart } from "./cad-message-parts"; export function AgentThread({ attachments, uploading, uploadError, taskRunning = false, onUpload, onCancel }: { attachments: CadAttachment[]; uploading: boolean; uploadError: string; taskRunning?: boolean; onUpload: (files: FileList | null) => void; onCancel?: () => void; }) { const fileInput = useRef(null); const dragDepth = useRef(0); const running = useAuiState((state) => state.thread.isRunning) || taskRunning; const [isDraggingFiles, setIsDraggingFiles] = useState(false); const canUpload = !uploading && !running; const onDragEnter = (event: DragEvent) => { event.preventDefault(); event.stopPropagation(); dragDepth.current += 1; if (canUpload && isFileDrag(event)) setIsDraggingFiles(true); }; const onDragOver = (event: DragEvent) => { event.preventDefault(); event.stopPropagation(); event.dataTransfer.dropEffect = canUpload ? "copy" : "none"; }; const onDragLeave = (event: DragEvent) => { event.preventDefault(); event.stopPropagation(); dragDepth.current = Math.max(0, dragDepth.current - 1); if (dragDepth.current === 0) setIsDraggingFiles(false); }; const onDrop = (event: DragEvent) => { event.preventDefault(); event.stopPropagation(); dragDepth.current = 0; setIsDraggingFiles(false); if (canUpload && event.dataTransfer.files.length) onUpload(event.dataTransfer.files); }; return (
Agent
{attachments.length ?
{attachments.map((attachment) => )}
: null} {uploadError ?
: null}
描述需要生成或修改的 CAD 模型。
{isDraggingFiles ?
拖放文件上传
: null}
); } function isFileDrag(event: DragEvent) { return event.dataTransfer.files.length > 0 || Array.from(event.dataTransfer.types).includes("Files"); } function AttachmentCard({ attachment }: { attachment: CadAttachment }) { const Icon = attachment.kind === "image" ? FileImage : FileText; return
{attachment.name}{attachment.kind === "image" ? "视觉参考" : "文本参考"}
; } function UserMessage() { return (
); } function AssistantMessage() { return (
); } function Composer({ fileInput, uploading, taskRunning = false, onUpload, onCancel }: { fileInput: React.RefObject; uploading: boolean; taskRunning?: boolean; onUpload: (files: FileList | null) => void; onCancel?: () => void }) { const aui = useAui(); const chatRunning = useAuiState((state) => state.thread.isRunning); const running = chatRunning || taskRunning; const handleCancel = () => { onCancel?.(); if (chatRunning) aui.thread().cancelRun(); }; const handleFileChange = (event: ChangeEvent) => { if (event.currentTarget.files?.length) onUpload(event.currentTarget.files); event.currentTarget.value = ""; }; return (
{running ? ( ) : ( <> )}
); }