transceiver-db/scripts/perplexity-research.ts
Rene Fichtmueller c6308e93c0 feat: massive scraper expansion + hype cycle engine + lifecycle prediction
New scrapers:
- GBICS.com (BigCommerce, GBP prices, 10 categories, 78 products)
- Juniper HCT (Next.js SSR parser, 475 transceivers with specs/EOL)
- SFPcables.com (Magento store, 16 categories, 78 products)
- Fluxlight (BigCommerce, 6 pages, 118 products)
- Champion ONE (compatible vendor scraper)

Scraper fixes:
- 10Gtek: rewritten to parse HTML spec tables (152 products)
- Flexoptix: fix price extraction from Magento Hyva HTML
- Register all scrapers in CLI (--gbics, --juniper, --sfpcables, etc.)

Hype Cycle Engine enhancements:
- Data-driven enrichment from scraped vendor/price data
- Revenue lifecycle prediction (peak year, decline, revenue index)
- Regional adoption model (NA, China, APAC, Europe, RoW with lag coefficients)
- New API endpoints: /enriched, /lifecycle, /regional/:tech

DB growth: 89 → 1,168 transceivers, 0 → 416 prices, 6 vendors
Qdrant: 1,162 products embedded with nomic-embed-text

Research: Norton-Bass model, standards-to-market timelines, hype signals
2026-03-28 02:30:19 +13:00

202 lines
7.4 KiB
TypeScript

/**
* Perplexity AI Research Agent for Transceiver Intelligence Platform
*
* Uses Perplexity's Search API to gather real-time market data,
* pricing, specs, and competitive intelligence for optical transceivers.
*
* Usage:
* PERPLEXITY_API_KEY=pplx-xxx tsx scripts/perplexity-research.ts [query]
*
* Examples:
* tsx scripts/perplexity-research.ts "QSFP28 100G LR4 pricing 2026"
* tsx scripts/perplexity-research.ts --mode=competitors
* tsx scripts/perplexity-research.ts --mode=specs --transceiver="SFP28 25G SR"
* tsx scripts/perplexity-research.ts --mode=market-trends
*/
const PERPLEXITY_API_URL = 'https://api.perplexity.ai/chat/completions';
const API_KEY = process.env.PERPLEXITY_API_KEY;
if (!API_KEY) {
console.error('Error: PERPLEXITY_API_KEY environment variable required');
console.error('Get your key at: https://console.perplexity.ai');
process.exit(1);
}
interface PerplexityResponse {
id: string;
choices: Array<{
message: {
role: string;
content: string;
};
finish_reason: string;
}>;
citations?: string[];
}
interface ResearchResult {
query: string;
mode: string;
timestamp: string;
response: string;
citations: string[];
}
async function perplexitySearch(query: string, systemPrompt: string): Promise<PerplexityResponse> {
const response = await fetch(PERPLEXITY_API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'sonar-pro',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: query },
],
search_recency_filter: 'month',
return_citations: true,
}),
});
if (!response.ok) {
throw new Error(`Perplexity API error: ${response.status} ${response.statusText}`);
}
return response.json() as Promise<PerplexityResponse>;
}
const RESEARCH_MODES: Record<string, { systemPrompt: string; queryTemplate: (arg?: string) => string }> = {
'competitors': {
systemPrompt: `You are a market research analyst specializing in optical networking equipment.
Focus on: pricing data, market share, product comparisons, vendor landscape.
Always include specific prices, model numbers, and sources.
Cover these competitor categories: OEM vendors (Cisco, Juniper, Arista, Nokia),
compatible/third-party (Flexoptix, ProLabs, AddOn Networks, Fiberstore/FS.com, 10Gtek),
and Chinese manufacturers (HiLink, Gigalight, Source Photonics).`,
queryTemplate: () => `List the top 60+ optical transceiver vendors worldwide with their:
1. Company name and website
2. Product range (SFP, SFP+, SFP28, QSFP28, QSFP-DD, OSFP)
3. Approximate pricing for popular models
4. Market positioning (OEM, compatible, budget)
5. Any recent news or product launches in 2025-2026`,
},
'specs': {
systemPrompt: `You are an optical networking engineer. Provide detailed technical specifications
for optical transceivers including: form factor, data rate, wavelength, reach, power consumption,
DOM parameters, operating temperature, connector type, fiber type, and MSA compliance.
Always include IEEE/MSA standards references.`,
queryTemplate: (transceiver?: string) => `Provide complete technical specifications for ${transceiver || 'QSFP28 100G LR4'} transceiver:
- All MSA-compliant specifications
- Typical pricing from different vendors
- Compatible equipment list
- Common failure modes and DOM thresholds
- Comparison with similar transceivers in the same category`,
},
'market-trends': {
systemPrompt: `You are a telecommunications industry analyst focusing on optical networking trends.
Cover: technology adoption curves, pricing trends, new standards (800G, 1.6T),
market size and growth, supply chain dynamics, and emerging technologies (silicon photonics, CPO).`,
queryTemplate: () => `What are the current optical transceiver market trends for 2025-2026?
Cover these areas:
1. 800G and 1.6T transceiver development status and pricing
2. Silicon photonics adoption in data centers
3. Co-packaged optics (CPO) timeline
4. Supply chain changes post-2024
5. Market size estimates and growth projections
6. Key M&A activity in the optical transceiver space
7. Impact of AI/ML data center buildout on transceiver demand`,
},
'pricing': {
systemPrompt: `You are a procurement specialist for optical networking equipment.
Provide current market pricing with specific vendor quotes where available.
Include: list price, street price, volume pricing tiers, and compatible vs OEM pricing gaps.`,
queryTemplate: (transceiver?: string) => `Current market pricing for ${transceiver || 'all common optical transceivers'}:
- SFP+ 10G SR/LR
- SFP28 25G SR/LR
- QSFP28 100G SR4/LR4/CWDM4
- QSFP56 200G
- QSFP-DD 400G DR4/FR4
- OSFP 800G
Include prices from: Cisco, Juniper, Arista (OEM) vs Flexoptix, FS.com, ProLabs (compatible)`,
},
'standards': {
systemPrompt: `You are an IEEE/MSA standards expert for optical transceivers.
Cover all relevant standards, their status, and implementation details.`,
queryTemplate: () => `List all current and upcoming optical transceiver standards:
1. IEEE 802.3 standards (ba, bm, bs, ck, cn, cw, db, df)
2. MSA specifications (SFP, SFP+, SFP28, SFP56, QSFP, QSFP28, QSFP-DD, OSFP)
3. OIF implementations
4. New standards in development for 800G and 1.6T
5. Pluggable vs co-packaged optics standardization efforts`,
},
};
async function runResearch(mode: string, customQuery?: string, transceiver?: string): Promise<ResearchResult> {
const config = RESEARCH_MODES[mode];
if (!config && !customQuery) {
console.error(`Unknown mode: ${mode}`);
console.error(`Available modes: ${Object.keys(RESEARCH_MODES).join(', ')}`);
process.exit(1);
}
const query = customQuery || config.queryTemplate(transceiver);
const systemPrompt = config?.systemPrompt ||
'You are a research assistant specializing in optical networking and transceivers. Provide detailed, sourced information.';
console.log(`\n🔍 Perplexity Research: ${mode}`);
console.log(` Query: ${query.substring(0, 100)}...`);
console.log(' Searching...\n');
const result = await perplexitySearch(query, systemPrompt);
const content = result.choices[0]?.message?.content || 'No response';
const citations = result.citations || [];
const researchResult: ResearchResult = {
query,
mode,
timestamp: new Date().toISOString(),
response: content,
citations,
};
// Save to file
const filename = `research-${mode}-${new Date().toISOString().split('T')[0]}.json`;
const outputPath = `storage/research/${filename}`;
const { mkdirSync, writeFileSync } = await import('fs');
mkdirSync('storage/research', { recursive: true });
writeFileSync(outputPath, JSON.stringify(researchResult, null, 2));
console.log(content);
console.log('\n📚 Citations:');
citations.forEach((c, i) => console.log(` [${i + 1}] ${c}`));
console.log(`\n💾 Saved to: ${outputPath}`);
return researchResult;
}
// Parse CLI arguments
const args = process.argv.slice(2);
let mode = 'market-trends';
let customQuery: string | undefined;
let transceiver: string | undefined;
for (const arg of args) {
if (arg.startsWith('--mode=')) {
mode = arg.split('=')[1];
} else if (arg.startsWith('--transceiver=')) {
transceiver = arg.split('=').slice(1).join('=');
} else {
customQuery = arg;
}
}
runResearch(mode, customQuery, transceiver).catch(console.error);