Files
deerflow-code/frontend-web/src/open-canvas/api/ai-writing-sessions.ts
T

116 lines
4.0 KiB
TypeScript

import { getBackendBaseURL } from '@/core/config';
import { apiFetch } from '@/core/api';
import type { ProgressEvent, CompletedIntervention } from '../types/ai-writing';
export interface AIWritingSessionSummary {
id: string;
user_id: string | null;
title: string;
user_intent: string | null;
status: string;
draft_title: string | null;
draft_markdown: string | null;
completed_interventions: CompletedInterventionRecord[] | null;
review_result: Record<string, unknown> | null;
transcript: AIWritingTranscript | null;
created_at: string;
updated_at: string;
}
export interface CompletedInterventionRecord {
pausePoint: string;
action: string;
timestamp: string;
}
/** 完整对话时间线快照:与实时对话用同一份数据结构,历史回显时直接喂给 AIWritingTimeline。 */
export interface AIWritingTranscript {
progressEvents: ProgressEvent[];
completedInterventions: CompletedIntervention[];
}
const BASE = () => `${getBackendBaseURL()}/api/ai-writing/sessions`;
// ── admin 调试用 —— 阶段 7 删冗余时一并移除 ───────────────────────────────────
export interface AIWritingCleanupResult {
deleted_db: number;
deleted_checkpoints: number;
skipped_active: number;
elapsed_seconds: number;
params: { retention_days: number; only_finished: boolean; batch_size: number };
}
/** 仅 admin 可用:触发一次性会话清理(保留 ai-writing-优化.md 迁移期临时调试入口)。 */
export async function adminCleanupAIWritingSessions(body: {
retention_days?: number;
only_finished?: boolean;
batch_size?: number;
} = {}): Promise<AIWritingCleanupResult> {
const resp = await apiFetch(`${getBackendBaseURL()}/api/ai-writing/admin/cleanup`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!resp.ok) {
const text = await resp.text().catch(() => '');
throw new Error(`清理失败 ${resp.status}: ${text || resp.statusText}`);
}
return resp.json();
}
export async function listAIWritingSessions(): Promise<AIWritingSessionSummary[]> {
const resp = await apiFetch(BASE());
if (!resp.ok) throw new Error(`获取历史记录失败: ${resp.status}`);
return resp.json();
}
export async function getAIWritingSession(id: string): Promise<AIWritingSessionSummary> {
const resp = await apiFetch(`${BASE()}/${id}`);
if (!resp.ok) throw new Error(`获取会话失败: ${resp.status}`);
return resp.json();
}
export async function renameAIWritingSession(id: string, title: string): Promise<AIWritingSessionSummary> {
const resp = await apiFetch(`${BASE()}/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title }),
});
if (!resp.ok) throw new Error(`重命名失败: ${resp.status}`);
return resp.json();
}
export async function deleteAIWritingSession(id: string): Promise<void> {
const resp = await apiFetch(`${BASE()}/${id}`, { method: 'DELETE' });
if (!resp.ok) throw new Error(`删除失败: ${resp.status}`);
}
/**
* 保存会话的完整对话时间线,供历史回显出与实时对话一致的富时间线。
*
* 该功能属于「锦上添花」:保存失败不应影响写作主流程,因此本函数永不抛错,
* 内部捕获所有异常(网络错误 / 接口 500 等),仅打印告警并返回是否成功。
*/
export async function saveAIWritingTranscript(
id: string,
transcript: AIWritingTranscript,
): Promise<boolean> {
try {
const resp = await apiFetch(`${BASE()}/${id}/transcript`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ transcript }),
});
if (!resp.ok) {
console.warn(`[ai-writing] 保存对话时间线失败: HTTP ${resp.status}(已忽略,不影响写作流程)`);
return false;
}
return true;
} catch (err) {
console.warn('[ai-writing] 保存对话时间线异常(已忽略,不影响写作流程):', err);
return false;
}
}