This commit is contained in:
96
services/xrayService.ts
Normal file
96
services/xrayService.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
import axios from 'axios';
|
||||
import { geminiService } from './geminiService.js';
|
||||
|
||||
interface XRayResult {
|
||||
success: boolean;
|
||||
data?: {
|
||||
metadata: {
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
tags: string[];
|
||||
};
|
||||
analysis: {
|
||||
visualDna: string[];
|
||||
sentimentGap: string;
|
||||
superiorPrompt: string;
|
||||
gapAnalysis: string;
|
||||
};
|
||||
};
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export const xrayService = {
|
||||
/**
|
||||
* Scrapes a product URL and performs deep AI analysis
|
||||
*/
|
||||
async analyzeProduct(url: string, apiKey?: string): Promise<XRayResult> {
|
||||
try {
|
||||
console.log(`[X-Ray] Analyzing: ${url}`);
|
||||
|
||||
// 1. WEB RESEARCH (Google Search Grounding)
|
||||
// Replaces legacy Axios scraping which gets blocked (403/422) by Etsy
|
||||
const researchResult = await geminiService.performWebResearch(url, apiKey);
|
||||
|
||||
if (!researchResult.title) {
|
||||
throw new Error("AI Retrieval failed to extract product title. The URL may not be accessible or the product page structure is unsupported.");
|
||||
}
|
||||
|
||||
if (!researchResult.image) {
|
||||
throw new Error("AI Retrieval could not find a product image URL. Please ensure the URL points to a valid product page.");
|
||||
}
|
||||
|
||||
console.log("[X-Ray] Metadata extracted via Google:", researchResult.title);
|
||||
|
||||
// 2. Perform AI Analysis (Visual + Text)
|
||||
// We pass the image URL directly if public, OR we might need to download it first base64.
|
||||
// For stability, let's download the image to base64 buffer
|
||||
// Note: Since we have the direct image URL now (likely CDN), downloadImage should work better
|
||||
// than scraping the main page.
|
||||
const imageBuffer = await this.downloadImage(researchResult.image);
|
||||
const imageBase64 = imageBuffer.toString('base64');
|
||||
|
||||
const metadata = {
|
||||
title: researchResult.title,
|
||||
description: researchResult.description,
|
||||
image: researchResult.image,
|
||||
tags: [] // Search might not return tags, optional
|
||||
};
|
||||
|
||||
const analysis = await geminiService.analyzeCompetitorProduct({
|
||||
title: researchResult.title,
|
||||
description: researchResult.description,
|
||||
imageBase64: imageBase64,
|
||||
apiKey
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
metadata,
|
||||
analysis
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("[X-Ray] Error:", error.message);
|
||||
return {
|
||||
success: false,
|
||||
error: error.message || "Failed to analyze product"
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
async downloadImage(url: string): Promise<Buffer> {
|
||||
const response = await axios.get(url, {
|
||||
responseType: 'arraybuffer',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
||||
'Referer': 'https://www.etsy.com/'
|
||||
}
|
||||
});
|
||||
return Buffer.from(response.data, 'binary');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user