import { LeadStatus, AnalysisResult, Competitor, Language, Tier, EmailDraft, SearchStrategy, SearchSignal, OutreachResponse } from "../types"; // URL Konfiguration: // Wir nutzen IMMER den relativen Pfad './api', damit Requests korrekt über den Nginx Proxy (/market/api/...) laufen. // Direkter Zugriff auf Port 3001 ist im Docker-Deployment von außen nicht möglich. const API_BASE_URL = './api'; // Helper to extract JSON (kann ggf. entfernt werden, wenn das Backend immer sauberes JSON liefert) const extractJson = (text: string): any => { try { return JSON.parse(text); } catch (e) { const jsonMatch = text.match(/```json\s*([\s\S]*?)\s*```/); if (jsonMatch && jsonMatch[1]) { try { return JSON.parse(jsonMatch[1]); } catch (e2) {} } const arrayMatch = text.match(/\\[\s\S]*\\s*\]/); if (arrayMatch) { try { return JSON.parse(arrayMatch[0]); } catch (e3) {} } const objectMatch = text.match(/\{\s*[\s\S]*\s*\}/); if (objectMatch) { try { return JSON.parse(objectMatch[0]); } catch (e4) {} } throw new Error("Could not parse JSON response"); } }; /** * NEU: Ruft unser Python-Backend über die Node.js API-Brücke auf. */ export const generateSearchStrategy = async ( referenceUrl: string, contextContent: string, language: Language ): Promise => { // API-Key wird jetzt vom Backend verwaltet try { const response = await fetch(`${API_BASE_URL}/generate-search-strategy`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ referenceUrl, contextContent, language }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(`Backend-Fehler: ${errorData.error || response.statusText}`); } const data = await response.json(); return { productContext: (data.summaryOfOffer || "Market Analysis") + " [Build: " + new Date().toLocaleString() + "]", idealCustomerProfile: data.idealCustomerProfile || "Companies similar to reference", searchStrategyICP: data.searchStrategyICP || "N/A (Not in API response)", digitalSignals: data.digitalSignals || "N/A (Not in API response)", targetPages: data.targetPages || "N/A (Not in API response)", signals: data.signals || [] }; } catch (error) { console.error("Strategy generation failed via API Bridge", error); throw error; } }; // Helper to generate IDs const generateId = () => Math.random().toString(36).substr(2, 9); export const identifyCompetitors = async ( referenceUrl: string, targetMarket: string, contextContent: string, referenceCity?: string, referenceCountry?: string, summaryOfOffer?: string ): Promise<{ localCompetitors: Competitor[], nationalCompetitors: Competitor[], internationalCompetitors: Competitor[] }> => { console.log("Frontend: identifyCompetitors API-Aufruf gestartet."); try { const response = await fetch(`${API_BASE_URL}/identify-competitors`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ referenceUrl, targetMarket, contextContent, referenceCity, referenceCountry, summaryOfOffer }), }); if (!response.ok) { const errorData = await response.json(); console.error(`Frontend: Backend-Fehler bei identifyCompetitors: ${errorData.error || response.statusText}`); throw new Error(`Backend-Fehler: ${errorData.error || response.statusText}`); } const data = await response.json(); console.log("Frontend: identifyCompetitors API-Aufruf erfolgreich. Empfangene Daten:", data); const addIds = (comps: any[]) => (comps || []).map(c => ({ ...c, id: c.id || generateId() })); return { localCompetitors: addIds(data.localCompetitors), nationalCompetitors: addIds(data.nationalCompetitors), internationalCompetitors: addIds(data.internationalCompetitors) }; } catch (error) { console.error("Frontend: Konkurrenten-Identifikation über API Bridge fehlgeschlagen", error); throw error; } }; /** * UPDATED: Dynamic Analysis based on Strategy (muss noch im Python-Backend implementiert werden) */ export const analyzeCompanyWithStrategy = async ( companyName: string, strategy: SearchStrategy, language: Language ): Promise => { console.log(`Frontend: Starte Audit für ${companyName}...`); try { const response = await fetch(`${API_BASE_URL}/analyze-company`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ companyName, strategy, targetMarket: language === 'de' ? 'Germany' : 'USA' // Einfache Ableitung, kann verfeinert werden }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(`Backend-Fehler: ${errorData.error || response.statusText}`); } const result = await response.json(); console.log(`Frontend: Audit für ${companyName} erfolgreich.`); return result as AnalysisResult; } catch (error) { console.error(`Frontend: Audit fehlgeschlagen für ${companyName}`, error); // Fallback-Analyse erstellen, damit die UI nicht abstürzt const fallbackAnalysis: Record = {}; if (strategy && strategy.signals) { strategy.signals.forEach(s => { fallbackAnalysis[s.id] = { value: "N/A (Error)", proof: "Audit failed" }; }); } // Fallback-Objekt bei Fehler, damit der Prozess nicht komplett stoppt return { companyName, status: LeadStatus.UNKNOWN, revenue: "Error", employees: "Error", tier: Tier.TIER_3, dataSource: "Error", dynamicAnalysis: fallbackAnalysis, recommendation: "Fehler bei der Analyse: " + (error as Error).message, processingChecks: { wiki: false, revenue: false, signalsChecked: false } }; } }; export const generateOutreachCampaign = async ( companyData: AnalysisResult, knowledgeBase: string, language: Language, referenceUrl: string, specificRole?: string ): Promise => { console.log(`Frontend: Starte Outreach-Generierung für ${companyData.companyName} (Role: ${specificRole || "All"})...`); try { const response = await fetch(`${API_BASE_URL}/generate-outreach`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ companyData, knowledgeBase, referenceUrl, specific_role: specificRole }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(`Backend-Fehler: ${errorData.error || response.statusText}`); } const result = await response.json(); // Expected: { campaigns: [...], available_roles: [...] } or single object console.log(`Frontend: Outreach-Generierung erfolgreich.`, result); let rawCampaigns: any[] = []; let availableRoles: string[] = []; // Handle Mode A (Batch) vs Mode B (Single) response structures if (result.campaigns && Array.isArray(result.campaigns)) { rawCampaigns = result.campaigns; availableRoles = result.available_roles || []; } else if (result.target_role && result.emails) { // Single campaign response (Mode B) rawCampaigns = [result]; } else if (Array.isArray(result)) { // Legacy fallback rawCampaigns = result; } const processedCampaigns: EmailDraft[] = rawCampaigns.map((item: any) => { let fullBody = ""; const firstSubject = item.emails?.[0]?.subject || "No Subject"; if (item.emails && Array.isArray(item.emails)) { item.emails.forEach((mail: any, idx: number) => { fullBody += `### Email ${idx + 1}: ${mail.subject}\n\n`; fullBody += `${mail.body}\n\n`; if (idx < item.emails.length - 1) fullBody += `\n---\n\n`; }); } else { fullBody = item.body || "No content generated."; } return { persona: item.target_role || "Unknown Role", subject: firstSubject, body: fullBody, keyPoints: item.rationale ? [item.rationale] : [] }; }); return { campaigns: processedCampaigns, available_roles: availableRoles }; } catch (error) { console.error(`Frontend: Outreach-Generierung fehlgeschlagen für ${companyData.companyName}`, error); throw error; } }; export const translateEmailDrafts = async (drafts: EmailDraft[], targetLanguage: Language): Promise => { // Dieser Teil muss noch im Python-Backend oder direkt im Frontend implementiert werden console.warn("translateEmailDrafts ist noch nicht im Python-Backend implementiert."); return drafts; } // --- PROJECT MANAGEMENT (DB) --- export const listProjects = async (): Promise => { const response = await fetch(`${API_BASE_URL}/projects`); if (!response.ok) throw new Error("Failed to list projects"); return await response.json(); }; export const loadProject = async (id: string): Promise => { const response = await fetch(`${API_BASE_URL}/projects/${id}`); if (!response.ok) throw new Error("Failed to load project"); return await response.json(); }; export const deleteProject = async (id: string): Promise => { const response = await fetch(`${API_BASE_URL}/projects/${id}`, { method: 'DELETE' }); if (!response.ok) throw new Error("Failed to delete project"); return await response.json(); }; export const saveProject = async (data: any): Promise => { const response = await fetch(`${API_BASE_URL}/save-project`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (!response.ok) throw new Error("Failed to save project"); return await response.json(); };