import { apiFetch, readSSE, type SSESummary } from "@/lib/api"; import type { Page } from "@/lib/admin-api"; /** * 投顾 Agent(/api/advisor-agent/*)适配层。 * 该系列接口的成功码是 0 而不是 200(agent_success),已在 lib/api.ts 统一兼容。 */ export interface AgentMessage { role?: string; content?: string; [key: string]: unknown; } export interface AgentDraft { draft_id?: string; id?: string; title?: string | null; content?: string | null; intent?: string | null; status?: string | null; customer_id?: number | null; create_time?: string | null; update_time?: string | null; structured_data?: Record | null; [key: string]: unknown; } export interface DataQueryResult { query_id?: string; answer?: string; summary?: string; columns?: string[]; rows?: Record[]; total?: number; page?: number; page_size?: number; [key: string]: unknown; } export interface FundAnalysisResult { analysis_text?: string; items?: Record[]; [key: string]: unknown; } export interface TalkScriptResult { script?: string; content?: string; scene?: string; [key: string]: unknown; } /** 会话上下文:scope=customer 时必须带 customer_id,否则后端会尝试从问题文本里猜客户。 */ export interface ChatScope { sessionId?: string; customerId?: number | null; scope?: "customer" | "advisor"; } function qs(params: Record) { const search = new URLSearchParams(); for (const [key, value] of Object.entries(params)) { if (value !== undefined && value !== null && value !== "") search.set(key, String(value)); } const text = search.toString(); return text ? `?${text}` : ""; } export const assistantApi = { /** GET /session/{session_id}/history —— 读取本人短期 Agent 会话记录。 */ sessionHistory: (sessionId: string) => apiFetch(`/advisor-agent/session/${encodeURIComponent(sessionId)}/history`), /** POST /chat/stream —— 读取 SSE,并支持调用方实时消费事件。 */ chatOnce( body: { query: string; session_id?: string; scope?: "customer" | "advisor"; customer_id?: number | null; }, signal?: AbortSignal ): Promise { return readSSE("/advisor-agent/chat/stream", body, signal); }, /** POST /data-query —— 自然语言查客户数据(非流式)。 */ dataQuery: (body: { query: string; session_id?: string; max_rows?: number; page?: number; page_size?: number; }) => apiFetch("/advisor-agent/data-query", { method: "POST", body: JSON.stringify(body), }), /** GET /draft/list */ drafts: (params: { customer_id?: number; status?: string; page?: number; page_size?: number } = {}) => apiFetch & { items?: AgentDraft[] }>(`/advisor-agent/draft/list${qs(params)}`), /** GET /draft/{draft_id} */ draft: (draftId: string) => apiFetch(`/advisor-agent/draft/${encodeURIComponent(draftId)}`), /** PUT /draft/{draft_id}/save */ saveDraft: ( draftId: string, body: { title?: string; content?: string; structured_data?: Record } ) => apiFetch(`/advisor-agent/draft/${encodeURIComponent(draftId)}/save`, { method: "PUT", body: JSON.stringify(body), }), /** POST /draft/{draft_id}/operate —— 后端目前仅支持 operation=discard。 */ operateDraft: (draftId: string, operation: "discard") => apiFetch(`/advisor-agent/draft/${encodeURIComponent(draftId)}/operate`, { method: "POST", body: JSON.stringify({ operation }), }), /** POST /rebalance/run —— 异步受理,返回 accepted/queued,草稿稍后生成。 */ runRebalance: (query: string) => apiFetch<{ accepted?: boolean; status?: string }>("/advisor-agent/rebalance/run", { method: "POST", body: JSON.stringify({ query }), }), /** POST /fund-analysis —— query 里需包含基金代码,如「分析 000001」。 */ fundAnalysis: (query: string) => apiFetch("/advisor-agent/fund-analysis", { method: "POST", body: JSON.stringify({ query }), }), /** POST /generate-talk-script */ generateTalkScript: (query: string) => apiFetch("/advisor-agent/generate-talk-script", { method: "POST", body: JSON.stringify({ query }), }), }; /** 生成本地会话 ID(后端 session_id 为空时自动创建,这里只是前端约定的稳定键)。 */ export function newSessionId(): string { return `advisor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; }