新增 AI 解析、評分結果
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useCallback } from "react"
|
||||
import { useState, useCallback, useEffect } from "react"
|
||||
import { Sidebar } from "@/components/sidebar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
@@ -22,6 +22,7 @@ interface UploadedFile {
|
||||
status: "uploading" | "completed" | "error"
|
||||
progress: number
|
||||
url?: string
|
||||
file?: File // 儲存原始文件對象
|
||||
}
|
||||
|
||||
export default function UploadPage() {
|
||||
@@ -30,24 +31,52 @@ export default function UploadPage() {
|
||||
const [projectTitle, setProjectTitle] = useState("")
|
||||
const [projectDescription, setProjectDescription] = useState("")
|
||||
const [isAnalyzing, setIsAnalyzing] = useState(false)
|
||||
const [analysisProgress, setAnalysisProgress] = useState(0)
|
||||
const { toast } = useToast()
|
||||
|
||||
// 動態進度條效果
|
||||
useEffect(() => {
|
||||
let progressInterval: NodeJS.Timeout | null = null
|
||||
|
||||
if (isAnalyzing) {
|
||||
setAnalysisProgress(0)
|
||||
|
||||
progressInterval = setInterval(() => {
|
||||
setAnalysisProgress((prev) => {
|
||||
if (prev >= 90) {
|
||||
// 在90%時停止,等待實際完成
|
||||
return prev
|
||||
}
|
||||
// 模擬不規則的進度增長
|
||||
const increment = Math.random() * 8 + 2 // 2-10之間的隨機增量
|
||||
return Math.min(prev + increment, 90)
|
||||
})
|
||||
}, 500) // 每500ms更新一次
|
||||
} else {
|
||||
setAnalysisProgress(0)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (progressInterval) {
|
||||
clearInterval(progressInterval)
|
||||
}
|
||||
}
|
||||
}, [isAnalyzing])
|
||||
|
||||
const onDrop = useCallback((acceptedFiles: File[]) => {
|
||||
const newFiles: UploadedFile[] = acceptedFiles.map((file) => ({
|
||||
id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
status: "uploading",
|
||||
progress: 0,
|
||||
status: "completed", // 直接標記為完成,因為我們會在評審時處理文件
|
||||
progress: 100,
|
||||
file: file, // 儲存原始文件對象
|
||||
}))
|
||||
|
||||
setFiles((prev) => [...prev, ...newFiles])
|
||||
|
||||
// 模擬上傳進度
|
||||
newFiles.forEach((file) => {
|
||||
simulateUpload(file.id)
|
||||
})
|
||||
|
||||
console.log('📁 文件已準備就緒:', newFiles.map(f => f.name).join(', '))
|
||||
}, [])
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
||||
@@ -61,27 +90,6 @@ export default function UploadPage() {
|
||||
maxSize: 100 * 1024 * 1024, // 100MB
|
||||
})
|
||||
|
||||
const simulateUpload = (fileId: string) => {
|
||||
const interval = setInterval(() => {
|
||||
setFiles((prev) =>
|
||||
prev.map((file) => {
|
||||
if (file.id === fileId) {
|
||||
const newProgress = Math.min(file.progress + Math.random() * 30, 100)
|
||||
const status = newProgress === 100 ? "completed" : "uploading"
|
||||
return { ...file, progress: newProgress, status }
|
||||
}
|
||||
return file
|
||||
}),
|
||||
)
|
||||
}, 500)
|
||||
|
||||
setTimeout(() => {
|
||||
clearInterval(interval)
|
||||
setFiles((prev) =>
|
||||
prev.map((file) => (file.id === fileId ? { ...file, progress: 100, status: "completed" } : file)),
|
||||
)
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
const removeFile = (fileId: string) => {
|
||||
setFiles((prev) => prev.filter((file) => file.id !== fileId))
|
||||
@@ -105,7 +113,7 @@ export default function UploadPage() {
|
||||
return <FileText className="h-8 w-8 text-gray-500" />
|
||||
}
|
||||
|
||||
const startAnalysis = () => {
|
||||
const startAnalysis = async () => {
|
||||
if (files.length === 0 && !websiteUrl.trim()) {
|
||||
toast({
|
||||
title: "請上傳文件或提供網站連結",
|
||||
@@ -126,16 +134,76 @@ export default function UploadPage() {
|
||||
|
||||
setIsAnalyzing(true)
|
||||
|
||||
// 模擬分析過程
|
||||
setTimeout(() => {
|
||||
setIsAnalyzing(false)
|
||||
toast({
|
||||
title: "分析完成",
|
||||
description: "評審結果已生成,請查看結果頁面",
|
||||
try {
|
||||
console.log('🚀 開始 AI 評審流程...')
|
||||
console.log('📝 專案標題:', projectTitle)
|
||||
console.log('📋 專案描述:', projectDescription)
|
||||
console.log('📁 上傳文件數量:', files.length)
|
||||
console.log('🌐 網站連結:', websiteUrl)
|
||||
|
||||
// 準備表單數據
|
||||
const formData = new FormData()
|
||||
formData.append('projectTitle', projectTitle)
|
||||
formData.append('projectDescription', projectDescription)
|
||||
|
||||
if (files.length > 0) {
|
||||
// 只處理第一個文件(可以後續擴展支援多文件)
|
||||
const firstFile = files[0]
|
||||
if (firstFile.file) {
|
||||
formData.append('file', firstFile.file)
|
||||
console.log('📄 處理文件:', firstFile.name, '大小:', firstFile.size)
|
||||
} else {
|
||||
throw new Error('文件對象遺失,請重新上傳')
|
||||
}
|
||||
}
|
||||
|
||||
if (websiteUrl.trim()) {
|
||||
formData.append('websiteUrl', websiteUrl)
|
||||
console.log('🌐 處理網站連結:', websiteUrl)
|
||||
}
|
||||
|
||||
// 發送評審請求
|
||||
console.log('📤 發送評審請求到 API...')
|
||||
const response = await fetch('/api/evaluate', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
// 這裡會導向到結果頁面
|
||||
window.location.href = "/results"
|
||||
}, 5000)
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
if (result.success) {
|
||||
console.log('✅ AI 評審完成!')
|
||||
console.log('📊 評審結果:', result.data)
|
||||
|
||||
// 設置進度為100%
|
||||
setAnalysisProgress(100)
|
||||
|
||||
// 等待一下讓用戶看到100%的進度
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
|
||||
toast({
|
||||
title: "評審完成",
|
||||
description: `總分: ${result.data.evaluation.totalScore}/${result.data.evaluation.maxTotalScore}`,
|
||||
})
|
||||
|
||||
// 儲存結果到 localStorage 以便結果頁面使用
|
||||
localStorage.setItem('evaluationResult', JSON.stringify(result.data))
|
||||
|
||||
// 導向到結果頁面
|
||||
window.location.href = "/results"
|
||||
} else {
|
||||
throw new Error(result.error || '評審失敗')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ AI 評審失敗:', error)
|
||||
toast({
|
||||
title: "評審失敗",
|
||||
description: error instanceof Error ? error.message : "請稍後再試",
|
||||
variant: "destructive",
|
||||
})
|
||||
} finally {
|
||||
setIsAnalyzing(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -332,8 +400,11 @@ export default function UploadPage() {
|
||||
<span>正在分析內容...</span>
|
||||
<span>預計 3-5 分鐘</span>
|
||||
</div>
|
||||
<Progress value={33} className="h-2" />
|
||||
<p className="text-xs text-muted-foreground mt-2">AI 正在深度分析您的內容,請稍候</p>
|
||||
<Progress value={analysisProgress} className="h-2" />
|
||||
<div className="flex items-center justify-between text-xs text-muted-foreground mt-2">
|
||||
<span>AI 正在深度分析您的內容,請稍候</span>
|
||||
<span>{Math.round(analysisProgress)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user