This commit is contained in:
AmintaCCCP
2025-08-12 20:48:52 +08:00
parent 4ef03f9dec
commit 3372552391
9 changed files with 103 additions and 29 deletions

4
dist/index.html vendored
View File

@@ -10,8 +10,8 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Material Icons CDN -->
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script type="module" crossorigin src="/assets/index-CQ4S0AeE.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BQKjD-gi.css">
<script type="module" crossorigin src="/assets/index-DZXyNObJ.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BWYOfSoc.css">
</head>
<body class="bg-gray-50 dark:bg-gray-900">
<div id="root"></div>

View File

@@ -1,7 +1,7 @@
{
"name": "github-stars-manager",
"private": true,
"version": "0.1.3",
"version": "0.1.4",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -197,7 +197,8 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
ai_summary: analysis.summary,
ai_tags: analysis.tags,
ai_platforms: analysis.platforms,
analyzed_at: new Date().toISOString()
analyzed_at: new Date().toISOString(),
analysis_failed: false // 分析成功,清除失败标记
};
updateRepository(updatedRepo);
@@ -209,6 +210,16 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
alert(successMessage);
} catch (error) {
console.error('AI analysis failed:', error);
// 标记为分析失败
const failedRepo = {
...repository,
analyzed_at: new Date().toISOString(),
analysis_failed: true
};
updateRepository(failedRepo);
alert(language === 'zh' ? 'AI分析失败请检查AI配置和网络连接。' : 'AI analysis failed. Please check AI configuration and network connection.');
} finally {
setLoading(false);
@@ -232,6 +243,12 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
content: repository.custom_description,
isCustom: true
};
} else if (showAISummary && repository.analysis_failed) {
return {
content: repository.description || (language === 'zh' ? '暂无描述' : 'No description available'),
isAI: false,
isFailed: true
};
} else if (showAISummary && repository.ai_summary) {
return {
content: repository.ai_summary,
@@ -277,7 +294,12 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
// 获取AI分析按钮的提示文本
const getAIButtonTitle = () => {
if (repository.analyzed_at) {
if (repository.analysis_failed) {
const analyzeTime = new Date(repository.analyzed_at!).toLocaleString();
return language === 'zh'
? `分析失败于 ${analyzeTime},点击重新分析`
: `Analysis failed on ${analyzeTime}, click to retry`;
} else if (repository.analyzed_at) {
const analyzeTime = new Date(repository.analyzed_at).toLocaleString();
return language === 'zh'
? `已于 ${analyzeTime} 分析过,点击重新分析`
@@ -315,7 +337,10 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
<button
onClick={handleAIAnalyze}
disabled={isLoading}
className={`p-2 rounded-lg transition-colors ${repository.analyzed_at
className={`p-2 rounded-lg transition-colors ${
repository.analysis_failed
? 'bg-red-100 text-red-600 dark:bg-red-900 dark:text-red-400 hover:bg-red-200 dark:hover:bg-red-800'
: repository.analyzed_at
? 'bg-green-100 text-green-600 dark:bg-green-900 dark:text-green-400 hover:bg-green-200 dark:hover:bg-green-800'
: 'bg-purple-100 text-purple-600 dark:bg-purple-900 dark:text-purple-400 hover:bg-purple-200 dark:hover:bg-purple-800'
} disabled:opacity-50`}
@@ -398,7 +423,13 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
<span>{language === 'zh' ? '自定义' : 'Custom'}</span>
</div>
)}
{displayContent.isAI && (
{displayContent.isFailed && (
<div className="flex items-center space-x-1 text-xs text-red-600 dark:text-red-400">
<Bot className="w-3 h-3" />
<span>{language === 'zh' ? '分析失败' : 'Analysis Failed'}</span>
</div>
)}
{displayContent.isAI && !displayContent.isFailed && (
<div className="flex items-center space-x-1 text-xs text-green-600 dark:text-green-400">
<Bot className="w-3 h-3" />
<span>{language === 'zh' ? 'AI总结' : 'AI Summary'}</span>
@@ -494,7 +525,12 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
<span>{language === 'zh' ? '已编辑' : 'Edited'}</span>
</div>
)}
{repository.analyzed_at && (
{repository.analysis_failed ? (
<div className="flex items-center space-x-1 text-xs">
<div className="w-2 h-2 bg-red-500 rounded-full" />
<span>{language === 'zh' ? '分析失败' : 'Analysis failed'}</span>
</div>
) : repository.analyzed_at && (
<div className="flex items-center space-x-1 text-xs">
<div className="w-2 h-2 bg-green-500 rounded-full" />
<span>{language === 'zh' ? 'AI已分析' : 'AI analyzed'}</span>

View File

@@ -75,7 +75,7 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
);
});
const handleAIAnalyze = async (analyzeUnanalyzedOnly: boolean = false) => {
const handleAIAnalyze = async (analyzeUnanalyzedOnly: boolean = false, analyzeFailedOnly: boolean = false) => {
if (!githubToken) {
alert(language === 'zh' ? 'GitHub token 未找到,请重新登录。' : 'GitHub token not found. Please login again.');
return;
@@ -87,21 +87,27 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
return;
}
const targetRepos = analyzeUnanalyzedOnly
const targetRepos = analyzeFailedOnly
? filteredRepositories.filter(repo => repo.analysis_failed)
: analyzeUnanalyzedOnly
? filteredRepositories.filter(repo => !repo.analyzed_at)
: filteredRepositories;
if (targetRepos.length === 0) {
alert(language === 'zh'
? (analyzeUnanalyzedOnly ? '所有仓库都已经分析过了!' : '没有分析的仓库!')
: (analyzeUnanalyzedOnly ? 'All repositories have been analyzed!' : 'No repositories to analyze!')
);
const message = analyzeFailedOnly
? (language === 'zh' ? '没有分析失败的仓库!' : 'No failed repositories to re-analyze!')
: analyzeUnanalyzedOnly
? (language === 'zh' ? '所有仓库都已经分析过了!' : 'All repositories have been analyzed!')
: (language === 'zh' ? '没有可分析的仓库!' : 'No repositories to analyze!');
alert(message);
return;
}
const actionText = language === 'zh'
? (analyzeUnanalyzedOnly ? '未分析' : '全部')
: (analyzeUnanalyzedOnly ? 'unanalyzed' : 'all');
const actionText = analyzeFailedOnly
? (language === 'zh' ? '失败' : 'failed')
: analyzeUnanalyzedOnly
? (language === 'zh' ? '未分析' : 'unanalyzed')
: (language === 'zh' ? '全部' : 'all');
const confirmMessage = language === 'zh'
? `将对 ${targetRepos.length}${actionText}仓库进行AI分析这可能需要几分钟时间。是否继续`
@@ -159,7 +165,8 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
ai_summary: analysis.summary,
ai_tags: analysis.tags,
ai_platforms: analysis.platforms,
analyzed_at: new Date().toISOString()
analyzed_at: new Date().toISOString(),
analysis_failed: false // 分析成功,清除失败标记
};
updateRepository(updatedRepo);
@@ -169,6 +176,18 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
return true;
} catch (error) {
console.warn(`Failed to analyze ${repo.full_name}:`, error);
// 标记为分析失败
const failedRepo = {
...repo,
analyzed_at: new Date().toISOString(),
analysis_failed: true
};
updateRepository(failedRepo);
analyzed++;
setAnalysisProgress({ current: analyzed, total: targetRepos.length });
return false;
}
};
@@ -275,7 +294,8 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
}
const unanalyzedCount = filteredRepositories.filter(r => !r.analyzed_at).length;
const analyzedCount = filteredRepositories.filter(r => r.analyzed_at).length;
const analyzedCount = filteredRepositories.filter(r => r.analyzed_at && !r.analysis_failed).length;
const failedCount = filteredRepositories.filter(r => r.analysis_failed).length;
const t = (zh: string, en: string) => language === 'zh' ? zh : en;
@@ -320,7 +340,7 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
<button
onClick={() => handleAIAnalyze(true)}
disabled={unanalyzedCount === 0}
className="w-full px-4 py-3 text-left hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
className="w-full px-4 py-3 text-left hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed border-b border-gray-100 dark:border-gray-600"
>
<div className="font-medium text-gray-900 dark:text-white">
{t('分析未分析的', 'Analyze Unanalyzed')}
@@ -329,6 +349,18 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
{t(`分析 ${unanalyzedCount} 个未分析仓库`, `Analyze ${unanalyzedCount} unanalyzed repositories`)}
</div>
</button>
<button
onClick={() => handleAIAnalyze(false, true)}
disabled={failedCount === 0}
className="w-full px-4 py-3 text-left hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="font-medium text-gray-900 dark:text-white">
{t('重新分析失败的', 'Re-analyze Failed')}
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
{t(`重新分析 ${failedCount} 个失败仓库`, `Re-analyze ${failedCount} failed repositories`)}
</div>
</button>
</div>
)}
</div>
@@ -414,6 +446,11 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
{analyzedCount} {t('个已AI分析', 'AI analyzed')}
</span>
)}
{failedCount > 0 && (
<span className="mr-3">
{failedCount} {t('个分析失败', 'analysis failed')}
</span>
)}
{unanalyzedCount > 0 && (
<span>
{unanalyzedCount} {t('个未分析', 'unanalyzed')}

View File

@@ -373,7 +373,7 @@ Focus on practicality and accurate categorization to help users quickly understa
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-1">
{t('当前版本: v0.1.3', 'Current Version: v0.1.3')}
{t('当前版本: v0.1.4', 'Current Version: v0.1.4')}
</p>
<p className="text-xs text-gray-500 dark:text-gray-500">
{t('检查是否有新版本可用', 'Check if a new version is available')}

View File

@@ -58,8 +58,8 @@ export class AIService {
return this.parseAIResponse(content);
} catch (error) {
console.error('AI analysis failed:', error);
// Fallback to basic analysis
return this.fallbackAnalysis(repository);
// 抛出错误,让调用方处理失败状态
throw error;
}
}

View File

@@ -17,7 +17,7 @@ export class UpdateService {
private static getCurrentVersion(): string {
// 在实际应用中,这个版本号应该在构建时注入
// 这里暂时硬编码,你可以通过构建脚本或环境变量来动态设置
return '0.1.3';
return '0.1.4';
}
static async checkForUpdates(): Promise<UpdateCheckResult> {

View File

@@ -20,6 +20,7 @@ export interface Repository {
ai_tags?: string[];
ai_platforms?: string[]; // 新增:支持的平台类型
analyzed_at?: string;
analysis_failed?: boolean; // 新增AI分析是否失败
// Release subscription
subscribed_to_releases?: boolean;
// Manual editing fields

View File

@@ -64,7 +64,7 @@
<h1>GitHub Stars Manager - 更新功能测试</h1>
<div>
<h2>当前版本: v0.1.3</h2>
<h2>当前版本: v0.1.4</h2>
<button id="checkUpdate" onclick="checkForUpdates()">检查更新</button>
<div id="status"></div>
<div id="updateInfo"></div>