feat: add distributor research functionality with detailed candidate information and outreach options
This commit is contained in:
@@ -2,6 +2,7 @@ import index from "./web/index.html";
|
||||
import * as XLSX from "xlsx";
|
||||
import { normalizeAsin } from "./asin.ts";
|
||||
import { db, client } from "./db/index.ts";
|
||||
import { eq } from "drizzle-orm";
|
||||
import {
|
||||
analysisRevisions,
|
||||
productDistributorResearch,
|
||||
@@ -639,8 +640,8 @@ function normalizeDistributorCandidates(payload: unknown): DistributorCandidate[
|
||||
rationale: String(item.rationale ?? "").trim(),
|
||||
confidence: clampDistributorConfidence(item.confidence),
|
||||
reputation: String(item.reputation ?? "").trim(),
|
||||
contactInfo: String(item.contact_info ?? "").trim(),
|
||||
outreachDraft: String(item.outreach_draft ?? "").trim(),
|
||||
contactInfo: String(item.contact_info ?? item.contactInfo ?? "").trim(),
|
||||
outreachDraft: String(item.outreach_draft ?? item.outreachDraft ?? "").trim(),
|
||||
}))
|
||||
.filter((item) => item.name.length > 0 && item.website.length > 0)
|
||||
.slice(0, 10);
|
||||
@@ -674,8 +675,8 @@ async function requestClaudeDistributorCandidates(context: Record<string, unknow
|
||||
"For each distributor:",
|
||||
"1. Identify whether they are an official brand distributor, authorized reseller, or national wholesaler.",
|
||||
"2. Investigate their reputation: check for BBB accreditation, industry tenure, any known complaints or red flags, and whether they appear on the brand's own authorized-distributor list.",
|
||||
"3. Find the most direct point-of-contact for new wholesale accounts — ideally a named buyer, vendor relations team, or wholesale inquiry email/phone from their website (not a generic contact form).",
|
||||
"4. Draft a short, professional cold-outreach message (3–5 sentences) I can send to open a wholesale account inquiry. The message should: mention the specific product or brand, state that I sell on Amazon as an FBA seller, ask about minimum order quantities and wholesale pricing, and invite them to share an application or terms sheet.",
|
||||
"3. Find the most direct point-of-contact for opening a new wholesale account. Search the distributor's website for a dedicated wholesale, reseller, or new-account page. Return AS MANY of these as you can find: full name and title of the wholesale/vendor relations contact, direct email address (e.g. wholesale@..., newaccounts@..., sales@...), direct phone number, and the URL of the wholesale application or inquiry page. If a named contact is not publicly listed, return the best department email and phone. Do NOT return a generic contact form URL as the only answer.",
|
||||
"4. Draft a short, professional cold-outreach message (3–5 sentences) I can copy-paste and send. Tone: warm, genuine, and business-oriented — the goal is to start a relationship, not close a deal. Rules: (a) Praise the brand's reputation, quality, or market position sincerely — make it specific to what this brand is known for. (b) Frame the inquiry as a mutual growth opportunity; express eagerness to carry their line and help it reach more customers. (c) Do NOT mention Amazon, FBA, or online marketplaces anywhere in the message — present yourself simply as a retailer / reseller interested in carrying their products. (d) Ask about wholesale account requirements and invite them to share terms or an application. (e) Keep it concise and human — avoid corporate filler phrases.",
|
||||
"",
|
||||
"Return a raw JSON array. Each object must have exactly these keys:",
|
||||
' "name" — distributor company name',
|
||||
@@ -683,8 +684,8 @@ async function requestClaudeDistributorCandidates(context: Record<string, unknow
|
||||
' "rationale" — why this distributor is a strong candidate (1–2 sentences)',
|
||||
' "confidence" — integer 0–100 reflecting how confident you are this is a real authorized source',
|
||||
' "reputation" — summary of reputation findings (BBB status, years in business, any red flags)',
|
||||
' "contact_info" — best point-of-contact found (name/title, email or phone, or wholesale inquiry URL)',
|
||||
' "outreach_draft"— ready-to-send outreach message addressed to the contact above',
|
||||
' "contact_info" — structured string with all contact details found: "Name: ..., Title: ..., Email: ..., Phone: ..., Wholesale page: ..."',
|
||||
' "outreach_draft"— complete ready-to-send message addressed to the specific contact',
|
||||
"",
|
||||
"Product context:",
|
||||
JSON.stringify(context, null, 2),
|
||||
@@ -800,6 +801,9 @@ async function findDistributorsForStalkerProduct(runItemId: number) {
|
||||
})),
|
||||
};
|
||||
const claude = await requestClaudeDistributorCandidates(promptContext);
|
||||
await db
|
||||
.delete(productDistributorResearch)
|
||||
.where(eq(productDistributorResearch.runItemId, runItemId));
|
||||
const [saved] = await db
|
||||
.insert(productDistributorResearch)
|
||||
.values({
|
||||
|
||||
Reference in New Issue
Block a user