feat(market-intel): complete end-to-end audit with enhanced UX and grounding

- Integrated ICP-based lookalike sourcing.
- Implemented Deep Tech Audit with automated evidence collection.
- Enhanced processing terminal with real-time logs.
- Refined daily logging and resolved all dependency issues.
- Documented final status and next steps.
This commit is contained in:
2025-12-21 22:39:30 +00:00
parent 4a765cbf71
commit 0a00146fd6
10 changed files with 511 additions and 141 deletions

View File

@@ -18,10 +18,14 @@ const App: React.FC = () => {
const [language, setLanguage] = useState<Language>('de');
const [referenceUrl, setReferenceUrl] = useState<string>('');
const [targetMarket, setTargetMarket] = useState<string>('');
const [productContext, setProductContext] = useState<string>(''); // Added state for productContext
const [referenceCity, setReferenceCity] = useState<string>(''); // Added state for referenceCity
const [referenceCountry, setReferenceCountry] = useState<string>(''); // Added state for referenceCountry
// Data States
const [strategy, setStrategy] = useState<SearchStrategy | null>(null);
const [competitors, setCompetitors] = useState<Competitor[]>([]);
const [categorizedCompetitors, setCategorizedCompetitors] = useState<{ localCompetitors: Competitor[], nationalCompetitors: Competitor[], internationalCompetitors: Competitor[] } | null>(null); // New state for categorized competitors
const [analysisResults, setAnalysisResults] = useState<AnalysisResult[]>([]);
const [processingState, setProcessingState] = useState<AnalysisState>({
currentCompany: '', progress: 0, total: 0, completed: 0
@@ -39,14 +43,20 @@ const App: React.FC = () => {
}
};
const handleInitialInput = async (url: string, productContext: string, market: string, selectedLang: Language) => {
const handleInitialInput = async (url: string, productCtx: string, market: string, selectedLang: Language) => {
setIsLoading(true);
setLanguage(selectedLang);
setReferenceUrl(url);
setTargetMarket(market);
setProductContext(productCtx); // Store productContext in state
// referenceCity and referenceCountry are not yet extracted from input in StepInput, leaving empty for now.
// Future improvement: extract from referenceUrl or add input fields.
setReferenceCity('');
setReferenceCountry('');
try {
// 1. Generate Strategy first
const generatedStrategy = await generateSearchStrategy(url, productContext, selectedLang);
const generatedStrategy = await generateSearchStrategy(url, productCtx, selectedLang);
setStrategy(generatedStrategy);
setStep(AppStep.STRATEGY);
} catch (error) {
@@ -75,17 +85,22 @@ const App: React.FC = () => {
setIsLoading(true);
try {
// 2. Identify Competitors based on Reference
const results = await identifyCompetitors(referenceUrl, targetMarket, language);
const mappedCompetitors: Competitor[] = results.map(c => ({
id: generateId(),
name: c.name || "Unknown",
url: c.url,
description: c.description
}));
setCompetitors(mappedCompetitors);
const idealCustomerProfile = finalStrategy.idealCustomerProfile; // Use ICP for lookalike search
const identifiedCompetitors = await identifyCompetitors(referenceUrl, targetMarket, productContext, referenceCity, referenceCountry, idealCustomerProfile);
setCategorizedCompetitors(identifiedCompetitors); // Store categorized competitors
// Flatten categorized competitors into a single list for existing StepReview component
const flatCompetitors: Competitor[] = [
...(identifiedCompetitors.localCompetitors || []),
...(identifiedCompetitors.nationalCompetitors || []),
...(identifiedCompetitors.internationalCompetitors || []),
];
setCompetitors(flatCompetitors); // Set the flattened list for StepReview
setStep(AppStep.REVIEW_LIST);
} catch (e) {
alert("Failed to find companies.");
console.error(e);
} finally {
setIsLoading(false);
}
@@ -103,24 +118,52 @@ const App: React.FC = () => {
if (!strategy) return;
setStep(AppStep.ANALYSIS);
setAnalysisResults([]);
setProcessingState({ currentCompany: '', progress: 0, total: competitors.length, completed: 0 });
setProcessingState({ currentCompany: '', progress: 0, total: competitors.length, completed: 0, terminalLogs: ['🚀 Starting Deep Tech Audit session...'] });
const results: AnalysisResult[] = [];
const addLog = (msg: string) => {
setProcessingState(prev => ({
...prev,
terminalLogs: [...(prev.terminalLogs || []), msg]
}));
};
for (let i = 0; i < competitors.length; i++) {
const comp = competitors[i];
setProcessingState(prev => ({ ...prev, currentCompany: comp.name }));
addLog(`> Analyzing ${comp.name} (${i + 1}/${competitors.length})`);
try {
// 3. Analyze using the specific strategy
// Step-by-step logging to make it feel real and informative
addLog(` 🔍 Searching official website for ${comp.name}...`);
// The actual API call happens here. While waiting, the user sees the search log.
const result = await analyzeCompanyWithStrategy(comp.name, strategy, language);
if (result.dataSource === "Error") {
addLog(` ❌ Error: Could not process ${comp.name}.`);
} else {
const websiteStatus = result.dataSource === "Digital Trace Audit" ? "Verified" : (result.dataSource || "Unknown");
const revenue = result.revenue || "N/A";
const employees = result.employees || "N/A";
const status = result.status || "Unknown";
const tier = result.tier || "N/A";
addLog(` ✓ Found website: ${websiteStatus}`);
addLog(` 📊 Estimated: ${revenue} revenue, ${employees} employees.`);
addLog(` 🎯 Status: ${status} | Tier: ${tier}`);
addLog(` ✅ Analysis complete for ${comp.name}.`);
}
results.push(result);
} catch (e) {
console.error(`Failed to analyze ${comp.name}`);
addLog(` ❌ Fatal error analyzing ${comp.name}.`);
}
setProcessingState(prev => ({ ...prev, completed: i + 1 }));
}
addLog(`✨ Audit session finished. Generating final report...`);
setAnalysisResults(results);
setStep(AppStep.REPORT);
}, [competitors, language, strategy]);
@@ -147,6 +190,7 @@ const App: React.FC = () => {
{step === AppStep.REVIEW_LIST && (
<StepReview
competitors={competitors}
categorizedCompetitors={categorizedCompetitors}
onAdd={handleAddCompetitor}
onRemove={handleRemoveCompetitor}
onConfirm={runAnalysis}