116 lines
4.0 KiB
TypeScript
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;
|
|
}
|
|
}
|