()
| 264 | }, [platformNameMap]); |
| 265 | |
| 266 | const handleAIAnalyze = async () => { |
| 267 | if (!githubToken) { |
| 268 | toast(t('GitHub token 未找到,请重新登录。', 'GitHub token not found. Please login again.'), 'error'); |
| 269 | return; |
| 270 | } |
| 271 | |
| 272 | const activeConfig = aiConfigs.find(config => config.id === activeAIConfig); |
| 273 | if (!activeConfig) { |
| 274 | toast(t('请先在设置中配置AI服务。', 'Please configure AI service in settings first.'), 'error'); |
| 275 | return; |
| 276 | } |
| 277 | |
| 278 | if (activeConfig.apiKeyStatus === 'decrypt_failed' || activeConfig.apiKeyStatus === 'empty') { |
| 279 | toast(t('AI服务的API密钥无法解密或为空,请在设置中重新输入并保存该配置。', 'The AI service API key could not be decrypted or is empty. Please re-enter and save the configuration in settings.'), 'error'); |
| 280 | return; |
| 281 | } |
| 282 | |
| 283 | if (!activeConfig.baseUrl || !activeConfig.apiKey || !activeConfig.model) { |
| 284 | toast(t('AI服务配置不完整,请检查API端点、密钥和模型名称。', 'AI service configuration is incomplete. Please check the API endpoint, key, and model name.'), 'error'); |
| 285 | return; |
| 286 | } |
| 287 | |
| 288 | if (repository.analyzed_at) { |
| 289 | const confirmMessage = language === 'zh' |
| 290 | ? `此仓库已于 ${new Date(repository.analyzed_at).toLocaleString()} 进行过AI分析。\n\n是否要重新分析?这将覆盖现有的分析结果。` |
| 291 | : `This repository was analyzed on ${new Date(repository.analyzed_at).toLocaleString()}.\n\nDo you want to re-analyze? This will overwrite the existing analysis results.`; |
| 292 | |
| 293 | if (!await confirm(t('重新分析确认', 'Re-analyze Confirmation'), confirmMessage, { type: 'warning' })) { |
| 294 | return; |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | abortControllerRef.current?.abort(); |
| 299 | const controller = new AbortController(); |
| 300 | abortControllerRef.current = controller; |
| 301 | |
| 302 | const analysisStartedAt = performance.now(); |
| 303 | setIsLocallyAnalyzing(true); |
| 304 | requestAnimationFrame(() => { |
| 305 | logger.info('ai.performance', 'Repository card AI spinner painted', { |
| 306 | repoId, |
| 307 | fullName: repository.full_name, |
| 308 | elapsedMs: Math.round(performance.now() - analysisStartedAt), |
| 309 | }); |
| 310 | }); |
| 311 | setAnalyzingRepository(repoId, true); |
| 312 | try { |
| 313 | const result = await analyzeRepository({ |
| 314 | repository, |
| 315 | githubToken, |
| 316 | aiConfig: activeConfig, |
| 317 | language, |
| 318 | categories: allCategories, |
| 319 | onProgress: (status) => { |
| 320 | logger.info('ai.performance', 'Repository card AI analysis step', { |
| 321 | repoId, |
| 322 | fullName: repository.full_name, |
| 323 | status, |
nothing calls this directly
no test coverage detected