diff --git a/.gitignore b/.gitignore index 3ef0b03..70878cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules .env -*/*.db \ No newline at end of file +*/*.db +data/ebay_items.db diff --git a/ai.js b/ai.js index cb4f6df..40a6629 100644 --- a/ai.js +++ b/ai.js @@ -8,37 +8,93 @@ const openai = new OpenAI({ async function getAiSuggestion(item) { try { + const imageUrl = item.detail_response.image ? item.detail_response.image.imageUrl : null; + const prompt = ` -Bạn là một chuyên gia thẩm định hàng hoá điện tử trên eBay. -Hãy kiểm tra các thông tin dưới đây để trả lời 3 câu hỏi: -1. Item có bị ảo / lừa đảo (fake) không? -2. Seller có uy tín không? (so sánh feedback score, percent) -3. Dữ liệu hiện tại đã đúng sản phẩm chưa? (Part Number, Specs) +ROLE: +Bạn là chuyên gia kiểm định listing eBay dựa trên dữ liệu + hình ảnh sản phẩm. -THÔNG TIN TÌM KIẾM: -- Part Number: ${item.partNumber} -- Specs mục tiêu: ${item.specs} +MỤC TIÊU: +Đánh giá độ tin cậy của listing dựa trên: +- Độ khớp giữa HÌNH ẢNH và THÔNG TIN +- Độ uy tín của seller +- Độ hợp lý tổng thể (price / data consistency) -THÔNG TIN EBAY (Tìm được): -- Tiêu đề: ${item.title} -- Seller: ${item.seller_username} (Score: ${item.seller_feedback_score}, Positive: ${item.seller_feedback_percent}%) +INPUT: + +[SEARCH TARGET] +- Part Number: ${item.partNumber || "N/A"} +- Expected Specs: ${item.specs || "N/A"} + +[EBAY DATA] +- Title: ${item.title} - Price: ${item.price} -- Phân tích JSON chi tiết từ API: -${item.detail_response ? JSON.stringify(item.detail_response).substring(0, 1500) : 'Không có dữ liệu chi tiết'} +- Seller: ${item.detail_response?.seller?.username} +- Feedback Score: ${item.detail_response?.seller?.feedbackScore} +- Positive %: ${item.detail_response?.seller?.feedbackPercent} -YÊU CẦU ĐẦU RA (Quan trọng!): -Chỉ đưa ra kết luận DUY NHẤT 1 câu ngắn gọn. (Ví dụ: "Hãy mua ngay, seller uy tín và đúng chuẩn sản phẩm." HOẶC "Cẩn thận, seller ít feedback và tiêu đề không rõ ràng.") -Khong giải thích dài dòng! +[DETAIL DATA] +- Brand: ${item.detail_response?.brand || "N/A"} +- Aspects: ${JSON.stringify(item.detail_response?.localizedAspects || {})} + +TASK (QUAN TRỌNG): +Thực hiện các bước sau (ngầm, không output): +1. Nếu có ảnh: + - OCR label / text chính (model, part number, specs) + - So sánh với Title + Aspects +2. Check mismatch: + - Sai model / sai part number / sai specs + - Ảnh không liên quan (stock image / generic) +3. Đánh giá seller: + - Feedback < 95% hoặc score thấp => rủi ro +4. Đánh giá tổng thể: + - Consistency + seller + price + +OUTPUT RULE (BẮT BUỘC): +- Chỉ 1 câu duy nhất kèm số điểm đánh giá từ 1-10 với độ khớp +- Không markdown, không xuống dòng +- Không giải thích dài +- Format: + +Nếu tốt: +"Hãy mua, dữ liệu và hình ảnh khớp, seller uy tín. (Điểm: {{điểm}})" + +Nếu có rủi ro: +"Cẩn thận, {{lý do chính ngắn gọn}}. (Điểm: {{điểm}})" + +Nếu rất tệ: +"Không nên mua, {{lý do rõ ràng}}. (Điểm: {{điểm}})" + +Ví dụ lý do: +- label không khớp title +- sai part number +- ảnh generic / không phải sản phẩm thật +- seller feedback thấp + +OUTPUT: `; + console.log(prompt); + const messages = [ + { role: "system", content: "Bạn là trợ lý AI chuyên thẩm định eBay bằng hình ảnh và dữ liệu. Chỉ trả về 1 câu kết luận ngắn gọn." } + ]; + + if (imageUrl) { + messages.push({ + role: "user", + content: [ + { type: "text", text: prompt }, + { type: "image_url", image_url: { url: imageUrl, detail: "high" } } + ] + }); + } else { + messages.push({ role: "user", content: prompt }); + } const response = await openai.chat.completions.create({ model: "gpt-4o-mini", - messages: [ - { role: "system", content: "Bạn là trợ lý AI chuyên thẩm định eBay. Chỉ trả về 1 câu ngắn gọn." }, - { role: "user", content: prompt } - ], - max_tokens: 100, - temperature: 0.3 + messages: messages, + max_tokens: 150, + temperature: 0.2 }); return { diff --git a/public/index.html b/public/index.html index 3f756b1..45e46a5 100644 --- a/public/index.html +++ b/public/index.html @@ -140,6 +140,37 @@ } .modal-padd { padding: 2.5rem; } + .thumb-img { + width: 60px; height: 60px; object-fit: cover; + border-radius: 6px; cursor: pointer; border: 2px solid transparent; + transition: all 0.2s; + } + .thumb-img:hover { border-color: var(--primary); transform: translateY(-2px); } + .thumb-img.active { border-color: var(--primary); } + + #detail-main-img { + max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in; + } + + .row-highlight { + background: rgba(34, 197, 94, 0.1) !important; + border-left: 4px solid var(--success) !important; + } + .toolbar-group { + display: flex; gap: 0.5rem; align-items: center; + background: var(--surface); border: 1px solid var(--border); + padding: 0.3rem 0.6rem; border-radius: 8px; + } + .toolbar-group label { margin-bottom: 0; font-size: 0.75rem; white-space: nowrap; color: var(--text-muted); } + .toolbar-group input { border: none; width: 60px; padding: 0.2rem; background: transparent; color: var(--text); outline: none; } + + .badge-offer { + background: #f97316; /* Orange */ + color: white; padding: 0.1rem 0.4rem; border-radius: 4px; + font-size: 0.7rem; font-weight: 700; margin-left: 0.5rem; + display: inline-block; vertical-align: middle; line-height: 1; + } + form div { margin-bottom: 1rem; } label { display: block; margin-bottom: 0.4rem; font-size: 0.9rem; color: var(--text-muted); } input[type="text"], input[type="number"], textarea { @@ -185,6 +216,23 @@ height: 100%; background: var(--primary); width: 0%; transition: width 0.3s; box-shadow: 0 0 10px var(--primary-glow); } + + /* Bulk Bar */ + .bulk-bar { + position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); + background: var(--primary); color: white; padding: 0.8rem 2rem; + border-radius: 50px; display: flex; align-items: center; gap: 1.5rem; + box-shadow: 0 10px 30px rgba(0,0,0,0.5); z-index: 1001; + opacity: 0; pointer-events: none; transition: all 0.3s; + } + .bulk-bar.active { opacity: 1; pointer-events: all; bottom: 40px; } + .bulk-bar button { + background: rgba(255,255,255,0.15); color: white; + border: 1px solid rgba(255,255,255,0.3); padding: 0.5rem 1.2rem; + } + .bulk-bar button:hover { background: rgba(255,255,255,0.25); } + + .item-checkbox { width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary); } @@ -220,6 +268,14 @@
+
+ + +
+
+ + +
@@ -227,6 +283,7 @@ + @@ -333,13 +390,23 @@ + +
+ +
+ + + +
+
+
Img Product Info Market Price