mirror of
https://github.com/AmintaCCCP/GithubStarsManager.git
synced 2025-11-25 02:34:54 +08:00
0.1.4
This commit is contained in:
4
dist/index.html
vendored
4
dist/index.html
vendored
@@ -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" />
|
<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 -->
|
<!-- Material Icons CDN -->
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||||
<script type="module" crossorigin src="/assets/index-CQ4S0AeE.js"></script>
|
<script type="module" crossorigin src="/assets/index-DZXyNObJ.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-BQKjD-gi.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-BWYOfSoc.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-50 dark:bg-gray-900">
|
<body class="bg-gray-50 dark:bg-gray-900">
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "github-stars-manager",
|
"name": "github-stars-manager",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -197,7 +197,8 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
|
|||||||
ai_summary: analysis.summary,
|
ai_summary: analysis.summary,
|
||||||
ai_tags: analysis.tags,
|
ai_tags: analysis.tags,
|
||||||
ai_platforms: analysis.platforms,
|
ai_platforms: analysis.platforms,
|
||||||
analyzed_at: new Date().toISOString()
|
analyzed_at: new Date().toISOString(),
|
||||||
|
analysis_failed: false // 分析成功,清除失败标记
|
||||||
};
|
};
|
||||||
|
|
||||||
updateRepository(updatedRepo);
|
updateRepository(updatedRepo);
|
||||||
@@ -209,6 +210,16 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
|
|||||||
alert(successMessage);
|
alert(successMessage);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('AI analysis failed:', 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.');
|
alert(language === 'zh' ? 'AI分析失败,请检查AI配置和网络连接。' : 'AI analysis failed. Please check AI configuration and network connection.');
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -232,6 +243,12 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
|
|||||||
content: repository.custom_description,
|
content: repository.custom_description,
|
||||||
isCustom: true
|
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) {
|
} else if (showAISummary && repository.ai_summary) {
|
||||||
return {
|
return {
|
||||||
content: repository.ai_summary,
|
content: repository.ai_summary,
|
||||||
@@ -277,7 +294,12 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
|
|||||||
|
|
||||||
// 获取AI分析按钮的提示文本
|
// 获取AI分析按钮的提示文本
|
||||||
const getAIButtonTitle = () => {
|
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();
|
const analyzeTime = new Date(repository.analyzed_at).toLocaleString();
|
||||||
return language === 'zh'
|
return language === 'zh'
|
||||||
? `已于 ${analyzeTime} 分析过,点击重新分析`
|
? `已于 ${analyzeTime} 分析过,点击重新分析`
|
||||||
@@ -315,9 +337,12 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
|
|||||||
<button
|
<button
|
||||||
onClick={handleAIAnalyze}
|
onClick={handleAIAnalyze}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className={`p-2 rounded-lg transition-colors ${repository.analyzed_at
|
className={`p-2 rounded-lg transition-colors ${
|
||||||
? 'bg-green-100 text-green-600 dark:bg-green-900 dark:text-green-400 hover:bg-green-200 dark:hover:bg-green-800'
|
repository.analysis_failed
|
||||||
: 'bg-purple-100 text-purple-600 dark:bg-purple-900 dark:text-purple-400 hover:bg-purple-200 dark:hover:bg-purple-800'
|
? '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`}
|
} disabled:opacity-50`}
|
||||||
title={getAIButtonTitle()}
|
title={getAIButtonTitle()}
|
||||||
>
|
>
|
||||||
@@ -398,7 +423,13 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
|
|||||||
<span>{language === 'zh' ? '自定义' : 'Custom'}</span>
|
<span>{language === 'zh' ? '自定义' : 'Custom'}</span>
|
||||||
</div>
|
</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">
|
<div className="flex items-center space-x-1 text-xs text-green-600 dark:text-green-400">
|
||||||
<Bot className="w-3 h-3" />
|
<Bot className="w-3 h-3" />
|
||||||
<span>{language === 'zh' ? 'AI总结' : 'AI Summary'}</span>
|
<span>{language === 'zh' ? 'AI总结' : 'AI Summary'}</span>
|
||||||
@@ -494,7 +525,12 @@ export const RepositoryCard: React.FC<RepositoryCardProps> = ({
|
|||||||
<span>{language === 'zh' ? '已编辑' : 'Edited'}</span>
|
<span>{language === 'zh' ? '已编辑' : 'Edited'}</span>
|
||||||
</div>
|
</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="flex items-center space-x-1 text-xs">
|
||||||
<div className="w-2 h-2 bg-green-500 rounded-full" />
|
<div className="w-2 h-2 bg-green-500 rounded-full" />
|
||||||
<span>{language === 'zh' ? 'AI已分析' : 'AI analyzed'}</span>
|
<span>{language === 'zh' ? 'AI已分析' : 'AI analyzed'}</span>
|
||||||
|
|||||||
@@ -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) {
|
if (!githubToken) {
|
||||||
alert(language === 'zh' ? 'GitHub token 未找到,请重新登录。' : 'GitHub token not found. Please login again.');
|
alert(language === 'zh' ? 'GitHub token 未找到,请重新登录。' : 'GitHub token not found. Please login again.');
|
||||||
return;
|
return;
|
||||||
@@ -87,21 +87,27 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetRepos = analyzeUnanalyzedOnly
|
const targetRepos = analyzeFailedOnly
|
||||||
? filteredRepositories.filter(repo => !repo.analyzed_at)
|
? filteredRepositories.filter(repo => repo.analysis_failed)
|
||||||
: filteredRepositories;
|
: analyzeUnanalyzedOnly
|
||||||
|
? filteredRepositories.filter(repo => !repo.analyzed_at)
|
||||||
|
: filteredRepositories;
|
||||||
|
|
||||||
if (targetRepos.length === 0) {
|
if (targetRepos.length === 0) {
|
||||||
alert(language === 'zh'
|
const message = analyzeFailedOnly
|
||||||
? (analyzeUnanalyzedOnly ? '所有仓库都已经分析过了!' : '没有可分析的仓库!')
|
? (language === 'zh' ? '没有分析失败的仓库!' : 'No failed repositories to re-analyze!')
|
||||||
: (analyzeUnanalyzedOnly ? 'All repositories have been analyzed!' : 'No repositories to analyze!')
|
: analyzeUnanalyzedOnly
|
||||||
);
|
? (language === 'zh' ? '所有仓库都已经分析过了!' : 'All repositories have been analyzed!')
|
||||||
|
: (language === 'zh' ? '没有可分析的仓库!' : 'No repositories to analyze!');
|
||||||
|
alert(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionText = language === 'zh'
|
const actionText = analyzeFailedOnly
|
||||||
? (analyzeUnanalyzedOnly ? '未分析' : '全部')
|
? (language === 'zh' ? '失败' : 'failed')
|
||||||
: (analyzeUnanalyzedOnly ? 'unanalyzed' : 'all');
|
: analyzeUnanalyzedOnly
|
||||||
|
? (language === 'zh' ? '未分析' : 'unanalyzed')
|
||||||
|
: (language === 'zh' ? '全部' : 'all');
|
||||||
|
|
||||||
const confirmMessage = language === 'zh'
|
const confirmMessage = language === 'zh'
|
||||||
? `将对 ${targetRepos.length} 个${actionText}仓库进行AI分析,这可能需要几分钟时间。是否继续?`
|
? `将对 ${targetRepos.length} 个${actionText}仓库进行AI分析,这可能需要几分钟时间。是否继续?`
|
||||||
@@ -159,7 +165,8 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
|
|||||||
ai_summary: analysis.summary,
|
ai_summary: analysis.summary,
|
||||||
ai_tags: analysis.tags,
|
ai_tags: analysis.tags,
|
||||||
ai_platforms: analysis.platforms,
|
ai_platforms: analysis.platforms,
|
||||||
analyzed_at: new Date().toISOString()
|
analyzed_at: new Date().toISOString(),
|
||||||
|
analysis_failed: false // 分析成功,清除失败标记
|
||||||
};
|
};
|
||||||
|
|
||||||
updateRepository(updatedRepo);
|
updateRepository(updatedRepo);
|
||||||
@@ -169,6 +176,18 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
|
|||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(`Failed to analyze ${repo.full_name}:`, 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;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -275,7 +294,8 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const unanalyzedCount = filteredRepositories.filter(r => !r.analyzed_at).length;
|
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;
|
const t = (zh: string, en: string) => language === 'zh' ? zh : en;
|
||||||
|
|
||||||
@@ -320,7 +340,7 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
|
|||||||
<button
|
<button
|
||||||
onClick={() => handleAIAnalyze(true)}
|
onClick={() => handleAIAnalyze(true)}
|
||||||
disabled={unanalyzedCount === 0}
|
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">
|
<div className="font-medium text-gray-900 dark:text-white">
|
||||||
{t('分析未分析的', 'Analyze Unanalyzed')}
|
{t('分析未分析的', 'Analyze Unanalyzed')}
|
||||||
@@ -329,6 +349,18 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
|
|||||||
{t(`分析 ${unanalyzedCount} 个未分析仓库`, `Analyze ${unanalyzedCount} unanalyzed repositories`)}
|
{t(`分析 ${unanalyzedCount} 个未分析仓库`, `Analyze ${unanalyzedCount} unanalyzed repositories`)}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</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>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -414,6 +446,11 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
|
|||||||
• {analyzedCount} {t('个已AI分析', 'AI analyzed')}
|
• {analyzedCount} {t('个已AI分析', 'AI analyzed')}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
{failedCount > 0 && (
|
||||||
|
<span className="mr-3">
|
||||||
|
• {failedCount} {t('个分析失败', 'analysis failed')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
{unanalyzedCount > 0 && (
|
{unanalyzedCount > 0 && (
|
||||||
<span>
|
<span>
|
||||||
• {unanalyzedCount} {t('个未分析', 'unanalyzed')}
|
• {unanalyzedCount} {t('个未分析', 'unanalyzed')}
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ Focus on practicality and accurate categorization to help users quickly understa
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-600 dark:text-gray-400 mb-1">
|
<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>
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-500">
|
<p className="text-xs text-gray-500 dark:text-gray-500">
|
||||||
{t('检查是否有新版本可用', 'Check if a new version is available')}
|
{t('检查是否有新版本可用', 'Check if a new version is available')}
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ export class AIService {
|
|||||||
return this.parseAIResponse(content);
|
return this.parseAIResponse(content);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('AI analysis failed:', error);
|
console.error('AI analysis failed:', error);
|
||||||
// Fallback to basic analysis
|
// 抛出错误,让调用方处理失败状态
|
||||||
return this.fallbackAnalysis(repository);
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export class UpdateService {
|
|||||||
private static getCurrentVersion(): string {
|
private static getCurrentVersion(): string {
|
||||||
// 在实际应用中,这个版本号应该在构建时注入
|
// 在实际应用中,这个版本号应该在构建时注入
|
||||||
// 这里暂时硬编码,你可以通过构建脚本或环境变量来动态设置
|
// 这里暂时硬编码,你可以通过构建脚本或环境变量来动态设置
|
||||||
return '0.1.3';
|
return '0.1.4';
|
||||||
}
|
}
|
||||||
|
|
||||||
static async checkForUpdates(): Promise<UpdateCheckResult> {
|
static async checkForUpdates(): Promise<UpdateCheckResult> {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export interface Repository {
|
|||||||
ai_tags?: string[];
|
ai_tags?: string[];
|
||||||
ai_platforms?: string[]; // 新增:支持的平台类型
|
ai_platforms?: string[]; // 新增:支持的平台类型
|
||||||
analyzed_at?: string;
|
analyzed_at?: string;
|
||||||
|
analysis_failed?: boolean; // 新增:AI分析是否失败
|
||||||
// Release subscription
|
// Release subscription
|
||||||
subscribed_to_releases?: boolean;
|
subscribed_to_releases?: boolean;
|
||||||
// Manual editing fields
|
// Manual editing fields
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<h1>GitHub Stars Manager - 更新功能测试</h1>
|
<h1>GitHub Stars Manager - 更新功能测试</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>当前版本: v0.1.3</h2>
|
<h2>当前版本: v0.1.4</h2>
|
||||||
<button id="checkUpdate" onclick="checkForUpdates()">检查更新</button>
|
<button id="checkUpdate" onclick="checkForUpdates()">检查更新</button>
|
||||||
<div id="status"></div>
|
<div id="status"></div>
|
||||||
<div id="updateInfo"></div>
|
<div id="updateInfo"></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user