Упростить фронтенд сохранённых сессий ассистента

This commit is contained in:
dctouch 2026-05-26 00:54:18 +03:00
parent 43ae3237ce
commit a14eee4976
6 changed files with 62 additions and 212 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>NDC AI Normalizer Playground</title> <title>NDC AI Normalizer Playground</title>
<script type="module" crossorigin src="/assets/index-BdTHVNKv.js"></script> <script type="module" crossorigin src="/assets/index-B26u5hxP.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D-Jp8Dx0.css"> <link rel="stylesheet" crossorigin href="/assets/index-D-Jp8Dx0.css">
</head> </head>
<body> <body>

View File

@ -312,7 +312,6 @@ export const apiClient = {
async sendAssistantMessage(input: { async sendAssistantMessage(input: {
connection: ConnectionState; connection: ConnectionState;
prompts: PromptState;
userMessage: string; userMessage: string;
sessionId?: string; sessionId?: string;
promptVersion?: string; promptVersion?: string;
@ -336,10 +335,6 @@ export const apiClient = {
temperature: input.connection.temperature, temperature: input.connection.temperature,
maxOutputTokens: input.connection.maxOutputTokens, maxOutputTokens: input.connection.maxOutputTokens,
promptVersion: input.promptVersion ?? "address_query_runtime_v1", promptVersion: input.promptVersion ?? "address_query_runtime_v1",
systemPrompt: input.prompts.systemPrompt,
developerPrompt: input.prompts.developerPrompt,
domainPrompt: input.prompts.domainPrompt,
fewShotExamples: input.prompts.fewShotExamples,
context: { context: {
period_hint: input.context?.periodHint ?? "", period_hint: input.context?.periodHint ?? "",
business_context: input.context?.businessContext ?? "" business_context: input.context?.businessContext ?? ""
@ -362,7 +357,6 @@ export const apiClient = {
model?: string; model?: string;
assistant_prompt_version?: string; assistant_prompt_version?: string;
decomposition_prompt_version?: string; decomposition_prompt_version?: string;
prompt_fingerprint?: string;
}; };
}): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> { }): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> {
return request("/autoruns/autogen/save-assistant-session", { return request("/autoruns/autogen/save-assistant-session", {
@ -534,35 +528,5 @@ export const apiClient = {
return request(`/autoruns/autogen/history/${encodeURIComponent(generationId)}`, { return request(`/autoruns/autogen/history/${encodeURIComponent(generationId)}`, {
method: "DELETE" 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)
});
} }
}; };

View File

@ -244,7 +244,7 @@ type UnifiedCommentListItem =
}; };
const DEFAULT_AUTOGEN_SETTINGS: AutoGenSettingsState = { const DEFAULT_AUTOGEN_SETTINGS: AutoGenSettingsState = {
mode: "codex_creative", mode: "saved_user_sessions",
count: 24, count: 24,
personalityId: "general", personalityId: "general",
personalityPrompts: buildDefaultPersonalityPrompts(), personalityPrompts: buildDefaultPersonalityPrompts(),
@ -723,7 +723,6 @@ export function AutoRunsHistoryPanel({
const [dragOverQuestionIndex, setDragOverQuestionIndex] = useState<number | null>(null); const [dragOverQuestionIndex, setDragOverQuestionIndex] = useState<number | null>(null);
const [activeAsyncJob, setActiveAsyncJob] = useState<AsyncEvalRunJob | null>(null); const [activeAsyncJob, setActiveAsyncJob] = useState<AsyncEvalRunJob | null>(null);
const [postAnalysis, setPostAnalysis] = useState<AutoRunPostAnalysisResponse | null>(null); const [postAnalysis, setPostAnalysis] = useState<AutoRunPostAnalysisResponse | null>(null);
const [autoGenBusy, setAutoGenBusy] = useState(false);
const [autogenRunBusy, setAutogenRunBusy] = useState(false); const [autogenRunBusy, setAutogenRunBusy] = useState(false);
const [postAnalysisBusy, setPostAnalysisBusy] = useState(false); const [postAnalysisBusy, setPostAnalysisBusy] = useState(false);
const [autogenHistoryBusy, setAutogenHistoryBusy] = useState(false); const [autogenHistoryBusy, setAutogenHistoryBusy] = useState(false);
@ -801,10 +800,6 @@ export function AutoRunsHistoryPanel({
const asyncJobPollTimerRef = useRef<number | null>(null); const asyncJobPollTimerRef = useRef<number | null>(null);
const questionEditorRef = useRef<HTMLInputElement | null>(null); const questionEditorRef = useRef<HTMLInputElement | null>(null);
const isSavedUserSessionsMode = autoGenSettings.mode === "saved_user_sessions"; const isSavedUserSessionsMode = autoGenSettings.mode === "saved_user_sessions";
const selectedPersonality = useMemo(
() => autogenPersonalities.find((item) => item.id === autoGenSettings.personalityId) ?? autogenPersonalities[0] ?? AUTOGEN_PERSONALITIES[0],
[autoGenSettings.personalityId, autogenPersonalities]
);
const visibleAutoGenHistory = useMemo( const visibleAutoGenHistory = useMemo(
() => autoGenHistory.filter((item) => item.mode === autoGenSettings.mode), () => autoGenHistory.filter((item) => item.mode === autoGenSettings.mode),
[autoGenHistory, autoGenSettings.mode] [autoGenHistory, autoGenSettings.mode]
@ -1104,7 +1099,6 @@ export function AutoRunsHistoryPanel({
try { try {
const response = await apiClient.sendAssistantMessage({ const response = await apiClient.sendAssistantMessage({
connection, connection,
prompts,
userMessage, userMessage,
sessionId: assistantLiveSessionId || undefined, sessionId: assistantLiveSessionId || undefined,
promptVersion: assistantPromptVersion, promptVersion: assistantPromptVersion,
@ -1132,8 +1126,7 @@ export function AutoRunsHistoryPanel({
assistantPromptVersion, assistantPromptVersion,
connection, connection,
loadAssistantLiveAnnotationsForSession, loadAssistantLiveAnnotationsForSession,
log, log
prompts
]); ]);
const openAssistantLiveSaveModal = useCallback(() => { const openAssistantLiveSaveModal = useCallback(() => {
@ -1164,13 +1157,6 @@ export function AutoRunsHistoryPanel({
setAssistantLiveSaveModal((prev) => ({ ...prev, saving: true, error: "" })); setAssistantLiveSaveModal((prev) => ({ ...prev, saving: true, error: "" }));
try { try {
const promptFingerprint = [
prompts.systemPrompt,
prompts.developerPrompt,
prompts.domainPrompt,
prompts.schemaNotes,
prompts.fewShotExamples
].join("||");
const payload = await apiClient.saveAutoRunAssistantSession({ const payload = await apiClient.saveAutoRunAssistantSession({
session_id: sessionId, session_id: sessionId,
title, title,
@ -1179,8 +1165,7 @@ export function AutoRunsHistoryPanel({
llm_provider: connection.llmProvider, llm_provider: connection.llmProvider,
model: connection.model, model: connection.model,
assistant_prompt_version: assistantPromptVersion, assistant_prompt_version: assistantPromptVersion,
decomposition_prompt_version: decompositionPromptVersion, decomposition_prompt_version: decompositionPromptVersion
prompt_fingerprint: promptFingerprint
} }
}); });
setAutoGenHistory((prev) => [payload.generation, ...prev.filter((item) => item.generation_id !== payload.generation.generation_id)]); setAutoGenHistory((prev) => [payload.generation, ...prev.filter((item) => item.generation_id !== payload.generation.generation_id)]);
@ -1202,12 +1187,7 @@ export function AutoRunsHistoryPanel({
connection.llmProvider, connection.llmProvider,
connection.model, connection.model,
decompositionPromptVersion, decompositionPromptVersion,
log, log
prompts.developerPrompt,
prompts.domainPrompt,
prompts.fewShotExamples,
prompts.schemaNotes,
prompts.systemPrompt
]); ]);
const commitLimitInput = useCallback( const commitLimitInput = useCallback(
@ -1363,87 +1343,6 @@ export function AutoRunsHistoryPanel({
} }
}, [filters.fromLocal, filters.mode, filters.promptContains, filters.target, filters.toLocal, filters.useMock, log, selectedRunId]); }, [filters.fromLocal, filters.mode, filters.promptContains, filters.target, filters.toLocal, filters.useMock, log, selectedRunId]);
const generateAutogenBatch = useCallback(async () => {
setAutoGenBusy(true);
setErrorText("");
try {
if (autoGenSettings.mode === "saved_user_sessions") {
throw new Error("Пользовательские сессии сохраняются из живого чата, а не генерируются автоматически.");
}
const activePersonalityPrompt = autoGenSettings.personalityPrompts[autoGenSettings.personalityId] ?? "";
const promptFingerprint = [
prompts.systemPrompt,
prompts.developerPrompt,
prompts.domainPrompt,
prompts.schemaNotes,
prompts.fewShotExamples
]
.join("\n")
.slice(0, 900);
const payload = await apiClient.generateAutoRunQuestions({
mode: autoGenSettings.mode,
count: autoGenSettings.count,
domain: selectedPersonality.domain || undefined,
persist_to_eval_cases: autoGenSettings.persistToEvalCases,
generated_by: autoGenSettings.generatedBy.trim() || undefined,
llm: {
llm_provider: connection.llmProvider,
api_key: connection.apiKey,
model: connection.model,
base_url: connection.baseUrl,
temperature: connection.temperature,
max_output_tokens: connection.maxOutputTokens
},
context: {
llm_provider: connection.llmProvider,
model: connection.model,
assistant_prompt_version: assistantPromptVersion,
decomposition_prompt_version: decompositionPromptVersion,
prompt_fingerprint: promptFingerprint,
autogen_personality_id: selectedPersonality.id,
autogen_personality_prompt: activePersonalityPrompt.trim() || undefined
}
});
log(
`Generated ${payload.generation.count} questions (${payload.generation.mode}) id=${payload.generation.generation_id}` +
(payload.generation.saved_case_set_file ? ` saved=${payload.generation.saved_case_set_file}` : "")
);
setSelectedAutogenGenerationId(payload.generation.generation_id);
setEditableGeneratedQuestions([...(payload.generation.questions ?? [])]);
await loadAutoGenHistory();
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
setErrorText(`Автогенерация: ${message}`);
log(`Autogen generate error: ${message}`);
} finally {
setAutoGenBusy(false);
}
}, [
assistantPromptVersion,
autoGenSettings.count,
autoGenSettings.generatedBy,
autoGenSettings.mode,
autoGenSettings.personalityId,
autoGenSettings.personalityPrompts,
autoGenSettings.persistToEvalCases,
connection.apiKey,
connection.baseUrl,
connection.llmProvider,
connection.maxOutputTokens,
connection.model,
connection.temperature,
decompositionPromptVersion,
loadAutoGenHistory,
log,
prompts.developerPrompt,
prompts.domainPrompt,
prompts.fewShotExamples,
prompts.schemaNotes,
prompts.systemPrompt,
selectedPersonality.domain,
selectedPersonality.id
]);
const loadCaseDialog = useCallback( const loadCaseDialog = useCallback(
async (runId: string, caseId: string) => { async (runId: string, caseId: string) => {
if (isLiveRunId(runId)) { if (isLiveRunId(runId)) {
@ -2477,12 +2376,7 @@ export function AutoRunsHistoryPanel({
: prev.personalityId; : prev.personalityId;
return { return {
...prev, ...prev,
mode: mode: "saved_user_sessions",
parsed.autoGenSettings?.mode === "codex_creative" ||
parsed.autoGenSettings?.mode === "qwen_seed" ||
parsed.autoGenSettings?.mode === "saved_user_sessions"
? parsed.autoGenSettings.mode
: prev.mode,
count: count:
typeof parsed.autoGenSettings?.count === "number" typeof parsed.autoGenSettings?.count === "number"
? Math.max(1, Math.min(200, parsed.autoGenSettings.count)) ? Math.max(1, Math.min(200, parsed.autoGenSettings.count))
@ -2767,7 +2661,7 @@ export function AutoRunsHistoryPanel({
) : null} ) : null}
<div className="autoruns-group-heading"> <div className="autoruns-group-heading">
<h4>Автопрогоны</h4> <h4>Сохранённые сессии</h4>
<button <button
type="button" type="button"
className="autoruns-group-toggle" className="autoruns-group-toggle"
@ -2780,20 +2674,19 @@ export function AutoRunsHistoryPanel({
</div> </div>
{autogenGroupExpanded ? ( {autogenGroupExpanded ? (
<> <>
<div className="autoruns-form-grid"> <div className="autoruns-form-grid">
<label> <label>
Режимы Режим
<select <select
value={autoGenSettings.mode} value={autoGenSettings.mode}
onChange={(event) => setAutoGenSettings((prev) => ({ ...prev, mode: event.target.value as AutoGenMode }))} disabled
> onChange={(event) => setAutoGenSettings((prev) => ({ ...prev, mode: event.target.value as AutoGenMode }))}
<option value="codex_creative">codex_creative</option> >
<option value="qwen_seed">qwen_seed</option> <option value="saved_user_sessions">Пользовательские сессии</option>
<option value="saved_user_sessions">Пользовательские сессии</option> </select>
</select> </label>
</label> {!isSavedUserSessionsMode ? (
{!isSavedUserSessionsMode ? ( <>
<>
<label> <label>
Кол-во Кол-во
<input <input
@ -2892,28 +2785,22 @@ export function AutoRunsHistoryPanel({
) : null} ) : null}
<div className="button-row"> <div className="button-row">
{!isSavedUserSessionsMode ? ( <button type="button" className="tab" disabled={autogenHistoryBusy} onClick={() => void loadAutoGenHistory()}>
<> {autogenHistoryBusy ? "Обновляю..." : "Обновить историю"}
<button type="button" disabled={autoGenBusy} onClick={() => void generateAutogenBatch()}>
{autoGenBusy ? "Генерирую..." : "Сгенерировать пачку"}
</button>
<button type="button" className="tab" disabled={autogenHistoryBusy} onClick={() => void loadAutoGenHistory()}>
{autogenHistoryBusy ? "Обновляю..." : "Обновить историю"}
</button>
</>
) : null}
<button
type="button"
className="autoruns-run-launch-btn"
style={isSavedUserSessionsMode ? { display: "none" } : undefined}
disabled={
autogenStopBusy ||
(!autogenRunBusy && (editableGeneratedQuestions.length === 0 || !selectedAutogenGeneration))
}
onClick={() => void (autogenRunBusy ? stopAutogenCampaign() : runAutogenCampaign())}
>
{autogenRunBusy ? (autogenStopBusy ? "Останавливаю..." : "Остановить прогон") : "Запустить прогон"}
</button> </button>
{!isSavedUserSessionsMode ? (
<button
type="button"
className="autoruns-run-launch-btn"
disabled={
autogenStopBusy ||
(!autogenRunBusy && (editableGeneratedQuestions.length === 0 || !selectedAutogenGeneration))
}
onClick={() => void (autogenRunBusy ? stopAutogenCampaign() : runAutogenCampaign())}
>
{autogenRunBusy ? (autogenStopBusy ? "Останавливаю..." : "Остановить прогон") : "Запустить прогон"}
</button>
) : null}
</div> </div>
<div className="autoruns-form-grid"> <div className="autoruns-form-grid">

View File

@ -111,8 +111,8 @@ export function PromptPanel({
<section className="embedded-panel-section"> <section className="embedded-panel-section">
<div className="embedded-panel-section-header"> <div className="embedded-panel-section-header">
<div> <div>
<h4>Prompt Manager</h4> <h4>Normalizer / eval prompts</h4>
<p>Системный, developer и domain уровни управляются отдельно.</p> <p>Эти поля управляют декомпозицией и eval-прогонами, а не live-ответом ассистента.</p>
</div> </div>
</div> </div>
{content} {content}
@ -121,7 +121,7 @@ export function PromptPanel({
} }
return ( return (
<PanelFrame title="Prompt Manager" subtitle="Системный, developer и domain уровни управляются отдельно."> <PanelFrame title="Normalizer / eval prompts" subtitle="Эти поля управляют декомпозицией и eval-прогонами, а не live-ответом ассистента.">
{content} {content}
</PanelFrame> </PanelFrame>
); );