Files

152 lines
4.7 KiB
TypeScript
Raw Permalink Normal View History

2026-09-14 20:31:06 +08:00
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<string, unknown> | null;
[key: string]: unknown;
}
export interface DataQueryResult {
query_id?: string;
answer?: string;
summary?: string;
columns?: string[];
rows?: Record<string, unknown>[];
total?: number;
page?: number;
page_size?: number;
[key: string]: unknown;
}
export interface FundAnalysisResult {
analysis_text?: string;
items?: Record<string, unknown>[];
[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<string, string | number | undefined | null>) {
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<AgentMessage[]>(`/advisor-agent/session/${encodeURIComponent(sessionId)}/history`),
2026-09-14 21:41:40 +08:00
/** POST /chat/stream —— 读取 SSE,并支持调用方实时消费事件。 */
2026-09-14 20:31:06 +08:00
chatOnce(
body: {
query: string;
session_id?: string;
scope?: "customer" | "advisor";
customer_id?: number | null;
},
signal?: AbortSignal
): Promise<SSESummary> {
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<DataQueryResult>("/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<Page<AgentDraft> & { items?: AgentDraft[] }>(`/advisor-agent/draft/list${qs(params)}`),
/** GET /draft/{draft_id} */
draft: (draftId: string) =>
apiFetch<AgentDraft>(`/advisor-agent/draft/${encodeURIComponent(draftId)}`),
/** PUT /draft/{draft_id}/save */
saveDraft: (
draftId: string,
body: { title?: string; content?: string; structured_data?: Record<string, unknown> }
) =>
apiFetch<AgentDraft>(`/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<AgentDraft>(`/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<FundAnalysisResult>("/advisor-agent/fund-analysis", {
method: "POST",
body: JSON.stringify({ query }),
}),
/** POST /generate-talk-script */
generateTalkScript: (query: string) =>
apiFetch<TalkScriptResult>("/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)}`;
}