feat: add support for Claude LLM integration across multiple modules
- Introduced `useClaude` option in `AnalysisPipelineOptions` to toggle Claude LLM usage. - Updated `processProductChunk` and `analyzeProducts` functions to accept and handle `useClaude` parameter. - Modified argument parsing in various scripts (`bestsellers-by-category`, `mid-range-sellers-by-category`, `top-monthly-sold-by-category`, etc.) to include `--claude` flag. - Enhanced `analyzeProductsInternal` to differentiate between LLM providers and handle requests to Claude API. - Added error handling for Claude API responses and ensured proper configuration for using Claude. - Updated documentation and usage messages to reflect the new `--claude` flag.
This commit is contained in:
@@ -103,6 +103,7 @@ const DEFAULT_PAGE_SIZE = 25;
|
||||
const MAX_PAGE_SIZE = 200;
|
||||
const ASIN_PATTERN = /^[A-Z0-9]{10}$/;
|
||||
const MAX_UPCS_PER_REQUEST = 1000;
|
||||
const USE_CLAUDE = process.argv.includes("--claude");
|
||||
|
||||
initDb(DB_PATH);
|
||||
const db = getDb(DB_PATH);
|
||||
@@ -128,7 +129,8 @@ function xlsx(buffer: ArrayBuffer, filename: string): Response {
|
||||
return new Response(buffer, {
|
||||
status: 200,
|
||||
headers: {
|
||||
"content-type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"content-type":
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"content-disposition": `attachment; filename="${filename}"`,
|
||||
},
|
||||
});
|
||||
@@ -758,7 +760,10 @@ function parseStalkerSort(sortParam: string | null): string {
|
||||
return parsed
|
||||
.replaceAll("runId", "runId")
|
||||
.replaceAll("rating_count", "rating_count")
|
||||
.replaceAll("persisted_inventory_asin_count", "persisted_inventory_asin_count")
|
||||
.replaceAll(
|
||||
"persisted_inventory_asin_count",
|
||||
"persisted_inventory_asin_count",
|
||||
)
|
||||
.replaceAll("storefront_asin_total", "storefront_asin_total");
|
||||
}
|
||||
|
||||
@@ -955,7 +960,11 @@ function parseStalkerProductSort(sortParam: string | null): string {
|
||||
"confidence",
|
||||
"last_seen_at",
|
||||
]);
|
||||
return parseSort(sortParam, allowedSort, "monthly_sold DESC, last_seen_at DESC, asin ASC");
|
||||
return parseSort(
|
||||
sortParam,
|
||||
allowedSort,
|
||||
"monthly_sold DESC, last_seen_at DESC, asin ASC",
|
||||
);
|
||||
}
|
||||
|
||||
function getStalkerProducts(filters: URLSearchParams) {
|
||||
@@ -1036,7 +1045,9 @@ function getStalkerProducts(filters: URLSearchParams) {
|
||||
};
|
||||
}
|
||||
|
||||
function getStalkerProductsForExport(filters: URLSearchParams): StalkerProductRecord[] {
|
||||
function getStalkerProductsForExport(
|
||||
filters: URLSearchParams,
|
||||
): StalkerProductRecord[] {
|
||||
const { where, params } = parseStalkerProductFilters(filters);
|
||||
const orderBy = parseStalkerProductSort(filters.get("sort"));
|
||||
|
||||
@@ -1100,7 +1111,12 @@ function exportStalkerProductsXlsx(filters: URLSearchParams): Response {
|
||||
Category: parseCategoryTreeForExport(row.category_tree),
|
||||
"Monthly Sold": row.monthly_sold ?? null,
|
||||
Sellers: row.seller_count ?? null,
|
||||
"Amazon Seller": row.amazon_is_seller == null ? "" : row.amazon_is_seller === 1 ? "Yes" : "No",
|
||||
"Amazon Seller":
|
||||
row.amazon_is_seller == null
|
||||
? ""
|
||||
: row.amazon_is_seller === 1
|
||||
? "Yes"
|
||||
: "No",
|
||||
"Sales Rank": row.sales_rank ?? null,
|
||||
"Current Price": row.current_price ?? null,
|
||||
"Avg 90d": row.avg_price_90d ?? null,
|
||||
@@ -1155,11 +1171,31 @@ function exportStalkerProductsXlsx(filters: URLSearchParams): Response {
|
||||
|
||||
function purgeStalkerData() {
|
||||
const counts = {
|
||||
inventory: (db.query("SELECT COUNT(*) AS count FROM stalker_seller_inventory").get() as { count: number }).count,
|
||||
asinSellers: (db.query("SELECT COUNT(*) AS count FROM stalker_asin_sellers").get() as { count: number }).count,
|
||||
sellers: (db.query("SELECT COUNT(*) AS count FROM stalker_sellers").get() as { count: number }).count,
|
||||
scans: (db.query("SELECT COUNT(*) AS count FROM stalker_asin_scans").get() as { count: number }).count,
|
||||
runs: (db.query("SELECT COUNT(*) AS count FROM stalker_runs").get() as { count: number }).count,
|
||||
inventory: (
|
||||
db
|
||||
.query("SELECT COUNT(*) AS count FROM stalker_seller_inventory")
|
||||
.get() as { count: number }
|
||||
).count,
|
||||
asinSellers: (
|
||||
db.query("SELECT COUNT(*) AS count FROM stalker_asin_sellers").get() as {
|
||||
count: number;
|
||||
}
|
||||
).count,
|
||||
sellers: (
|
||||
db.query("SELECT COUNT(*) AS count FROM stalker_sellers").get() as {
|
||||
count: number;
|
||||
}
|
||||
).count,
|
||||
scans: (
|
||||
db.query("SELECT COUNT(*) AS count FROM stalker_asin_scans").get() as {
|
||||
count: number;
|
||||
}
|
||||
).count,
|
||||
runs: (
|
||||
db.query("SELECT COUNT(*) AS count FROM stalker_runs").get() as {
|
||||
count: number;
|
||||
}
|
||||
).count,
|
||||
};
|
||||
|
||||
db.transaction(() => {
|
||||
@@ -1683,7 +1719,9 @@ async function reanalyzeSingleAsin(
|
||||
fetchedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const verdicts = await analyzeProducts([enriched]);
|
||||
const verdicts = await analyzeProducts([enriched], {
|
||||
useClaude: USE_CLAUDE,
|
||||
});
|
||||
const verdict = verdicts[0] ?? {
|
||||
asin,
|
||||
verdict: "SKIP" as const,
|
||||
|
||||
Reference in New Issue
Block a user