import { useState, useCallback } from 'react'; import { expertTransformCategoryStream } from '../services/api'; import type { ExpertTransformationInput, ExpertTransformationProgress, ExpertTransformationCategoryResult, ExpertTransformationDAGResult, ExpertProfile, CategoryDefinition, ExpertSource, } from '../types'; interface UseExpertTransformationOptions { model?: string; temperature?: number; expertSource?: ExpertSource; } export function useExpertTransformation(options: UseExpertTransformationOptions = {}) { const [loading, setLoading] = useState(false); const [progress, setProgress] = useState({ step: 'idle', currentCategory: '', processedCategories: [], message: '', }); const [results, setResults] = useState(null); const [error, setError] = useState(null); // Global expert team - generated once and shared across all categories const [experts, setExperts] = useState(null); const transformCategory = useCallback( async ( query: string, category: CategoryDefinition, attributes: string[], expertConfig: { expert_count: number; keywords_per_expert: number; custom_experts?: string[]; } ): Promise<{ result: ExpertTransformationCategoryResult | null; experts: ExpertProfile[]; }> => { return new Promise((resolve) => { let categoryExperts: ExpertProfile[] = []; setProgress((prev) => ({ ...prev, step: 'expert', currentCategory: category.name, message: `組建專家團隊...`, })); expertTransformCategoryStream( { query, category: category.name, attributes, expert_count: expertConfig.expert_count, keywords_per_expert: expertConfig.keywords_per_expert, custom_experts: expertConfig.custom_experts, expert_source: options.expertSource, model: options.model, temperature: options.temperature, }, { onExpertStart: () => { setProgress((prev) => ({ ...prev, step: 'expert', message: `正在組建專家團隊...`, })); }, onExpertComplete: (expertsData) => { categoryExperts = expertsData; setExperts(expertsData); setProgress((prev) => ({ ...prev, experts: expertsData, message: `專家團隊組建完成(${expertsData.length}位專家)`, })); }, onKeywordStart: () => { setProgress((prev) => ({ ...prev, step: 'keyword', message: `專家團隊為「${category.name}」的屬性生成關鍵字...`, })); }, onKeywordProgress: (data) => { setProgress((prev) => ({ ...prev, currentAttribute: data.attribute, message: `為「${data.attribute}」生成了 ${data.count} 個關鍵字`, })); }, onKeywordComplete: (totalKeywords) => { setProgress((prev) => ({ ...prev, message: `共生成了 ${totalKeywords} 個專家關鍵字`, })); }, onDescriptionStart: () => { setProgress((prev) => ({ ...prev, step: 'description', message: `為「${category.name}」的專家關鍵字生成創新描述...`, })); }, onDescriptionComplete: (count) => { setProgress((prev) => ({ ...prev, message: `生成了 ${count} 個創新描述`, })); }, onDone: (data) => { setProgress((prev) => ({ ...prev, step: 'done', processedCategories: [...prev.processedCategories, category.name], message: `「${category.name}」處理完成`, })); resolve({ result: data.result, experts: data.experts, }); }, onError: (err) => { setProgress((prev) => ({ ...prev, step: 'error', error: err, message: `處理「${category.name}」時發生錯誤`, })); resolve({ result: null, experts: categoryExperts, }); }, } ).catch((err) => { setProgress((prev) => ({ ...prev, step: 'error', error: err.message, message: `處理「${category.name}」時發生錯誤`, })); resolve({ result: null, experts: categoryExperts, }); }); }); }, [options.model, options.temperature, options.expertSource] ); const transformAll = useCallback( async (input: ExpertTransformationInput) => { setLoading(true); setError(null); setResults(null); setExperts(null); setProgress({ step: 'idle', currentCategory: '', processedCategories: [], message: '開始處理...', }); const categoryResults: ExpertTransformationCategoryResult[] = []; let globalExperts: ExpertProfile[] = []; // Process each category sequentially for (const category of input.categories) { const attributes = input.attributesByCategory[category.name] || []; if (attributes.length === 0) continue; const { result, experts: categoryExperts } = await transformCategory( input.query, category, attributes, input.expertConfig ); // Store global experts from first category if (globalExperts.length === 0 && categoryExperts.length > 0) { globalExperts = categoryExperts; } if (result) { categoryResults.push(result); } } // Build final result const finalResult: ExpertTransformationDAGResult = { query: input.query, experts: globalExperts, results: categoryResults, }; setResults(finalResult); setLoading(false); setProgress((prev) => ({ ...prev, step: 'done', message: '所有類別處理完成', })); return finalResult; }, [transformCategory] ); const clearResults = useCallback(() => { setResults(null); setError(null); setExperts(null); setProgress({ step: 'idle', currentCategory: '', processedCategories: [], message: '', }); }, []); return { loading, progress, results, error, experts, transformCategory, transformAll, clearResults, }; }