ebayDeepScan/ai.js

145 lines
4.2 KiB
JavaScript

require('dotenv').config();
const { OpenAI } = require('openai');
const db = require('./db');
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
async function getAiSuggestion(item) {
try {
const imageUrl = item.detail_response.image ? item.detail_response.image.imageUrl : null;
const prompt = `
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.
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)
INPUT:
[SEARCH TARGET]
- Part Number: ${item.partNumber || "N/A"}
- Expected Specs: ${item.specs || "N/A"}
[EBAY DATA]
- Title: ${item.title}
- Price: ${item.price}
- Seller: ${item.detail_response?.seller?.username}
- Feedback Score: ${item.detail_response?.seller?.feedbackScore}
- Positive %: ${item.detail_response?.seller?.feedbackPercent}
[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: messages,
max_tokens: 150,
temperature: 0.2
});
return {
suggestion: response.choices[0].message.content.trim(),
usage: response.usage.total_tokens
};
} catch (error) {
console.error(`AI Error for item ${item.id}:`, error.message);
return { suggestion: "Lỗi khi gọi AI.", usage: 0 };
}
}
async function runAiSuggestions() {
console.log("Bat dau chay AI Suggestions...");
const items = db.getMissingAiSuggestionItems();
console.log(`Tim thay ${items.length} item can check AI.`);
let totalTokens = 0;
const batchSize = 10;
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const results = await Promise.all(batch.map(async item => {
console.log(`Dang check AI cho item: ${item.id}`);
const { suggestion, usage } = await getAiSuggestion(item);
db.updateAiSuggestion(item.id, suggestion);
console.log(`Ket qua AI cho ${item.id}: ${suggestion} (Tokens: ${usage})`);
return usage;
}));
totalTokens += results.reduce((a, b) => a + b, 0);
// Minimal delay between batches to respect rate limits
if (i + batchSize < items.length) {
await new Promise(r => setTimeout(r, 500));
}
}
console.log(`Hoan thanh AI Suggestions. Total tokens: ${totalTokens}`);
return totalTokens;
}
module.exports = {
runAiSuggestions,
getAiSuggestion
};
// Allow standalone run
if (require.main === module) {
runAiSuggestions().catch(console.error);
}