NODEDC_1C/llm_normalizer/frontend/src/api/client.ts

563 lines
18 KiB
TypeScript

import type {
AsyncEvalRunStartResponse,
AsyncEvalRunStatusResponse,
AutoGenPersonalityCatalogResponse,
AutoGenHistoryResponse,
AutoGenHistoryRecord,
AutoGenMode,
AutoRunAnnotationsResponse,
AutoRunAnnotationRecord,
AutoRunDetailResponse,
AutoRunDialogResponse,
AutoRunHistoryResponse,
AutoRunPostAnalysisResponse,
AssistantAnnotationsResponse,
AssistantAnnotationRecord,
AssistantMessageResultState,
AssistantConversationItem,
ConnectionState,
HistoryItem,
ManualCaseDecision,
NormalizeResultState,
PromptState,
RuntimeRun
} from "../state/types";
const PREFIX = "/api";
async function request<T>(path: string, init?: RequestInit): Promise<T> {
const response = await fetch(`${PREFIX}${path}`, {
...init,
headers: {
"Content-Type": "application/json",
...(init?.headers ?? {})
}
});
const payload = (await response.json()) as T & { error?: { message?: string } };
if (!response.ok) {
const message = (payload as { error?: { message?: string } }).error?.message ?? "Ошибка запроса";
throw new Error(message);
}
return payload;
}
export const apiClient = {
async loadSharedConnectionConfig(): Promise<{
ok: boolean;
connection: Omit<ConnectionState, "apiKey"> | null;
updated_at: string | null;
exists: boolean;
}> {
return request("/llm/shared-connection");
},
async saveSharedConnectionConfig(connection: ConnectionState): Promise<{
ok: boolean;
connection: Omit<ConnectionState, "apiKey">;
updated_at: string;
}> {
return request("/llm/shared-connection", {
method: "POST",
body: JSON.stringify({
llmProvider: connection.llmProvider,
model: connection.model,
baseUrl: connection.baseUrl,
temperature: connection.temperature,
maxOutputTokens: connection.maxOutputTokens
})
});
},
async listModels(connection: ConnectionState): Promise<{ ok: boolean; models: string[]; count: number; timestamp: string }> {
return request("/llm/models", {
method: "POST",
body: JSON.stringify({
llmProvider: connection.llmProvider,
apiKey: connection.apiKey,
model: connection.model,
baseUrl: connection.baseUrl
})
});
},
async testConnection(connection: ConnectionState): Promise<{
ok: boolean;
provider: "openai" | "local";
model: string;
model_found: boolean | null;
models_count: number | null;
timestamp: string;
}> {
return request("/llm/test-connection", {
method: "POST",
body: JSON.stringify({
llmProvider: connection.llmProvider,
apiKey: connection.apiKey,
model: connection.model,
baseUrl: connection.baseUrl
})
});
},
async normalize(params: {
connection: ConnectionState;
prompts: PromptState;
promptVersion?: string;
query: {
userQuestion: string;
periodHint?: string;
businessContext?: string;
expectedRoute?: string;
};
saveAsTestCase?: boolean;
useMock?: boolean;
}): Promise<NormalizeResultState> {
return request("/normalize", {
method: "POST",
body: JSON.stringify({
llmProvider: params.connection.llmProvider,
apiKey: params.connection.apiKey,
model: params.connection.model,
baseUrl: params.connection.baseUrl,
temperature: params.connection.temperature,
maxOutputTokens: params.connection.maxOutputTokens,
promptVersion: params.promptVersion,
systemPrompt: params.prompts.systemPrompt,
developerPrompt: params.prompts.developerPrompt,
domainPrompt: params.prompts.domainPrompt,
fewShotExamples: params.prompts.fewShotExamples,
userQuestion: params.query.userQuestion,
context: {
period_hint: params.query.periodHint ?? "",
business_context: params.query.businessContext ?? "",
expected_route: params.query.expectedRoute ?? ""
},
saveAsTestCase: Boolean(params.saveAsTestCase),
useMock: Boolean(params.useMock)
})
});
},
async loadHistory(): Promise<{ ok: boolean; items: HistoryItem[] }> {
return request("/history");
},
async loadTrace(traceId: string): Promise<{ ok: boolean; trace: unknown }> {
return request(`/history/${traceId}`);
},
async loadPresets(): Promise<{
ok: boolean;
presets: Array<{
id: string;
name: string;
prompt_version: string;
systemPrompt: string;
developerPrompt: string;
domainPrompt: string;
schemaNotes?: string;
fewShotExamples?: string;
}>;
}> {
return request("/presets");
},
async savePreset(input: {
id?: string;
name: string;
prompt_version?: string;
systemPrompt: string;
developerPrompt: string;
domainPrompt: string;
schemaNotes?: string;
fewShotExamples?: string;
}): Promise<{ ok: boolean }> {
return request("/presets/save", {
method: "POST",
body: JSON.stringify(input)
});
},
async runEval(input: {
connection: ConnectionState;
prompts: PromptState;
promptVersion?: string;
caseIds?: string[];
useMock?: boolean;
mode?: "standard" | "single-pass-strict";
caseSetFile?: string;
rawQuestions?: string;
evalTarget?: "normalizer" | "assistant_stage1" | "assistant_stage2" | "assistant_p0";
compareWithReportFile?: string;
analysisDate?: string;
}): Promise<{ ok: boolean; report: unknown }> {
return request("/eval/run", {
method: "POST",
body: JSON.stringify({
normalizeConfig: {
llmProvider: input.connection.llmProvider,
apiKey: input.connection.apiKey,
model: input.connection.model,
baseUrl: input.connection.baseUrl,
temperature: input.connection.temperature,
maxOutputTokens: input.connection.maxOutputTokens,
promptVersion: input.promptVersion,
systemPrompt: input.prompts.systemPrompt,
developerPrompt: input.prompts.developerPrompt,
domainPrompt: input.prompts.domainPrompt,
fewShotExamples: input.prompts.fewShotExamples
},
caseIds: input.caseIds,
useMock: Boolean(input.useMock),
mode: input.mode ?? "standard",
caseSetFile: input.caseSetFile,
rawQuestions: input.rawQuestions,
eval_target: input.evalTarget,
compare_with_report_file: input.compareWithReportFile,
analysis_date: input.analysisDate
})
});
},
async startEvalRunAsync(input: {
connection: ConnectionState;
prompts: PromptState;
promptVersion?: string;
caseIds?: string[];
useMock?: boolean;
mode?: "standard" | "single-pass-strict";
caseSetFile?: string;
rawQuestions?: string;
evalTarget?: "normalizer" | "assistant_stage1" | "assistant_stage2" | "assistant_p0";
compareWithReportFile?: string;
questions?: string[];
scenarioQuestions?: string[];
scenarioTitle?: string;
analysisDate?: string;
}): Promise<AsyncEvalRunStartResponse> {
return request("/eval/run-async/start", {
method: "POST",
body: JSON.stringify({
normalizeConfig: {
llmProvider: input.connection.llmProvider,
apiKey: input.connection.apiKey,
model: input.connection.model,
baseUrl: input.connection.baseUrl,
temperature: input.connection.temperature,
maxOutputTokens: input.connection.maxOutputTokens,
promptVersion: input.promptVersion,
systemPrompt: input.prompts.systemPrompt,
developerPrompt: input.prompts.developerPrompt,
domainPrompt: input.prompts.domainPrompt,
fewShotExamples: input.prompts.fewShotExamples
},
caseIds: input.caseIds,
useMock: Boolean(input.useMock),
mode: input.mode ?? "standard",
caseSetFile: input.caseSetFile,
rawQuestions: input.rawQuestions,
eval_target: input.evalTarget,
compare_with_report_file: input.compareWithReportFile,
questions: input.questions,
scenarioQuestions: input.scenarioQuestions,
scenarioTitle: input.scenarioTitle,
analysis_date: input.analysisDate
})
});
},
async loadEvalRunAsyncStatus(jobId: string): Promise<AsyncEvalRunStatusResponse> {
return request(`/eval/run-async/${encodeURIComponent(jobId)}`);
},
async startRun(): Promise<{ ok: boolean; run: RuntimeRun; runId: string; sessionId: string; status: string }> {
return request("/accounting-agent/v1/runs/start", {
method: "POST",
body: JSON.stringify({
initiator: "ndc_operator",
source: "gui"
})
});
},
async finishRun(runId: string): Promise<{ ok: boolean; run: RuntimeRun }> {
return request("/accounting-agent/v1/runs/finish", {
method: "POST",
body: JSON.stringify({
runId,
status: "DONE",
source: "gui",
reason: "Остановлено оператором из GUI"
})
});
},
async listRuns(): Promise<{ ok: boolean; items: RuntimeRun[] }> {
return request("/accounting-agent/v1/runs");
},
async listResults(): Promise<{ ok: boolean; items: unknown[] }> {
return request("/accounting-agent/v1/results");
},
async runTrace(runId: string): Promise<{ ok: boolean; items: unknown[] }> {
return request(`/accounting-agent/v1/trace/run/${runId}`);
},
async sendAssistantMessage(input: {
connection: ConnectionState;
prompts: PromptState;
userMessage: string;
sessionId?: string;
promptVersion?: string;
context?: {
periodHint?: string;
businessContext?: string;
};
useMock?: boolean;
}): Promise<AssistantMessageResultState> {
return request("/assistant/message", {
method: "POST",
body: JSON.stringify({
session_id: input.sessionId ?? "",
mode: "assistant",
message: input.userMessage,
user_message: input.userMessage,
llmProvider: input.connection.llmProvider,
apiKey: input.connection.apiKey,
model: input.connection.model,
baseUrl: input.connection.baseUrl,
temperature: input.connection.temperature,
maxOutputTokens: input.connection.maxOutputTokens,
promptVersion: input.promptVersion ?? "address_query_runtime_v1",
systemPrompt: input.prompts.systemPrompt,
developerPrompt: input.prompts.developerPrompt,
domainPrompt: input.prompts.domainPrompt,
fewShotExamples: input.prompts.fewShotExamples,
context: {
period_hint: input.context?.periodHint ?? "",
business_context: input.context?.businessContext ?? ""
},
useMock: Boolean(input.useMock)
})
});
},
async loadAssistantSession(sessionId: string): Promise<{ ok: boolean; session: { items: AssistantConversationItem[] } }> {
return request(`/assistant/session/${sessionId}`);
},
async saveAutoRunAssistantSession(input: {
session_id: string;
title: string;
generated_by?: string;
context?: {
llm_provider?: string;
model?: string;
assistant_prompt_version?: string;
decomposition_prompt_version?: string;
prompt_fingerprint?: string;
};
}): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> {
return request("/autoruns/autogen/save-assistant-session", {
method: "POST",
body: JSON.stringify(input)
});
},
async loadAssistantAnnotations(input?: {
session_id?: string;
limit?: number;
}): Promise<AssistantAnnotationsResponse> {
const params = new URLSearchParams();
if (input?.session_id) params.set("session_id", input.session_id);
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
const query = params.toString();
return request(`/assistant/annotations${query ? `?${query}` : ""}`);
},
async saveAssistantAnnotation(input: {
session_id: string;
message_index: number;
rating: number;
comment: string;
annotation_author?: string;
}): Promise<{ ok: boolean; annotation: AssistantAnnotationRecord }> {
return request("/assistant/annotations", {
method: "POST",
body: JSON.stringify(input)
});
},
async loadAutoRunsHistory(input?: {
from?: string;
to?: string;
target?: string;
mode?: string;
use_mock?: "any" | "true" | "false";
prompt_contains?: string;
limit?: number;
scan_limit?: number;
}): Promise<AutoRunHistoryResponse> {
const params = new URLSearchParams();
if (input?.from) params.set("from", input.from);
if (input?.to) params.set("to", input.to);
if (input?.target) params.set("target", input.target);
if (input?.mode) params.set("mode", input.mode);
if (input?.use_mock) params.set("use_mock", input.use_mock);
if (input?.prompt_contains) params.set("prompt_contains", input.prompt_contains);
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
if (typeof input?.scan_limit === "number") params.set("scan_limit", String(input.scan_limit));
const query = params.toString();
return request(`/autoruns/history${query ? `?${query}` : ""}`);
},
async loadAutoRunDetail(runId: string): Promise<AutoRunDetailResponse> {
return request(`/autoruns/history/${encodeURIComponent(runId)}`);
},
async loadAutoRunCaseDialog(runId: string, caseId: string): Promise<AutoRunDialogResponse> {
return request(`/autoruns/history/${encodeURIComponent(runId)}/case/${encodeURIComponent(caseId)}/dialog`);
},
async loadAutoRunAnnotations(input?: {
run_id?: string;
case_id?: string;
min_rating?: number;
manual_case_decision?: ManualCaseDecision | "all";
limit?: number;
}): Promise<AutoRunAnnotationsResponse> {
const params = new URLSearchParams();
if (input?.run_id) params.set("run_id", input.run_id);
if (input?.case_id) params.set("case_id", input.case_id);
if (typeof input?.min_rating === "number") params.set("min_rating", String(input.min_rating));
if (input?.manual_case_decision) params.set("manual_case_decision", input.manual_case_decision);
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
const query = params.toString();
return request(`/autoruns/annotations${query ? `?${query}` : ""}`);
},
async saveAutoRunAnnotation(input: {
run_id: string;
case_id: string;
message_index: number;
rating: number;
comment: string;
manual_case_decision: ManualCaseDecision;
annotation_author?: string;
}): Promise<{ ok: boolean; annotation: AutoRunAnnotationRecord; case_annotation_stats: { count: number; latest_at: string | null; avg_rating: number | null } | null }> {
return request("/autoruns/annotations", {
method: "POST",
body: JSON.stringify(input)
});
},
async updateAutoRunAnnotation(input: {
annotation_id: string;
resolved: boolean;
resolved_by?: string;
}): Promise<{ ok: boolean; annotation: AutoRunAnnotationRecord; case_annotation_stats: { count: number; latest_at: string | null; avg_rating: number | null } | null }> {
return request(`/autoruns/annotations/${encodeURIComponent(input.annotation_id)}`, {
method: "PATCH",
body: JSON.stringify({
resolved: input.resolved,
resolved_by: input.resolved_by
})
});
},
async loadAutoRunPostAnalysis(input?: {
run_id?: string;
limit_per_queue?: number;
annotation_limit?: number;
scan_limit?: number;
from?: string;
to?: string;
target?: string;
mode?: string;
use_mock?: "any" | "true" | "false";
prompt_contains?: string;
}): Promise<AutoRunPostAnalysisResponse> {
const params = new URLSearchParams();
if (input?.run_id) params.set("run_id", input.run_id);
if (typeof input?.limit_per_queue === "number") params.set("limit_per_queue", String(input.limit_per_queue));
if (typeof input?.annotation_limit === "number") params.set("annotation_limit", String(input.annotation_limit));
if (typeof input?.scan_limit === "number") params.set("scan_limit", String(input.scan_limit));
if (input?.from) params.set("from", input.from);
if (input?.to) params.set("to", input.to);
if (input?.target) params.set("target", input.target);
if (input?.mode) params.set("mode", input.mode);
if (input?.use_mock) params.set("use_mock", input.use_mock);
if (input?.prompt_contains) params.set("prompt_contains", input.prompt_contains);
const query = params.toString();
return request(`/autoruns/post-analysis${query ? `?${query}` : ""}`);
},
async loadAutoRunAutogenHistory(input?: {
mode?: AutoGenMode;
limit?: number;
}): Promise<AutoGenHistoryResponse> {
const params = new URLSearchParams();
if (input?.mode) params.set("mode", input.mode);
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
const query = params.toString();
return request(`/autoruns/autogen/history${query ? `?${query}` : ""}`);
},
async loadAutoRunAutogenPersonalityCatalog(): Promise<AutoGenPersonalityCatalogResponse> {
return request("/autoruns/autogen/personality-catalog");
},
async updateAutoRunAutogenQuestions(input: {
generation_id: string;
questions: string[];
}): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> {
return request(`/autoruns/autogen/history/${encodeURIComponent(input.generation_id)}/questions`, {
method: "PATCH",
body: JSON.stringify({
questions: input.questions
})
});
},
async deleteAutoRunAutogenHistoryRecord(generationId: string): Promise<{
ok: boolean;
generation_id: string;
deleted_files: string[];
}> {
return request(`/autoruns/autogen/history/${encodeURIComponent(generationId)}`, {
method: "DELETE"
});
},
async generateAutoRunQuestions(input: {
mode: AutoGenMode;
count: number;
domain?: string;
persist_to_eval_cases?: boolean;
generated_by?: string;
llm?: {
llm_provider?: "openai" | "local";
api_key?: string;
model?: string;
base_url?: string;
temperature?: number;
max_output_tokens?: number;
};
context?: {
llm_provider?: string;
model?: string;
assistant_prompt_version?: string;
decomposition_prompt_version?: string;
prompt_fingerprint?: string;
autogen_personality_id?: string;
autogen_personality_prompt?: string;
};
}): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> {
return request("/autoruns/autogen/generate", {
method: "POST",
body: JSON.stringify(input)
});
}
};