ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: retention и стабильная загрузка аудио Voice Tasker
This commit is contained in:
+73
-11
@@ -52,6 +52,7 @@ type TFormState = {
|
||||
workspace_daily_limit: number;
|
||||
project_daily_limit: number;
|
||||
workspace_concurrency_limit: number;
|
||||
sensitive_data_retention_days: number;
|
||||
openai_api_key: string;
|
||||
};
|
||||
|
||||
@@ -75,6 +76,7 @@ const getInitialFormState = (settings?: TWorkspaceAISettings): TFormState => ({
|
||||
workspace_daily_limit: settings?.workspace_daily_limit ?? 1000,
|
||||
project_daily_limit: settings?.project_daily_limit ?? 300,
|
||||
workspace_concurrency_limit: settings?.workspace_concurrency_limit ?? 3,
|
||||
sensitive_data_retention_days: settings?.sensitive_data_retention_days ?? 30,
|
||||
openai_api_key: "",
|
||||
});
|
||||
|
||||
@@ -116,6 +118,7 @@ export const AIVoiceTaskerSettingsContent = observer(function AIVoiceTaskerSetti
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [isCleaningStaleSessions, setIsCleaningStaleSessions] = useState(false);
|
||||
const [isRunningRetention, setIsRunningRetention] = useState(false);
|
||||
// store hooks
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { fetchProjects, projectMap } = useProject();
|
||||
@@ -208,6 +211,7 @@ export const AIVoiceTaskerSettingsContent = observer(function AIVoiceTaskerSetti
|
||||
workspace_daily_limit: formState.workspace_daily_limit,
|
||||
project_daily_limit: formState.project_daily_limit,
|
||||
workspace_concurrency_limit: formState.workspace_concurrency_limit,
|
||||
sensitive_data_retention_days: formState.sensitive_data_retention_days,
|
||||
};
|
||||
|
||||
if (formState.openai_api_key.trim()) payload.openai_api_key = formState.openai_api_key.trim();
|
||||
@@ -272,6 +276,25 @@ export const AIVoiceTaskerSettingsContent = observer(function AIVoiceTaskerSetti
|
||||
}
|
||||
};
|
||||
|
||||
const handleRunRetention = async () => {
|
||||
setIsRunningRetention(true);
|
||||
try {
|
||||
const response = await workspaceAIService.runVoiceTaskRetention(workspaceSlug);
|
||||
await mutateMonitor(response, false);
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
title: `Retention выполнен: очищено ${response.redacted_count ?? 0}`,
|
||||
});
|
||||
} catch {
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Не удалось запустить retention Voice Tasker",
|
||||
});
|
||||
} finally {
|
||||
setIsRunningRetention(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (workspaceUserInfo && !canPerformWorkspaceAdminActions) {
|
||||
return <NotAuthorizedView section="settings" className="h-auto" />;
|
||||
}
|
||||
@@ -453,14 +476,25 @@ export const AIVoiceTaskerSettingsContent = observer(function AIVoiceTaskerSetti
|
||||
onChange={(value) => updateFormValue("workspace_concurrency_limit", value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Хранение чувствительных данных">
|
||||
<NumberInput
|
||||
value={formState.sensitive_data_retention_days}
|
||||
min={1}
|
||||
max={365}
|
||||
suffix="дней"
|
||||
onChange={(value) => updateFormValue("sensitive_data_retention_days", value)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<VoiceTaskMonitorSection
|
||||
isCleaning={isCleaningStaleSessions}
|
||||
isLoading={isMonitorLoading}
|
||||
isRunningRetention={isRunningRetention}
|
||||
monitor={monitor}
|
||||
onCleanupStale={handleCleanupStaleSessions}
|
||||
onRunRetention={handleRunRetention}
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
@@ -650,15 +684,19 @@ function getWorkspaceRoleLabel(role: IWorkspaceMember["role"]) {
|
||||
type TVoiceTaskMonitorSectionProps = {
|
||||
isCleaning: boolean;
|
||||
isLoading: boolean;
|
||||
isRunningRetention: boolean;
|
||||
monitor?: TVoiceTaskMonitor;
|
||||
onCleanupStale: () => void;
|
||||
onRunRetention: () => void;
|
||||
};
|
||||
|
||||
function VoiceTaskMonitorSection({
|
||||
isCleaning,
|
||||
isLoading,
|
||||
isRunningRetention,
|
||||
monitor,
|
||||
onCleanupStale,
|
||||
onRunRetention,
|
||||
}: TVoiceTaskMonitorSectionProps) {
|
||||
const staleCount = monitor?.summary.stale ?? 0;
|
||||
const recentSessions = monitor?.recent_sessions ?? [];
|
||||
@@ -671,17 +709,30 @@ function VoiceTaskMonitorSection({
|
||||
title="Очередь и диагностика"
|
||||
description="Мониторинг обработок Voice Tasker за последние 24 часа: активные job, ошибки, latency и расход parser tokens."
|
||||
right={
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
className="nodedc-settings-chip min-w-[11rem]"
|
||||
disabled={!monitor || staleCount === 0}
|
||||
loading={isCleaning}
|
||||
onClick={onCleanupStale}
|
||||
>
|
||||
<RotateCcw className="size-3.5" />
|
||||
Сбросить зависшие
|
||||
</Button>
|
||||
<div className="flex flex-wrap justify-end gap-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
className="nodedc-settings-chip min-w-[11rem]"
|
||||
disabled={!monitor || staleCount === 0 || isRunningRetention}
|
||||
loading={isCleaning}
|
||||
onClick={onCleanupStale}
|
||||
>
|
||||
<RotateCcw className="size-3.5" />
|
||||
Сбросить зависшие
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
className="nodedc-settings-chip min-w-[11rem]"
|
||||
disabled={!monitor || isCleaning}
|
||||
loading={isRunningRetention}
|
||||
onClick={onRunRetention}
|
||||
>
|
||||
<ShieldCheck className="size-3.5" />
|
||||
Запустить retention
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -727,6 +778,12 @@ function VoiceTaskMonitorSection({
|
||||
value={formatMonitorNumber(monitor.summary.parser_total_tokens)}
|
||||
meta="OpenAI usage proxy"
|
||||
/>
|
||||
<MonitorMetricCard
|
||||
label="Redacted"
|
||||
value={formatMonitorNumber(monitor.summary.redacted)}
|
||||
meta="очищенные сессии"
|
||||
tone={monitor.summary.redacted ? "accent" : "default"}
|
||||
/>
|
||||
<MonitorMetricCard
|
||||
label="Audio size"
|
||||
value={formatBytes(monitor.summary.total_audio_size)}
|
||||
@@ -830,6 +887,11 @@ function MonitorSessionRow({ session }: { session: TVoiceTaskMonitorSession }) {
|
||||
<span className="nodedc-settings-chip px-2.5 py-1">
|
||||
{formatDateTime(session.timings.completed_at || session.timings.failed_at || session.timings.created_at)}
|
||||
</span>
|
||||
{session.usage.sensitive_data_redacted_at && (
|
||||
<span className="nodedc-settings-chip px-2.5 py-1 text-[rgb(var(--nodedc-accent-rgb))]">
|
||||
очищено
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{session.error.code && <div className="mt-2 truncate text-11 text-red-300">{session.error.code}</div>}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user