diff --git a/app/api/evaluation/[id]/route.ts b/app/api/evaluation/[id]/route.ts
new file mode 100644
index 0000000..b55bec2
--- /dev/null
+++ b/app/api/evaluation/[id]/route.ts
@@ -0,0 +1,168 @@
+import { NextRequest, NextResponse } from 'next/server';
+import { EvaluationService } from '@/lib/services/database';
+
+export async function GET(
+ request: NextRequest,
+ { params }: { params: { id: string } }
+) {
+ try {
+ const evaluationId = parseInt(params.id);
+
+ if (isNaN(evaluationId)) {
+ return NextResponse.json(
+ { success: false, error: '無效的評審ID' },
+ { status: 400 }
+ );
+ }
+
+ console.log(`📊 開始獲取評審詳細數據: ID=${evaluationId}`);
+
+ // 獲取評審詳細數據
+ const evaluationWithDetails = await EvaluationService.findWithDetails(evaluationId);
+
+ if (!evaluationWithDetails) {
+ return NextResponse.json(
+ { success: false, error: '找不到指定的評審記錄' },
+ { status: 404 }
+ );
+ }
+
+ console.log(`✅ 成功獲取評審數據: 專案=${evaluationWithDetails.project?.title}`);
+
+ // 處理反饋數據,按類型分組
+ const feedbackByType = {
+ criteria: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'criteria') || [],
+ strength: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'strength') || [],
+ improvement: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'improvement') || [],
+ overall: evaluationWithDetails.feedback?.filter(f => f.feedback_type === 'overall') || []
+ };
+
+ // 為每個評分標準獲取對應的 AI 評語、優點和改進建議
+ const criteriaWithFeedback = evaluationWithDetails.scores?.map(score => {
+ const criteriaId = score.criteria_item_id;
+ const criteriaName = score.criteria_item_name || '未知項目';
+
+ // 獲取該評分標準的 AI 評語
+ const criteriaFeedback = feedbackByType.criteria
+ .filter(f => f.criteria_item_id === criteriaId)
+ .map(f => f.content)
+ .filter((content, index, arr) => arr.indexOf(content) === index); // 去重
+
+ // 獲取該評分標準的優點
+ const strengths = feedbackByType.strength
+ .filter(f => f.criteria_item_id === criteriaId)
+ .map(f => f.content)
+ .filter((content, index, arr) => arr.indexOf(content) === index); // 去重
+
+ // 獲取該評分標準的改進建議
+ const improvements = feedbackByType.improvement
+ .filter(f => f.criteria_item_id === criteriaId)
+ .map(f => f.content)
+ .filter((content, index, arr) => arr.indexOf(content) === index); // 去重
+
+ return {
+ name: criteriaName,
+ score: Number(score.score) || 0,
+ maxScore: Number(score.max_score) || 10,
+ weight: Number(score.weight) || 1,
+ weightedScore: Number(score.weighted_score) || 0,
+ percentage: Number(score.percentage) || 0,
+ feedback: criteriaFeedback[0] || '無評語', // 使用第一個評語
+ strengths: strengths,
+ improvements: improvements
+ };
+ }) || [];
+
+ // 生成圖表數據
+ const chartData = {
+ // 各項目得分 - 使用 evaluation_scores 的 score 資料
+ barChart: criteriaWithFeedback.map(criteria => ({
+ name: criteria.name,
+ score: criteria.score
+ })),
+
+ // 權重分布 - 使用 evaluation_scores 的 weighted_score 資料
+ pieChart: criteriaWithFeedback.map(criteria => ({
+ name: criteria.name,
+ value: criteria.weightedScore,
+ weight: criteria.weight
+ })),
+
+ // 能力雷達圖 - 使用 evaluation_scores 的 score 資料
+ radarChart: criteriaWithFeedback.map(criteria => ({
+ subject: criteria.name,
+ score: criteria.score,
+ fullMark: criteria.maxScore
+ }))
+ };
+
+ // 轉換數據格式以符合前端需求
+ const formattedData = {
+ projectTitle: evaluationWithDetails.project?.title || '未知專案',
+ overallScore: Number(evaluationWithDetails.overall_score) || 0,
+ totalPossible: Number(evaluationWithDetails.max_possible_score) || 100,
+ grade: evaluationWithDetails.grade || 'N/A',
+ performanceStatus: evaluationWithDetails.performance_status || 'N/A',
+ recommendedStars: evaluationWithDetails.recommended_stars || 0,
+ analysisDate: evaluationWithDetails.created_at ? new Date(evaluationWithDetails.created_at).toISOString().split('T')[0] : new Date().toISOString().split('T')[0],
+ criteria: criteriaWithFeedback,
+ overview: {
+ excellentItems: evaluationWithDetails.excellent_items || 0,
+ improvementItems: evaluationWithDetails.improvement_items || 0,
+ overallPerformance: Number(evaluationWithDetails.overall_score) || 0
+ },
+ detailedAnalysis: {
+ summary: feedbackByType.overall[0]?.content || '無詳細分析',
+ keyFindings: feedbackByType.overall.map(f => f.content).filter((content, index, arr) => arr.indexOf(content) === index) // 去重
+ },
+ improvementSuggestions: {
+ // 整體改進建議 - evaluation_feedback 的第一筆 overall
+ overallSuggestions: feedbackByType.overall[0]?.content || '無改進建議',
+
+ // 繼續保持的優勢 - evaluation_feedback 的 strength
+ maintainStrengths: feedbackByType.strength
+ .filter(f => f.criteria_item_id) // 只取有 criteria_item_id 的
+ .map(f => ({
+ title: f.criteria_item_name || '優勢',
+ description: f.content || '無描述'
+ }))
+ .filter((item, index, arr) => arr.findIndex(i => i.title === item.title) === index), // 去重
+
+ // 重點改進方向 - evaluation_feedback 的 improvement (除了最後3筆)
+ keyImprovements: feedbackByType.improvement
+ .filter(f => f.criteria_item_id) // 只取有 criteria_item_id 的
+ .slice(0, -3) // 排除最後3筆
+ .map(f => ({
+ title: f.criteria_item_name || '改進項目',
+ description: f.content || '無描述',
+ suggestions: [f.content || '無建議']
+ }))
+ .filter((item, index, arr) => arr.findIndex(i => i.title === item.title) === index), // 去重
+
+ // 下一步行動計劃 - evaluation_feedback 的 improvement 最後3筆
+ actionPlan: feedbackByType.improvement
+ .filter(f => f.criteria_item_id) // 只取有 criteria_item_id 的
+ .slice(-3) // 取最後3筆
+ .map((f, index) => ({
+ phase: `階段 ${index + 1}`,
+ description: f.content || '無描述'
+ }))
+ },
+ chartData: chartData
+ };
+
+ console.log(`📋 評審數據格式化完成: 專案=${formattedData.projectTitle}, 分數=${formattedData.overallScore}`);
+
+ return NextResponse.json({
+ success: true,
+ data: formattedData
+ });
+
+ } catch (error) {
+ console.error('❌ 獲取評審詳細數據失敗:', error);
+ return NextResponse.json(
+ { success: false, error: '獲取評審詳細數據失敗' },
+ { status: 500 }
+ );
+ }
+}
diff --git a/app/history/page.tsx b/app/history/page.tsx
index 474520d..4615a5e 100644
--- a/app/history/page.tsx
+++ b/app/history/page.tsx
@@ -260,7 +260,7 @@ export default function HistoryPage() {
{item.status === "completed" ? (
<>
diff --git a/app/results/page.tsx b/app/results/page.tsx
index 8f39ed7..2f976c0 100644
--- a/app/results/page.tsx
+++ b/app/results/page.tsx
@@ -1,6 +1,7 @@
"use client"
import { useState, useEffect } from "react"
+import { useSearchParams } from "next/navigation"
import { Sidebar } from "@/components/sidebar"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
@@ -128,32 +129,58 @@ export default function ResultsPage() {
const [activeTab, setActiveTab] = useState("overview")
const [evaluationData, setEvaluationData] = useState(null)
const [isLoading, setIsLoading] = useState(true)
+ const [error, setError] = useState(null)
const { toast } = useToast()
+ const searchParams = useSearchParams()
useEffect(() => {
- // 從 localStorage 獲取評審結果
- const storedData = localStorage.getItem('evaluationResult')
- if (storedData) {
+ const loadEvaluationData = async () => {
try {
- const data = JSON.parse(storedData)
- setEvaluationData(data)
+ setIsLoading(true)
+ setError(null)
+
+ // 檢查是否有 URL 參數中的評審 ID
+ const evaluationId = searchParams.get('id')
+
+ if (evaluationId) {
+ // 從 API 獲取評審數據
+ console.log(`📊 從 API 獲取評審數據: ID=${evaluationId}`)
+ const response = await fetch(`/api/evaluation/${evaluationId}`)
+ const result = await response.json()
+
+ if (result.success) {
+ setEvaluationData(result.data)
+ console.log('✅ 成功載入評審數據:', result.data.projectTitle)
+ } else {
+ throw new Error(result.error || '獲取評審數據失敗')
+ }
+ } else {
+ // 回退到從 localStorage 獲取評審結果
+ console.log('📊 從 localStorage 獲取評審結果')
+ const storedData = localStorage.getItem('evaluationResult')
+ if (storedData) {
+ const data = JSON.parse(storedData)
+ setEvaluationData(data)
+ console.log('✅ 成功載入 localStorage 數據')
+ } else {
+ throw new Error('沒有找到評審結果')
+ }
+ }
} catch (error) {
- console.error('解析評審結果失敗:', error)
+ console.error('載入評審結果失敗:', error)
+ setError(error.message)
toast({
- title: "數據錯誤",
- description: "無法載入評審結果,請重新進行評審",
+ title: "載入失敗",
+ description: error.message || "無法載入評審結果,請重新進行評審",
variant: "destructive",
})
+ } finally {
+ setIsLoading(false)
}
- } else {
- toast({
- title: "無評審結果",
- description: "請先進行評審以查看結果",
- variant: "destructive",
- })
}
- setIsLoading(false)
- }, [toast])
+
+ loadEvaluationData()
+ }, [searchParams, toast])
// 如果正在載入,顯示載入狀態
if (isLoading) {
@@ -174,8 +201,8 @@ export default function ResultsPage() {
)
}
- // 如果沒有數據,顯示錯誤狀態
- if (!evaluationData) {
+ // 如果沒有數據或發生錯誤,顯示錯誤狀態
+ if (!evaluationData || error) {
return (
@@ -183,10 +210,17 @@ export default function ResultsPage() {
-
沒有找到評審結果
-
+
+ {error ? `載入失敗: ${error}` : '沒有找到評審結果'}
+
+
+
+
+
@@ -196,7 +230,7 @@ export default function ResultsPage() {
}
// 使用真實數據或回退到模擬數據
- const results = evaluationData.evaluation?.fullData || mockResults
+ const results = evaluationData.evaluation?.fullData || evaluationData || mockResults
// 計算統計數據 - 基於 criteria_items 的平均分作為閾值
const calculateOverview = (criteria: any[]) => {
diff --git a/check-feedback-data.js b/check-feedback-data.js
new file mode 100644
index 0000000..4a0013a
--- /dev/null
+++ b/check-feedback-data.js
@@ -0,0 +1,66 @@
+const mysql = require('mysql2/promise');
+
+const dbConfig = {
+ host: 'mysql.theaken.com',
+ port: 33306,
+ user: 'root',
+ password: 'zh6161168',
+ database: 'db_AI_scoring'
+};
+
+async function checkFeedbackData() {
+ let connection;
+ try {
+ console.log('🔗 連接到資料庫...');
+ connection = await mysql.createConnection(dbConfig);
+ console.log('✅ 資料庫連接成功');
+
+ // 檢查 evaluation_feedback 表結構
+ console.log('📋 檢查 evaluation_feedback 表結構...');
+ const [columns] = await connection.execute(`
+ SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE TABLE_NAME = 'evaluation_feedback'
+ ORDER BY ORDINAL_POSITION
+ `);
+ console.log('表結構:', columns);
+
+ // 檢查 evaluation_feedback 數據
+ console.log('📊 檢查 evaluation_feedback 數據...');
+ const [feedbackData] = await connection.execute(`
+ SELECT id, evaluation_id, criteria_item_id, feedback_type, content, sort_order
+ FROM evaluation_feedback
+ WHERE evaluation_id = 2
+ ORDER BY sort_order
+ `);
+ console.log('評審 ID 2 的反饋數據:', feedbackData);
+
+ // 檢查不同 feedback_type 的數據
+ console.log('🔍 檢查不同 feedback_type 的數據...');
+ const [typeStats] = await connection.execute(`
+ SELECT feedback_type, COUNT(*) as count
+ FROM evaluation_feedback
+ GROUP BY feedback_type
+ `);
+ console.log('feedback_type 統計:', typeStats);
+
+ // 檢查 criteria_items 表
+ console.log('📝 檢查 criteria_items 表...');
+ const [criteriaItems] = await connection.execute(`
+ SELECT id, name, description
+ FROM criteria_items
+ ORDER BY id
+ `);
+ console.log('評分標準項目:', criteriaItems);
+
+ } catch (error) {
+ console.error('❌ 錯誤:', error.message);
+ } finally {
+ if (connection) {
+ await connection.end();
+ console.log('🔌 資料庫連接已關閉');
+ }
+ }
+}
+
+checkFeedbackData();
diff --git a/check-strength-improvement.js b/check-strength-improvement.js
new file mode 100644
index 0000000..26fa975
--- /dev/null
+++ b/check-strength-improvement.js
@@ -0,0 +1,61 @@
+const mysql = require('mysql2/promise');
+
+const dbConfig = {
+ host: 'mysql.theaken.com',
+ port: 33306,
+ user: 'root',
+ password: 'zh6161168',
+ database: 'db_AI_scoring'
+};
+
+async function checkStrengthImprovement() {
+ let connection;
+ try {
+ console.log('🔗 連接到資料庫...');
+ connection = await mysql.createConnection(dbConfig);
+ console.log('✅ 資料庫連接成功');
+
+ // 檢查 strength 類型的數據
+ console.log('💪 檢查 strength 類型的數據...');
+ const [strengthData] = await connection.execute(`
+ SELECT ef.id, ef.evaluation_id, ef.criteria_item_id, ef.content, ci.name as criteria_name
+ FROM evaluation_feedback ef
+ LEFT JOIN criteria_items ci ON ef.criteria_item_id = ci.id
+ WHERE ef.evaluation_id = 2 AND ef.feedback_type = 'strength'
+ ORDER BY ef.criteria_item_id, ef.sort_order
+ `);
+ console.log('優點數據:', strengthData);
+
+ // 檢查 improvement 類型的數據
+ console.log('🔧 檢查 improvement 類型的數據...');
+ const [improvementData] = await connection.execute(`
+ SELECT ef.id, ef.evaluation_id, ef.criteria_item_id, ef.content, ci.name as criteria_name
+ FROM evaluation_feedback ef
+ LEFT JOIN criteria_items ci ON ef.criteria_item_id = ci.id
+ WHERE ef.evaluation_id = 2 AND ef.feedback_type = 'improvement'
+ ORDER BY ef.criteria_item_id, ef.sort_order
+ `);
+ console.log('改進建議數據:', improvementData);
+
+ // 檢查 criteria 類型的數據(AI 評語)
+ console.log('💬 檢查 criteria 類型的數據(AI 評語)...');
+ const [criteriaData] = await connection.execute(`
+ SELECT ef.id, ef.evaluation_id, ef.criteria_item_id, ef.content, ci.name as criteria_name
+ FROM evaluation_feedback ef
+ LEFT JOIN criteria_items ci ON ef.criteria_item_id = ci.id
+ WHERE ef.evaluation_id = 2 AND ef.feedback_type = 'criteria'
+ ORDER BY ef.criteria_item_id, ef.sort_order
+ `);
+ console.log('AI 評語數據:', criteriaData);
+
+ } catch (error) {
+ console.error('❌ 錯誤:', error.message);
+ } finally {
+ if (connection) {
+ await connection.end();
+ console.log('🔌 資料庫連接已關閉');
+ }
+ }
+}
+
+checkStrengthImprovement();
diff --git a/test-api.js b/test-api.js
new file mode 100644
index 0000000..666ba87
--- /dev/null
+++ b/test-api.js
@@ -0,0 +1,25 @@
+const fetch = require('node-fetch');
+
+async function testAPI() {
+ try {
+ console.log('🧪 測試 API 端點...');
+
+ // 測試統計API
+ console.log('📊 測試統計API...');
+ const statsResponse = await fetch('http://localhost:3000/api/history/stats');
+ const statsData = await statsResponse.json();
+ console.log('統計數據:', statsData);
+
+ // 測試評審詳細API
+ console.log('📋 測試評審詳細API...');
+ const detailResponse = await fetch('http://localhost:3000/api/evaluation/2');
+ const detailData = await detailResponse.json();
+ console.log('評審詳細數據:', JSON.stringify(detailData, null, 2));
+
+ } catch (error) {
+ console.error('❌ 測試失敗:', error.message);
+ }
+}
+
+// 等待一下讓服務器啟動
+setTimeout(testAPI, 3000);
diff --git a/test-chart-data.js b/test-chart-data.js
new file mode 100644
index 0000000..c5d9ae8
--- /dev/null
+++ b/test-chart-data.js
@@ -0,0 +1,74 @@
+const http = require('http');
+
+function makeRequest(url) {
+ return new Promise((resolve, reject) => {
+ const req = http.get(url, (res) => {
+ let data = '';
+ res.on('data', (chunk) => {
+ data += chunk;
+ });
+ res.on('end', () => {
+ try {
+ const jsonData = JSON.parse(data);
+ resolve(jsonData);
+ } catch (error) {
+ reject(error);
+ }
+ });
+ });
+ req.on('error', reject);
+ });
+}
+
+async function testChartData() {
+ try {
+ console.log('🧪 測試圖表數據生成...');
+
+ // 測試評審詳細API
+ console.log('📋 測試評審詳細API (ID=2)...');
+ const detailData = await makeRequest('http://localhost:3000/api/evaluation/2');
+
+ if (detailData.success) {
+ console.log('✅ API 調用成功');
+ console.log('📊 專案標題:', detailData.data.projectTitle);
+ console.log('📊 總分:', detailData.data.overallScore);
+
+ // 檢查圖表數據
+ console.log('\n📊 圖表數據檢查:');
+
+ console.log('\n📈 各項目得分 (Bar Chart):');
+ detailData.data.chartData.barChart.forEach((item, index) => {
+ console.log(` ${index + 1}. ${item.name}: ${item.score}分`);
+ });
+
+ console.log('\n🥧 權重分布 (Pie Chart):');
+ detailData.data.chartData.pieChart.forEach((item, index) => {
+ console.log(` ${index + 1}. ${item.name}: 權重=${item.weight}%, 加權分數=${item.value}`);
+ });
+
+ console.log('\n🎯 能力雷達圖 (Radar Chart):');
+ detailData.data.chartData.radarChart.forEach((item, index) => {
+ console.log(` ${index + 1}. ${item.subject}: ${item.score}/${item.fullMark}`);
+ });
+
+ // 檢查評分標準詳情
+ console.log('\n📝 評分標準詳情:');
+ detailData.data.criteria.forEach((criteria, index) => {
+ console.log(` ${index + 1}. ${criteria.name}: ${criteria.score}/${criteria.maxScore}`);
+ console.log(` AI 評語: ${criteria.feedback}`);
+ console.log(` 優點: ${criteria.strengths.length > 0 ? criteria.strengths.join(', ') : '無'}`);
+ console.log(` 改進建議: ${criteria.improvements.length > 0 ? criteria.improvements.join(', ') : '無'}`);
+ console.log('');
+ });
+
+ } else {
+ console.log('❌ API 調用失敗:', detailData.error);
+ }
+
+ } catch (error) {
+ console.error('❌ 測試失敗:', error.message);
+ }
+}
+
+// 等待一下讓服務器啟動
+setTimeout(testChartData, 2000);
diff --git a/test-database.js b/test-database.js
new file mode 100644
index 0000000..902755c
--- /dev/null
+++ b/test-database.js
@@ -0,0 +1,40 @@
+const mysql = require('mysql2/promise');
+
+const dbConfig = {
+ host: 'mysql.theaken.com',
+ port: 33306,
+ user: 'root',
+ password: 'zh6161168',
+ database: 'db_AI_scoring'
+};
+
+async function checkData() {
+ let connection;
+ try {
+ console.log('🔗 連接到資料庫...');
+ connection = await mysql.createConnection(dbConfig);
+ console.log('✅ 資料庫連接成功');
+
+ // 檢查評審記錄
+ const [evaluations] = await connection.execute('SELECT id, project_id, overall_score, grade FROM evaluations LIMIT 5');
+ console.log('📊 評審記錄:', evaluations);
+
+ // 檢查專案記錄
+ const [projects] = await connection.execute('SELECT id, title, status FROM projects LIMIT 5');
+ console.log('📋 專案記錄:', projects);
+
+ // 檢查評分記錄
+ const [scores] = await connection.execute('SELECT id, evaluation_id, criteria_item_id, score FROM evaluation_scores LIMIT 5');
+ console.log('🎯 評分記錄:', scores);
+
+ } catch (error) {
+ console.error('❌ 錯誤:', error.message);
+ } finally {
+ if (connection) {
+ await connection.end();
+ console.log('🔌 資料庫連接已關閉');
+ }
+ }
+}
+
+checkData();
diff --git a/test-fixed-api.js b/test-fixed-api.js
new file mode 100644
index 0000000..0898d5d
--- /dev/null
+++ b/test-fixed-api.js
@@ -0,0 +1,66 @@
+const http = require('http');
+
+function makeRequest(url) {
+ return new Promise((resolve, reject) => {
+ const req = http.get(url, (res) => {
+ let data = '';
+ res.on('data', (chunk) => {
+ data += chunk;
+ });
+ res.on('end', () => {
+ try {
+ const jsonData = JSON.parse(data);
+ resolve(jsonData);
+ } catch (error) {
+ reject(error);
+ }
+ });
+ });
+ req.on('error', reject);
+ });
+}
+
+async function testFixedAPI() {
+ try {
+ console.log('🧪 測試修正後的 API...');
+
+ // 測試評審詳細API
+ console.log('📋 測試評審詳細API (ID=2)...');
+ const detailData = await makeRequest('http://localhost:3000/api/evaluation/2');
+
+ if (detailData.success) {
+ console.log('✅ API 調用成功');
+ console.log('📊 專案標題:', detailData.data.projectTitle);
+ console.log('📊 總分:', detailData.data.overallScore);
+ console.log('📊 等級:', detailData.data.grade);
+
+ console.log('\n📝 評分標準詳情:');
+ detailData.data.criteria.forEach((criteria, index) => {
+ console.log(` ${index + 1}. ${criteria.name}: ${criteria.score}/${criteria.maxScore}`);
+ console.log(` AI 評語: ${criteria.feedback}`);
+ console.log(` 優點: ${criteria.strengths.length > 0 ? criteria.strengths.join(', ') : '無'}`);
+ console.log(` 改進建議: ${criteria.improvements.length > 0 ? criteria.improvements.join(', ') : '無'}`);
+ console.log('');
+ });
+
+ console.log('📋 詳細分析:');
+ console.log(' 摘要:', detailData.data.detailedAnalysis.summary);
+ console.log(' 關鍵發現:', detailData.data.detailedAnalysis.keyFindings);
+
+ console.log('\n💡 改進建議:');
+ console.log(' 整體建議:', detailData.data.improvementSuggestions.overallSuggestions);
+ console.log(' 保持優勢:', detailData.data.improvementSuggestions.maintainStrengths);
+ console.log(' 關鍵改進:', detailData.data.improvementSuggestions.keyImprovements);
+ console.log(' 行動計劃:', detailData.data.improvementSuggestions.actionPlan);
+
+ } else {
+ console.log('❌ API 調用失敗:', detailData.error);
+ }
+
+ } catch (error) {
+ console.error('❌ 測試失敗:', error.message);
+ }
+}
+
+// 等待一下讓服務器啟動
+setTimeout(testFixedAPI, 2000);
diff --git a/uploads/projects/24/1758637006045_3d4e2i2yb.pptx b/uploads/projects/24/1758637006045_3d4e2i2yb.pptx
new file mode 100644
index 0000000..8b38ba6
Binary files /dev/null and b/uploads/projects/24/1758637006045_3d4e2i2yb.pptx differ