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 @@
+ |
Img |
Product Info |
Market Price |
@@ -333,13 +390,23 @@
+
+
+
+
+
+
+
+
+
+