diff --git a/app/api/evaluate/route.ts b/app/api/evaluate/route.ts index 07a723b..6c13faf 100644 --- a/app/api/evaluate/route.ts +++ b/app/api/evaluate/route.ts @@ -263,7 +263,7 @@ export async function POST(request: NextRequest) { score: score, max_score: maxScore, weight: criteriaItem.weight, - weighted_score: (score / maxScore) * criteriaItem.weight, + weighted_score: (score / maxScore) * (criteriaItem.weight / 100), percentage: (score / maxScore) * 100 }; @@ -274,7 +274,7 @@ export async function POST(request: NextRequest) { score: score, max_score: maxScore, weight: criteriaItem.weight, - weighted_score: (score / maxScore) * criteriaItem.weight, + weighted_score: (score / maxScore) * (criteriaItem.weight / 100), percentage: (score / maxScore) * 100 }); diff --git a/app/api/evaluation/[id]/download/route.ts b/app/api/evaluation/[id]/download/route.ts index a3f5256..d56ce40 100644 --- a/app/api/evaluation/[id]/download/route.ts +++ b/app/api/evaluation/[id]/download/route.ts @@ -85,7 +85,7 @@ export async function GET( overview: { excellentItems: evaluationWithDetails.excellent_items || 0, improvementItems: evaluationWithDetails.improvement_items || 0, - overallPerformance: Number(evaluationWithDetails.overall_score) || 0 + overallPerformance: Math.round(Number(evaluationWithDetails.overall_score) || 0) }, improvementSuggestions: { overallSuggestions: feedbackByType.overall[0]?.content || '無詳細分析', diff --git a/app/api/evaluation/[id]/route.ts b/app/api/evaluation/[id]/route.ts index 62023b5..cbb8d69 100644 --- a/app/api/evaluation/[id]/route.ts +++ b/app/api/evaluation/[id]/route.ts @@ -109,7 +109,7 @@ export async function GET( overview: { excellentItems: evaluationWithDetails.excellent_items || 0, improvementItems: evaluationWithDetails.improvement_items || 0, - overallPerformance: Number(evaluationWithDetails.overall_score) || 0 + overallPerformance: Math.round(Number(evaluationWithDetails.overall_score) || 0) }, detailedAnalysis: { summary: feedbackByType.overall[0]?.content || '無詳細分析', diff --git a/app/results/results-content.tsx b/app/results/results-content.tsx index 08d8827..a2857ab 100644 --- a/app/results/results-content.tsx +++ b/app/results/results-content.tsx @@ -103,7 +103,7 @@ const calculateMockOverview = (criteria: any[]) => { const improvementItems = criteria.filter(item => item.score < averageScore).length; // 整體表現:基於權重的加權平均分數 - const overallPerformance = Math.round(criteria.reduce((sum, item) => sum + (item.score / item.maxScore) * item.weight, 0)); + const overallPerformance = Math.round(criteria.reduce((sum, item) => sum + (item.score / item.maxScore) * (item.weight / 100), 0)); return { excellentItems, @@ -254,7 +254,7 @@ export default function ResultsContent() { const improvementItems = criteria.filter(item => item.score < averageScore).length; // 整體表現:基於權重的加權平均分數 - const overallPerformance = Math.round(criteria.reduce((sum, item) => sum + (item.score / item.maxScore) * item.weight, 0)); + const overallPerformance = Math.round(criteria.reduce((sum, item) => sum + (item.score / item.maxScore) * (item.weight / 100), 0) * 10) / 10; return { excellentItems, @@ -263,9 +263,24 @@ export default function ResultsContent() { }; }; + // 重新計算基於權重的總分 + const calculateWeightedTotalScore = (criteria: any[]): number => { + if (!criteria || criteria.length === 0) return 0; + + const totalScore = criteria.reduce((sum, item) => { + const weightedScore = (item.score / item.maxScore) * (item.weight / 100); + return sum + weightedScore; + }, 0); + + // 將小數轉換為100分制的分數,保留一位小數 + return Math.round(totalScore * 100 * 10) / 10; // 保留一位小數 + }; + // 確保所有必要的數據結構存在 const safeResults = { ...results, + // 重新計算總分 + overallScore: calculateWeightedTotalScore(results.criteria || []), overview: results.overview || calculateOverview(results.criteria || []), chartData: results.chartData || { barChart: [], diff --git a/lib/services/gemini.ts b/lib/services/gemini.ts index 587a371..baf1022 100644 --- a/lib/services/gemini.ts +++ b/lib/services/gemini.ts @@ -145,7 +145,17 @@ ${criteriaList} **評分要求:** 1. 請對每個評分項目給出 0 到滿分的分數,要敢於給出極高分(9-10分)和極低分(1-3分) 2. 為每個項目提供具體的評分理由、優點和改進建議 - 3. 計算總分(各項目分數 × 權重比例) + 3. **重要:計算總分時,請嚴格按照以下步驟:** + - 步驟1:計算每個項目的加權分數 = (該項目得分 ÷ 該項目滿分) × 該項目權重百分比 + - 步驟2:將所有項目的加權分數相加得到總分 + - 步驟3:檢查計算結果是否正確 + - **計算範例:** + * 應用實務性:8/10 × 30% = 0.8 × 30 = 24分 + * 創新性:6/10 × 15% = 0.6 × 15 = 9分 + * 成效與效益:9/10 × 25% = 0.9 × 25 = 22.5分 + * 擴散與可複用性:7/10 × 20% = 0.7 × 20 = 14分 + * 簡報與表達:8/10 × 10% = 0.8 × 10 = 8分 + * **總分 = 24 + 9 + 22.5 + 14 + 8 = 77.5分** 4. 提供整體評價和建議 5. 分析優秀項目和待改進項目的數量 6. 給出等級評比 (S、A+、A、A-、B+、B、B-、C、D) @@ -156,7 +166,7 @@ ${criteriaList} **回應格式 (請嚴格按照以下 JSON 格式回應):** { "projectTitle": "專案標題", - "overallScore": 總分數字, + "overallScore": 總分數字(必須是根據加權公式計算的正確總分,請仔細計算每個項目的加權分數後相加,例如:77.5), "totalPossible": 100, "grade": "等級評比", "performanceStatus": "表現狀態", @@ -239,6 +249,12 @@ ${criteriaList} } } +**重要提醒:在回應前,請務必檢查以下計算:** +1. 列出每個項目的得分和權重 +2. 計算每個項目的加權分數:(得分÷滿分) × 權重百分比 +3. 將所有加權分數相加得到總分 +4. 確認總分是否正確 + 請確保回應是有效的 JSON 格式,不要包含任何其他文字。 `.trim(); } @@ -308,8 +324,8 @@ ${criteriaList} console.log(' 優秀項目 (≥' + averageScore + '):', excellentItems); console.log(' 待改進項目 (<' + averageScore + '):', improvementItems); - // 整體表現:基於權重的加權平均分數 - const overallPerformance = Math.round(criteria.reduce((sum, item) => sum + (item.score / item.maxScore) * item.weight, 0)); + // 整體表現:基於權重的加權平均分數(百分比) + const overallPerformance = Math.round(criteria.reduce((sum, item) => sum + (item.score / item.maxScore) * (item.weight / 100), 0) * 100); return { excellentItems, @@ -331,7 +347,7 @@ ${criteriaList} })), pieChart: criteria.map(item => ({ name: item.name, - value: item.weightedScore || (item.score / item.maxScore) * item.weight, + value: item.weightedScore || (item.score / item.maxScore) * (item.weight / 100), weight: item.weight })), radarChart: criteria.map(item => ({ @@ -387,14 +403,25 @@ ${criteriaList} private static convertToProjectEvaluation(parsed: any, criteria: CriteriaItem[]): ProjectEvaluation { console.log('🔄 轉換完整格式回應...'); - // 計算總分 + // 計算總分 - 總是重新計算,不直接使用 AI 的 overallScore let totalScore = 0; - if (parsed.overallScore) { - totalScore = Number(parsed.overallScore); - } else if (parsed.criteria && Array.isArray(parsed.criteria)) { + if (parsed.criteria && Array.isArray(parsed.criteria)) { + // 使用權重重新計算總分 totalScore = parsed.criteria.reduce((sum: number, item: any) => { - return sum + (Number(item.weightedScore) || 0); + const score = Number(item.score) || 0; + const maxScore = Number(item.maxScore) || 10; + const weight = Number(item.weight) || 0; + const weightedScore = (score / maxScore) * (weight / 100); + console.log(` ${item.name}: ${score}/${maxScore} × ${weight}% = ${weightedScore.toFixed(2)}`); + return sum + weightedScore; }, 0); + // 轉換為 100 分制 + totalScore = totalScore * 100; + console.log(`📊 重新計算的總分: ${totalScore.toFixed(1)}/100`); + } else if (parsed.overallScore) { + // 如果沒有 criteria 數據,才使用 AI 的 overallScore + totalScore = Number(parsed.overallScore); + console.log(`📊 使用 AI 的總分: ${totalScore}/100`); } // 轉換評分結果 @@ -410,7 +437,7 @@ ${criteriaList} return { projectTitle: parsed.projectTitle || '', projectDescription: '', - totalScore: Math.round(totalScore * 100) / 100, + totalScore: Math.round(totalScore * 10) / 10, // 保留一位小數(100分制) maxTotalScore: 100, results, overallFeedback: parsed.detailedAnalysis?.summary || parsed.overallFeedback || '整體評價', @@ -570,7 +597,7 @@ ${criteriaList} totalScore = results.reduce((sum, result) => { const criteriaItem = criteria.find(c => c.id === result.criteriaId); const weight = criteriaItem ? criteriaItem.weight : 0; - const weightedScore = (result.score / result.maxScore) * weight; + const weightedScore = (result.score / result.maxScore) * (weight / 100); console.log(` ${result.criteriaName}: ${result.score}/${result.maxScore} × ${weight}% = ${weightedScore.toFixed(2)}`); return sum + weightedScore; }, 0); @@ -587,8 +614,8 @@ ${criteriaList} return { projectTitle: '', projectDescription: '', - totalScore: Math.round(totalScore * 100) / 100, // 四捨五入到小數點後兩位 - maxTotalScore: Math.round(maxTotalScore * 100) / 100, + totalScore: Math.round(totalScore * 10) / 10, // 四捨五入到小數點後一位 + maxTotalScore: Math.round(maxTotalScore * 10) / 10, results, overallFeedback: parsed.overallFeedback || '基於資料庫評分標準的整體評價' }; @@ -621,7 +648,7 @@ ${criteriaList} totalScore = results.reduce((sum, result) => { const criteriaItem = criteria.find(c => c.id === result.criteriaId); const weight = criteriaItem ? criteriaItem.weight : 0; - return sum + ((result.score / result.maxScore) * weight); + return sum + ((result.score / result.maxScore) * (weight / 100)); }, 0); } else { const rawTotal = results.reduce((sum, result) => sum + result.score, 0); @@ -632,8 +659,8 @@ ${criteriaList} return { projectTitle: '', projectDescription: '', - totalScore: Math.round(totalScore * 100) / 100, - maxTotalScore: Math.round(maxTotalScore * 100) / 100, + totalScore: Math.round(totalScore * 10) / 10, // 四捨五入到小數點後一位 + maxTotalScore: Math.round(maxTotalScore * 10) / 10, results, overallFeedback: '由於技術問題,無法完成完整的 AI 分析。建議檢查文件格式或重新上傳。' }; diff --git a/uploads/projects/30/1758644704994_cm3863nuv.pptx b/uploads/projects/30/1758644704994_cm3863nuv.pptx new file mode 100644 index 0000000..8b38ba6 Binary files /dev/null and b/uploads/projects/30/1758644704994_cm3863nuv.pptx differ