From 9dbc3cfcb59aaa675da67bca4a60d61123b51dcd Mon Sep 17 00:00:00 2001 From: zardol Date: Wed, 7 Oct 2026 22:23:16 +0500 Subject: [PATCH] Prompt for access code from the AI analysis button --- apps/web/src/components/AiWorkspace.tsx | 22 ++++++++++++++++------ docs/AI.md | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/web/src/components/AiWorkspace.tsx b/apps/web/src/components/AiWorkspace.tsx index b922562..39f6f70 100644 --- a/apps/web/src/components/AiWorkspace.tsx +++ b/apps/web/src/components/AiWorkspace.tsx @@ -20,6 +20,8 @@ export function AiWorkspace({ snapshot, active, disabled, onStation }: { const [accessCode, setAccessCode] = useState(''); const [checkedCode, setCheckedCode] = useState(''); const [settingsOpen, setSettingsOpen] = useState(false); + const [accessPrompt, setAccessPrompt] = useState(null); + const accessCodeInput = useRef(null); const [status, setStatus] = useState(null); const [checking, setChecking] = useState(false); const [pending, setPending] = useState(false); @@ -47,7 +49,15 @@ export function AiWorkspace({ snapshot, active, disabled, onStation }: { useEffect(() => () => request.current?.abort(), []); const analyze = () => { - if (!canAnalyze || base === null || disabled || request.current) return; + if (disabled || pending || request.current) return; + if (!canAnalyze || base === null || checking) { + setError(null); setSettingsOpen(true); + setAccessPrompt(!normalizedCode ? 'Введите код доступа, затем нажмите «Проверить подключение».' + : checking ? 'Проверяем подключение. Дождитесь подтверждения доступа.' + : 'Подтвердите код доступа кнопкой «Проверить подключение», затем запустите анализ.'); + accessCodeInput.current?.focus(); + return; + } const controller = new AbortController(); request.current = controller; setPending(true); setError(null); void requestAiAnalysis(base, input, checkedCode, controller.signal).then(value => { @@ -64,7 +74,7 @@ export function AiWorkspace({ snapshot, active, disabled, onStation }: { try { const nextBase = urlDraft.trim() ? normalizeAiUrl(urlDraft.trim()) : defaultAiUrl(); setBase(nextBase); setUrlDraft(nextBase ?? ''); setAccessCode(normalizedCode); setCheckedCode(normalizedCode); - setStatus(null); setConnectionError(null); setError(null); setRefreshStatus(value => value + 1); + setStatus(null); setConnectionError(null); setError(null); setAccessPrompt(null); setRefreshStatus(value => value + 1); } catch (reason) { setConnectionError(reason instanceof Error ? reason.message : 'Проверьте адрес.'); } }; const statusLabel = checking ? 'Проверяем подключение…' : canAnalyze ? 'Готов к анализу' : connectionError ? 'Подключение не подтверждено' : status?.configured ? normalizedCode ? 'Проверьте код доступа' : 'Нужен код доступа' : 'OpenAI не подключён'; @@ -81,10 +91,9 @@ export function AiWorkspace({ snapshot, active, disabled, onStation }: {
{([15, 30, 60] as const).map(minutes => )}
- - Запуск вручную · только текущие показатели @@ -92,11 +101,12 @@ export function AiWorkspace({ snapshot, active, disabled, onStation }: { {settingsOpen &&

Подключение к ИИ-сервису

API-ключ хранится на сервере. Код доступа к демонстрации остаётся только в памяти этой вкладки.

- + {connectionError &&

{connectionError}

} + {accessPrompt && !canAnalyze && !connectionError &&

{accessPrompt}

} {canAnalyze && !checking &&

Доступ подтверждён. Можно запускать ИИ-анализ.

} - {status?.configured && !canAnalyze && !checking && !connectionError &&

Сервер доступен. Введите код демонстрации и нажмите «Проверить подключение».

} + {status?.configured && !canAnalyze && !checking && !connectionError && !accessPrompt &&

Сервер доступен. Введите код демонстрации и нажмите «Проверить подключение».

}
} {error &&
{error}
} diff --git a/docs/AI.md b/docs/AI.md index 23caa9c..3c26300 100644 --- a/docs/AI.md +++ b/docs/AI.md @@ -12,7 +12,7 @@ 2. Выполнить `npm run build` и `npm start`, открыть `http://localhost:3001/#/ai`. В режиме разработки — `npm run dev` и `http://localhost:5173/#/ai`. 3. Для локальной браузерной сборки `http://localhost:4173/#/ai` сервер ИИ отдельно должен работать на `http://127.0.0.1:3001`. -Приложение читает `.env` при запуске сервера. Без ключа расчёт мощности доступен, а кнопка OpenAI не выдаёт фиктивный ответ. Ошибки и отказы API показываются отдельно. «Проверить подключение» проверяет также введённый код доступа, без обращения к OpenAI и расхода лимита. Анализ доступен только после подтверждения кода сервером; изменение кода или адреса требует новой проверки. В поле кода нужно вставлять только сам код демонстрации, без инструкции; случайно вставленный API-ключ блокируется до отправки. Сброс смены отменяет запрос и очищает результат; переход между разделами сохраняет готовый анализ. Результат имеет время среза и помечается устаревшим через пять модельных минут или при смене горизонта. +Приложение читает `.env` при запуске сервера. Без ключа расчёт мощности доступен, а кнопка OpenAI не выдаёт фиктивный ответ. Ошибки и отказы API показываются отдельно. «Проверить подключение» проверяет также введённый код доступа, без обращения к OpenAI и расхода лимита. Кнопка «Проанализировать риски» доступна до авторизации: нажатие открывает форму подключения и предлагает ввести или подтвердить код. Запрос анализа отправляется только после подтверждения кода сервером; изменение кода или адреса требует новой проверки. В поле кода нужно вставлять только сам код демонстрации, без инструкции; случайно вставленный API-ключ блокируется до отправки. Сброс смены отменяет запрос и очищает результат; переход между разделами сохраняет готовый анализ. Результат имеет время среза и помечается устаревшим через пять модельных минут или при смене горизонта. ## Публичный сервер