import { useCallback, useRef, useState } from 'react'; import { generateProblemFraming } from '../lib/api'; import { loadSettings } from '../lib/settings'; import { getActiveProvider, providerToCustomApiConfig } from '../lib/ai-providers'; import type { OutputMode, ProblemFramingPlan, Quality, ReferenceImage } from '../types/api'; import { useI18n } from '../i18n'; import { loadPrompts } from './usePrompts'; interface GenerationDraft { concept: string; quality: Quality; outputMode: OutputMode; referenceImages?: ReferenceImage[]; } interface StartPlanOptions { request: GenerationDraft; feedback?: string; } interface RefinePlanOptions { feedback: string; } interface UseProblemFramingResult { status: 'idle' | 'loading' | 'ready' | 'error'; plan: ProblemFramingPlan | null; error: string | null; draft: GenerationDraft | null; startPlan: (options: StartPlanOptions) => Promise; refinePlan: (options: RefinePlanOptions) => Promise; reset: () => void; } function hasIncompleteCustomProvider(provider: { apiUrl: string; apiKey: string; model: string } | null): boolean { if (!provider) { return false; } const hasAny = Boolean(provider.apiUrl.trim() || provider.apiKey.trim() || provider.model.trim()); const hasRequired = Boolean(provider.apiUrl.trim() && provider.apiKey.trim() && provider.model.trim()); return hasAny && !hasRequired; } export function useProblemFraming(): UseProblemFramingResult { const { locale, t } = useI18n(); const [status, setStatus] = useState<'idle' | 'loading' | 'ready' | 'error'>('idle'); const [plan, setPlan] = useState(null); const [error, setError] = useState(null); const [draft, setDraft] = useState(null); const [feedbackHistory, setFeedbackHistory] = useState([]); const abortControllerRef = useRef(null); const callPlanner = useCallback(async ( request: GenerationDraft, feedback?: string, currentPlan?: ProblemFramingPlan | null, history?: string[] ) => { abortControllerRef.current?.abort(); abortControllerRef.current = new AbortController(); const settings = loadSettings(); const activeProvider = getActiveProvider(settings.api); const customApiConfig = providerToCustomApiConfig(activeProvider); if (hasIncompleteCustomProvider(activeProvider) && !customApiConfig) { throw new Error(t('settings.test.needUrlAndKey')); } return generateProblemFraming( { concept: request.concept, feedback, feedbackHistory: history && history.length ? history : undefined, currentPlan: currentPlan || undefined, locale, referenceImages: request.referenceImages, promptOverrides: loadPrompts(locale), customApiConfig: customApiConfig || undefined, }, abortControllerRef.current.signal ); }, [locale, t]); const startPlan = useCallback(async ({ request, feedback }: StartPlanOptions) => { setStatus('loading'); setError(null); setDraft(request); const trimmedFeedback = feedback?.trim(); const nextHistory = trimmedFeedback ? [trimmedFeedback] : []; setFeedbackHistory(nextHistory); try { const response = await callPlanner(request, trimmedFeedback, undefined, nextHistory); setPlan(response.plan); setStatus('ready'); } catch (err) { if (err instanceof Error && err.name === 'AbortError') { return; } setStatus('error'); setError(err instanceof Error ? err.message : t('generation.problemFramingFailed')); } }, [callPlanner, t]); const refinePlan = useCallback(async ({ feedback }: RefinePlanOptions) => { if (!draft) { return; } setStatus('loading'); setError(null); const trimmedFeedback = feedback.trim(); const nextHistory = trimmedFeedback ? [...feedbackHistory, trimmedFeedback] : feedbackHistory; try { const response = await callPlanner(draft, trimmedFeedback, plan, nextHistory); setPlan(response.plan); setFeedbackHistory(nextHistory); setStatus('ready'); } catch (err) { if (err instanceof Error && err.name === 'AbortError') { return; } setStatus('error'); setError(err instanceof Error ? err.message : t('generation.problemFramingFailed')); } }, [callPlanner, draft, feedbackHistory, plan, t]); const reset = useCallback(() => { abortControllerRef.current?.abort(); setStatus('idle'); setPlan(null); setError(null); setDraft(null); setFeedbackHistory([]); }, []); return { status, plan, error, draft, startPlan, refinePlan, reset, }; }