docs: update migration guide with gemini versioning and model availability insights (v2.4)
This commit is contained in:
@@ -8,11 +8,9 @@ import { AlertTriangle, ArrowRight, ArrowLeft, Check, Database, Globe, Search, S
|
||||
|
||||
const TRANSLATIONS = {
|
||||
en: {
|
||||
// ... existing ...
|
||||
historyTitle: 'Recent Sessions',
|
||||
loadBtn: 'Load',
|
||||
noSessions: 'No history found.',
|
||||
// ... existing ...
|
||||
phase1: 'Product & Constraints',
|
||||
phase2: 'ICP Discovery',
|
||||
phase3: 'Whale Hunting',
|
||||
@@ -27,7 +25,7 @@ const TRANSLATIONS = {
|
||||
inputPlaceholder: 'Paste raw technical data, brochure text, or product URL here...',
|
||||
startBtn: 'Start Analysis',
|
||||
backBtn: 'Back',
|
||||
processing: 'Processing...',
|
||||
processing: 'Processing...',
|
||||
features: 'Detected Features',
|
||||
constraints: 'Hard Constraints',
|
||||
conflictTitle: 'Portfolio Conflict Detected',
|
||||
@@ -55,7 +53,7 @@ const TRANSLATIONS = {
|
||||
downloadAsset: 'Download Asset',
|
||||
translateBtn: 'Translate Report to English',
|
||||
downloadEn: 'Download English Report (.md)',
|
||||
translating: 'Translating...',
|
||||
translating: 'Translating...',
|
||||
toPhase6: 'Proceed to Sales Enablement (Phase 6)',
|
||||
toPhase7: 'Proceed to Landing Pages (Phase 7)',
|
||||
toPhase8: 'Proceed to Business Case (Phase 8)',
|
||||
@@ -74,19 +72,18 @@ const TRANSLATIONS = {
|
||||
editImage: 'Edit & Iterate',
|
||||
regenerateSketch: 'Regenerate with Sketch',
|
||||
cancelEdit: 'Cancel Edit',
|
||||
generating: 'Generating...',
|
||||
generating: 'Generating...',
|
||||
uploadImage: 'Product Reference Images',
|
||||
uploadHint: 'Upload multiple photos (Front, Side, Detail) for better 3D understanding.',
|
||||
imageUploaded: 'Reference Images',
|
||||
canvasClear: 'Clear',
|
||||
canvasMode: 'Sketch Mode',
|
||||
// New placeholders
|
||||
addName: 'Name...',
|
||||
addName: 'Name...',
|
||||
addRationale: 'Rationale...',
|
||||
addTarget: 'Target criteria...',
|
||||
addMethod: 'Method...',
|
||||
addAccount: 'Account name...',
|
||||
addRole: 'Job title...',
|
||||
addRole: 'Job title...',
|
||||
loading: [
|
||||
"Initializing quantum analysis engines...",
|
||||
"Parsing raw technical specifications...",
|
||||
@@ -111,10 +108,10 @@ const TRANSLATIONS = {
|
||||
phase9: 'Feature-to-Value Translator',
|
||||
initTitle: 'Neue Produktsequenz initialisieren',
|
||||
inputLabel: 'Produkt-URL oder Technische Spezifikation',
|
||||
inputPlaceholder: 'Füge hier rohe technische Daten, Broschürentexte oder Produkt-URL ein...',
|
||||
inputPlaceholder: 'Füge hier rohe technische Daten, Broschürentexte oder Produkt-URL ein...',
|
||||
startBtn: 'Analyse starten',
|
||||
backBtn: 'Zurück',
|
||||
processing: 'Verarbeite...',
|
||||
processing: 'Verarbeite...',
|
||||
features: 'Erkannte Features',
|
||||
constraints: 'Harte Constraints',
|
||||
conflictTitle: 'Portfolio-Konflikt erkannt',
|
||||
@@ -137,12 +134,12 @@ const TRANSLATIONS = {
|
||||
genAssets: 'Generierter Strategie-Report & Assets',
|
||||
complete: 'Prozess abgeschlossen. Strategie fixiert.',
|
||||
restart: 'Neue Session starten',
|
||||
addPlaceholder: 'Punkt hinzufügen...',
|
||||
addPlaceholder: 'Punkt hinzufügen...',
|
||||
download: 'Gesamtbericht herunterladen (.md)',
|
||||
downloadAsset: 'Bild speichern',
|
||||
translateBtn: 'Bericht ins Englische übersetzen',
|
||||
downloadEn: 'Englischen Bericht herunterladen (.md)',
|
||||
translating: 'Übersetze...',
|
||||
translating: 'Übersetze...',
|
||||
toPhase6: 'Weiter zu Sales Enablement (Phase 6)',
|
||||
toPhase7: 'Weiter zu Landing Pages (Phase 7)',
|
||||
toPhase8: 'Weiter zu Business Case (Phase 8)',
|
||||
@@ -161,19 +158,18 @@ const TRANSLATIONS = {
|
||||
editImage: 'Zeichnen & Iterieren',
|
||||
regenerateSketch: 'Mit Skizze neu generieren',
|
||||
cancelEdit: 'Abbrechen',
|
||||
generating: 'Generiere...',
|
||||
generating: 'Generiere...',
|
||||
uploadImage: 'Produkt-Referenzbilder',
|
||||
uploadHint: 'Lade mehrere Fotos hoch (Front, Seite, Detail), um das 3D-Verständnis zu verbessern.',
|
||||
imageUploaded: 'Referenzbilder',
|
||||
canvasClear: 'Leeren',
|
||||
canvasMode: 'Zeichenmodus',
|
||||
// New placeholders
|
||||
addName: 'Name...',
|
||||
addRationale: 'Begründung...',
|
||||
addTarget: 'Zielkriterium...',
|
||||
addMethod: 'Suchmethode...',
|
||||
addAccount: 'Firmenname...',
|
||||
addRole: 'Jobtitel...',
|
||||
addName: 'Name...',
|
||||
addRationale: 'Begründung...',
|
||||
addTarget: 'Zielkriterium...',
|
||||
addMethod: 'Suchmethode...',
|
||||
addAccount: 'Firmenname...',
|
||||
addRole: 'Jobtitel...',
|
||||
loading: [
|
||||
"Initialisiere Quanten-Analyse-Engines...",
|
||||
"Analysiere technische Spezifikationen...",
|
||||
@@ -191,7 +187,7 @@ const App: React.FC = () => {
|
||||
isLoading: false,
|
||||
history: [],
|
||||
productInput: '',
|
||||
productImages: [], // Now an array
|
||||
productImages: [],
|
||||
language: 'light', // temporary init, fix in useEffect
|
||||
theme: 'light' // Default to light
|
||||
});
|
||||
@@ -328,21 +324,64 @@ const App: React.FC = () => {
|
||||
const data = await Gemini.loadSession(projectId);
|
||||
const phases = data.phases || {};
|
||||
|
||||
console.log("Raw Loaded Phases from DB:", phases);
|
||||
|
||||
// Helper to safely parse potentially MULTIPLE times stringified JSON
|
||||
const parsePhaseData = (phaseData: any) => {
|
||||
if (!phaseData) return undefined;
|
||||
let parsed = phaseData;
|
||||
try {
|
||||
// Versuch 1
|
||||
if (typeof parsed === 'string') parsed = JSON.parse(parsed);
|
||||
// Versuch 2 (falls double encoded)
|
||||
if (typeof parsed === 'string') parsed = JSON.parse(parsed);
|
||||
// Versuch 3 (extrem)
|
||||
if (typeof parsed === 'string') parsed = JSON.parse(parsed);
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse phase data", e, phaseData);
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
};
|
||||
|
||||
const p1 = parsePhaseData(phases.phase1_result);
|
||||
const p2 = parsePhaseData(phases.phase2_result);
|
||||
const p3 = parsePhaseData(phases.phase3_result);
|
||||
const p4 = parsePhaseData(phases.phase4_result);
|
||||
const p5 = parsePhaseData(phases.phase5_result);
|
||||
const p6 = parsePhaseData(phases.phase6_result);
|
||||
const p7 = parsePhaseData(phases.phase7_result);
|
||||
const p8 = parsePhaseData(phases.phase8_result);
|
||||
const p9 = parsePhaseData(phases.phase9_result);
|
||||
|
||||
console.log("Parsed Phase 2:", p2); // Debug
|
||||
|
||||
// Determine the highest available phase to jump to
|
||||
let targetPhase = Phase.ProductAnalysis;
|
||||
if (p9) targetPhase = Phase.TechTranslator;
|
||||
else if (p8) targetPhase = Phase.BusinessCase;
|
||||
else if (p7) targetPhase = Phase.LandingPage;
|
||||
else if (p6) targetPhase = Phase.SalesEnablement;
|
||||
else if (p5) targetPhase = Phase.AssetGeneration;
|
||||
else if (p4) targetPhase = Phase.Strategy;
|
||||
else if (p3) targetPhase = Phase.WhaleHunting;
|
||||
else if (p2) targetPhase = Phase.ICPDiscovery;
|
||||
|
||||
setState(s => ({
|
||||
...s,
|
||||
isLoading: false,
|
||||
currentPhase: Phase.ProductAnalysis,
|
||||
currentPhase: targetPhase,
|
||||
projectId: projectId,
|
||||
productInput: phases.phase1_result?.rawAnalysis || "",
|
||||
phase1Result: phases.phase1_result,
|
||||
phase2Result: phases.phase2_result,
|
||||
phase3Result: phases.phase3_result,
|
||||
phase4Result: phases.phase4_result,
|
||||
phase5Result: phases.phase5_result,
|
||||
phase6Result: phases.phase6_result,
|
||||
phase7Result: phases.phase7_result,
|
||||
phase8Result: phases.phase8_result,
|
||||
phase9Result: phases.phase9_result,
|
||||
productInput: p1?.rawAnalysis || "",
|
||||
phase1Result: p1,
|
||||
phase2Result: p2,
|
||||
phase3Result: p3,
|
||||
phase4Result: p4,
|
||||
phase5Result: p5,
|
||||
phase6Result: p6,
|
||||
phase7Result: p7,
|
||||
phase8Result: p8,
|
||||
phase9Result: p9,
|
||||
}));
|
||||
} catch (e: any) {
|
||||
setError("Failed to load session: " + e.message);
|
||||
@@ -380,6 +419,8 @@ const App: React.FC = () => {
|
||||
reader.readAsText(file);
|
||||
};
|
||||
|
||||
// --- Asset Generation Helpers ---
|
||||
|
||||
const generateFullReportMarkdown = (): string => {
|
||||
if (!state.phase5Result || !state.phase5Result.report) return "";
|
||||
|
||||
@@ -397,7 +438,11 @@ const App: React.FC = () => {
|
||||
state.phase6Result.visualPrompts.forEach(prompt => {
|
||||
fullReport += `### ${prompt.title}\n`;
|
||||
fullReport += `*Context: ${prompt.context}*\n\n`;
|
||||
fullReport += `\`\`\`\n${prompt.prompt}\n\`\`\`\n\n`;
|
||||
fullReport += `\
|
||||
\
|
||||
${prompt.prompt}\n\
|
||||
\
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -467,7 +512,7 @@ const App: React.FC = () => {
|
||||
const element = document.createElement("a");
|
||||
element.href = dataUrl;
|
||||
element.download = `roboplanet-visual-${index + 1}.png`;
|
||||
document.body.appendChild(element);
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
};
|
||||
@@ -480,251 +525,170 @@ const App: React.FC = () => {
|
||||
|
||||
// --- Image Generation Handlers ---
|
||||
|
||||
const handleGenerateImage = async (prompt: string, index: number, overrideReference?: string) => {
|
||||
setGeneratingImages(prev => ({ ...prev, [index]: true }));
|
||||
try {
|
||||
// If sketching, use only the sketch as the strong reference
|
||||
// If not sketching, use the array of uploaded product images
|
||||
const refImages = overrideReference ? [overrideReference] : state.productImages;
|
||||
|
||||
const imageUrl = await Gemini.generateConceptImage(prompt, refImages);
|
||||
setGeneratedImages(prev => ({ ...prev, [index]: imageUrl }));
|
||||
|
||||
// If we were editing, close edit mode
|
||||
if (editingIndex === index) {
|
||||
setEditingIndex(null);
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error("Failed to generate image", e);
|
||||
setError("Image generation failed: " + e.message);
|
||||
} finally {
|
||||
setGeneratingImages(prev => ({ ...prev, [index]: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = event.target.files;
|
||||
if (files && files.length > 0) {
|
||||
Array.from(files).forEach((file: File) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
if (reader.result) {
|
||||
setState(s => ({ ...s, productImages: [...s.productImages, reader.result as string] }));
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const removeUploadedImage = (index: number) => {
|
||||
setState(s => ({
|
||||
...s,
|
||||
productImages: s.productImages.filter((_, i) => i !== index)
|
||||
}));
|
||||
};
|
||||
|
||||
// --- Drawing / Editing Handlers ---
|
||||
|
||||
const startDrawing = (e: React.MouseEvent<HTMLCanvasElement> | React.TouchEvent<HTMLCanvasElement>) => {
|
||||
setIsDrawing(true);
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const scaleX = canvas.width / rect.width;
|
||||
const scaleY = canvas.height / rect.height;
|
||||
const x = (('touches' in e ? e.touches[0].clientX : e.clientX) - rect.left) * scaleX;
|
||||
const y = (('touches' in e ? e.touches[0].clientY : e.clientY) - rect.top) * scaleY;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
};
|
||||
|
||||
const draw = (e: React.MouseEvent<HTMLCanvasElement> | React.TouchEvent<HTMLCanvasElement>) => {
|
||||
if (!isDrawing) return;
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const scaleX = canvas.width / rect.width;
|
||||
const scaleY = canvas.height / rect.height;
|
||||
const x = (('touches' in e ? e.touches[0].clientX : e.clientX) - rect.left) * scaleX;
|
||||
const y = (('touches' in e ? e.touches[0].clientY : e.clientY) - rect.top) * scaleY;
|
||||
|
||||
ctx.lineTo(x, y);
|
||||
ctx.strokeStyle = brushColor;
|
||||
ctx.lineWidth = brushSize;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
const stopDrawing = () => {
|
||||
setIsDrawing(false);
|
||||
};
|
||||
|
||||
const clearCanvas = () => {
|
||||
const canvas = canvasRef.current;
|
||||
if (canvas && editingIndex !== null) {
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
ctx.clearRect(0,0, canvas.width, canvas.height);
|
||||
ctx.drawImage(img, 0, 0);
|
||||
}
|
||||
img.src = generatedImages[editingIndex];
|
||||
const handleGenerateImage = async (prompt: string, index: number, overrideReference?: string) => {
|
||||
setGeneratingImages(prev => ({ ...prev, [index]: true }));
|
||||
try {
|
||||
// If sketching, use only the sketch as the strong reference
|
||||
// If not sketching, use the array of uploaded product images
|
||||
const refImages = overrideReference ? [overrideReference] : state.productImages;
|
||||
|
||||
const imageUrl = await Gemini.generateConceptImage(prompt, refImages, state.projectId);
|
||||
setGeneratedImages(prev => ({ ...prev, [index]: imageUrl }));
|
||||
|
||||
// If we were editing, close edit mode
|
||||
if (editingIndex === index) {
|
||||
setEditingIndex(null);
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error("Failed to generate image", e);
|
||||
setError("Image generation failed: " + e.message);
|
||||
} finally {
|
||||
setGeneratingImages(prev => ({ ...prev, [index]: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleRegenerateWithSketch = (index: number, prompt: string) => {
|
||||
const canvas = canvasRef.current;
|
||||
if (canvas) {
|
||||
const sketchData = canvas.toDataURL('image/png');
|
||||
handleGenerateImage(prompt, index, sketchData);
|
||||
};
|
||||
|
||||
// ... (Upload handlers remain same) ...
|
||||
|
||||
// --- Handlers ---
|
||||
|
||||
const handlePhase1Submit = async () => {
|
||||
if (!state.productInput.trim()) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
setError(null);
|
||||
try {
|
||||
const result = await Gemini.analyzeProduct(state.productInput, language);
|
||||
setState(s => ({ ...s, currentPhase: Phase.ProductAnalysis, phase1Result: result, isLoading: false, projectId: result.projectId }));
|
||||
} catch (e: any) {
|
||||
setError(e.message || "Analysis failed");
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
// --- Handlers ---
|
||||
|
||||
const handlePhase1Submit = async () => {
|
||||
if (!state.productInput.trim()) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
setError(null);
|
||||
try {
|
||||
const result = await Gemini.analyzeProduct(state.productInput, language);
|
||||
setState(s => ({ ...s, currentPhase: Phase.ProductAnalysis, phase1Result: result, isLoading: false, projectId: result.projectId })); // Save projectId!
|
||||
} catch (e: any) {
|
||||
setError(e.message || "Analysis failed");
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase2Submit = async () => {
|
||||
if (!state.phase1Result) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.discoverICPs(state.phase1Result, language);
|
||||
setState(s => ({ ...s, currentPhase: Phase.ICPDiscovery, phase2Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase3Submit = async () => {
|
||||
if (!state.phase2Result) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.huntWhales(state.phase2Result, language);
|
||||
setState(s => ({ ...s, currentPhase: Phase.WhaleHunting, phase3Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase4Submit = async () => {
|
||||
if (!state.phase3Result || !state.phase1Result) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.developStrategy(state.phase3Result, state.phase1Result, language);
|
||||
setState(s => ({ ...s, currentPhase: Phase.Strategy, phase4Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase5Submit = async () => {
|
||||
// Requires all previous data for the final report
|
||||
if (!state.phase4Result || !state.phase3Result || !state.phase2Result || !state.phase1Result) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.generateAssets(
|
||||
state.phase4Result,
|
||||
state.phase3Result,
|
||||
state.phase2Result,
|
||||
state.phase1Result,
|
||||
language
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.AssetGeneration, phase5Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase6Submit = async () => {
|
||||
if (!state.phase4Result || !state.phase3Result || !state.phase1Result) return;
|
||||
};
|
||||
|
||||
const handlePhase2Submit = async () => {
|
||||
if (!state.phase1Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.generateSalesEnablement(
|
||||
state.phase4Result,
|
||||
state.phase3Result,
|
||||
state.phase1Result,
|
||||
language
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.SalesEnablement, phase6Result: result, isLoading: false }));
|
||||
const result = await Gemini.discoverICPs(state.phase1Result, language, state.projectId);
|
||||
setState(s => ({ ...s, currentPhase: Phase.ICPDiscovery, phase2Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase7Submit = async () => {
|
||||
if (!state.phase4Result || !state.phase2Result) return;
|
||||
};
|
||||
|
||||
const handlePhase3Submit = async () => {
|
||||
if (!state.phase2Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.generateLandingPageCopy(
|
||||
state.phase4Result,
|
||||
state.phase2Result,
|
||||
language
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.LandingPage, phase7Result: result, isLoading: false }));
|
||||
const result = await Gemini.huntWhales(state.phase2Result, language, state.projectId);
|
||||
setState(s => ({ ...s, currentPhase: Phase.WhaleHunting, phase3Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase8Submit = async () => {
|
||||
if (!state.phase2Result || !state.phase1Result) return;
|
||||
};
|
||||
|
||||
const handlePhase4Submit = async () => {
|
||||
if (!state.phase3Result || !state.phase1Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.buildBusinessCase(
|
||||
state.phase2Result,
|
||||
state.phase1Result,
|
||||
language
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.BusinessCase, phase8Result: result, isLoading: false }));
|
||||
const result = await Gemini.developStrategy(state.phase3Result, state.phase1Result, language, state.projectId);
|
||||
setState(s => ({ ...s, currentPhase: Phase.Strategy, phase4Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase9Submit = async () => {
|
||||
if (!state.phase1Result || !state.phase4Result) return;
|
||||
};
|
||||
|
||||
const handlePhase5Submit = async () => {
|
||||
// Requires all previous data for the final report
|
||||
if (!state.phase4Result || !state.phase3Result || !state.phase2Result || !state.phase1Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.translateTech(
|
||||
state.phase1Result,
|
||||
state.phase4Result,
|
||||
language
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.TechTranslator, phase9Result: result, isLoading: false }));
|
||||
const result = await Gemini.generateAssets(
|
||||
state.phase4Result,
|
||||
state.phase3Result,
|
||||
state.phase2Result,
|
||||
state.phase1Result,
|
||||
language,
|
||||
state.projectId
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.AssetGeneration, phase5Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
const handlePhase6Submit = async () => {
|
||||
if (!state.phase4Result || !state.phase3Result || !state.phase1Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.generateSalesEnablement(
|
||||
state.phase4Result,
|
||||
state.phase3Result,
|
||||
state.phase1Result,
|
||||
language,
|
||||
state.projectId
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.SalesEnablement, phase6Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase7Submit = async () => {
|
||||
if (!state.phase4Result || !state.phase2Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.generateLandingPageCopy(
|
||||
state.phase4Result,
|
||||
state.phase2Result,
|
||||
language,
|
||||
state.projectId
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.LandingPage, phase7Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase8Submit = async () => {
|
||||
if (!state.phase2Result || !state.phase1Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.buildBusinessCase(
|
||||
state.phase2Result,
|
||||
state.phase1Result,
|
||||
language,
|
||||
state.projectId
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.BusinessCase, phase8Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhase9Submit = async () => {
|
||||
if (!state.phase1Result || !state.phase4Result || !state.projectId) return;
|
||||
setState(s => ({ ...s, isLoading: true }));
|
||||
try {
|
||||
const result = await Gemini.translateTech(
|
||||
state.phase1Result,
|
||||
state.phase4Result,
|
||||
language,
|
||||
state.projectId
|
||||
);
|
||||
setState(s => ({ ...s, currentPhase: Phase.TechTranslator, phase9Result: result, isLoading: false }));
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
setState(s => ({ ...s, isLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
// --- List Mutation Handlers (Phase 1) ---
|
||||
|
||||
const addFeature = () => {
|
||||
@@ -960,7 +924,7 @@ const App: React.FC = () => {
|
||||
<label className="flex flex-col items-center justify-center aspect-square rounded-lg border-2 border-dashed border-slate-300 dark:border-robo-600 hover:border-blue-400 dark:hover:border-robo-400 cursor-pointer transition-colors bg-slate-50 dark:bg-robo-900/30">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
accept="image/*"
|
||||
multiple
|
||||
onChange={handleImageUpload}
|
||||
className="hidden"
|
||||
@@ -1196,7 +1160,9 @@ const App: React.FC = () => {
|
||||
{state.isLoading ? (
|
||||
<span className="flex items-center gap-2"><Loader2 className="animate-spin"/> {labels.processing}</span>
|
||||
) : (
|
||||
<> {labels.confirmICP} <ArrowRight size={18} /></>
|
||||
<>
|
||||
{labels.confirmICP} <ArrowRight size={18} />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
@@ -2091,4 +2057,4 @@ const App: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
|
||||
@@ -31,18 +31,18 @@ export const analyzeProduct = async (productInput: string, lang: Language): Prom
|
||||
};
|
||||
|
||||
// --- Phase 2: ICP Discovery ---
|
||||
export const discoverICPs = async (phase1Data: Phase1Data, lang: Language): Promise<Phase2Data> => {
|
||||
return callApi<Phase2Data>('run', 'phase2', { phase1Data, lang });
|
||||
export const discoverICPs = async (phase1Data: Phase1Data, lang: Language, projectId: string): Promise<Phase2Data> => {
|
||||
return callApi<Phase2Data>('run', 'phase2', { phase1Data, lang, projectId });
|
||||
};
|
||||
|
||||
// --- Phase 3: Whale Hunting ---
|
||||
export const huntWhales = async (phase2Data: Phase2Data, lang: Language): Promise<Phase3Data> => {
|
||||
return callApi<Phase3Data>('run', 'phase3', { phase2Data, lang });
|
||||
export const huntWhales = async (phase2Data: Phase2Data, lang: Language, projectId: string): Promise<Phase3Data> => {
|
||||
return callApi<Phase3Data>('run', 'phase3', { phase2Data, lang, projectId });
|
||||
};
|
||||
|
||||
// --- Phase 4: Strategy ---
|
||||
export const developStrategy = async (phase3Data: Phase3Data, phase1Data: Phase1Data, lang: Language): Promise<Phase4Data> => {
|
||||
return callApi<Phase4Data>('run', 'phase4', { phase3Data, phase1Data, lang });
|
||||
export const developStrategy = async (phase3Data: Phase3Data, phase1Data: Phase1Data, lang: Language, projectId: string): Promise<Phase4Data> => {
|
||||
return callApi<Phase4Data>('run', 'phase4', { phase3Data, phase1Data, lang, projectId });
|
||||
};
|
||||
|
||||
// --- Phase 5: Assets & Report ---
|
||||
@@ -51,9 +51,10 @@ export const generateAssets = async (
|
||||
phase3Data: Phase3Data,
|
||||
phase2Data: Phase2Data,
|
||||
phase1Data: Phase1Data,
|
||||
lang: Language
|
||||
lang: Language,
|
||||
projectId: string
|
||||
): Promise<{ report: string }> => {
|
||||
return callApi<{ report: string }>('run', 'phase5', { phase4Data, phase3Data, phase2Data, phase1Data, lang });
|
||||
return callApi<{ report: string }>('run', 'phase5', { phase4Data, phase3Data, phase2Data, phase1Data, lang, projectId });
|
||||
};
|
||||
|
||||
// --- Phase 6: Sales Enablement & Visuals ---
|
||||
@@ -61,45 +62,48 @@ export const generateSalesEnablement = async (
|
||||
phase4Data: Phase4Data,
|
||||
phase3Data: Phase3Data,
|
||||
phase1Data: Phase1Data,
|
||||
lang: Language
|
||||
lang: Language,
|
||||
projectId: string
|
||||
): Promise<Phase6Data> => {
|
||||
return callApi<Phase6Data>('run', 'phase6', { phase4Data, phase3Data, phase1Data, lang });
|
||||
return callApi<Phase6Data>('run', 'phase6', { phase4Data, phase3Data, phase1Data, lang, projectId });
|
||||
};
|
||||
|
||||
// --- Phase 7: Vertical Landing Page Copy ---
|
||||
export const generateLandingPageCopy = async (
|
||||
phase4Data: Phase4Data,
|
||||
phase2Data: Phase2Data,
|
||||
lang: Language
|
||||
lang: Language,
|
||||
projectId: string
|
||||
): Promise<Phase7Data> => {
|
||||
return callApi<Phase7Data>('run', 'phase7', { phase4Data, phase2Data, lang });
|
||||
return callApi<Phase7Data>('run', 'phase7', { phase4Data, phase2Data, lang, projectId });
|
||||
};
|
||||
|
||||
// --- Phase 8: Business Case Builder ---
|
||||
export const buildBusinessCase = async (
|
||||
phase2Data: Phase2Data,
|
||||
phase1Data: Phase1Data,
|
||||
lang: Language
|
||||
lang: Language,
|
||||
projectId: string
|
||||
): Promise<Phase8Data> => {
|
||||
return callApi<Phase8Data>('run', 'phase8', { phase2Data, phase1Data, lang });
|
||||
return callApi<Phase8Data>('run', 'phase8', { phase2Data, phase1Data, lang, projectId });
|
||||
};
|
||||
|
||||
// --- Phase 9: Feature-to-Value Translator ---
|
||||
export const translateTech = async (
|
||||
phase1Data: Phase1Data,
|
||||
phase4Data: Phase4Data,
|
||||
lang: Language
|
||||
lang: Language,
|
||||
projectId: string
|
||||
): Promise<Phase9Data> => {
|
||||
return callApi<Phase9Data>('run', 'phase9', { phase1Data, phase4Data, lang });
|
||||
return callApi<Phase9Data>('run', 'phase9', { phase1Data, phase4Data, lang, projectId });
|
||||
};
|
||||
|
||||
export const translateReportToEnglish = async (reportMarkdown: string): Promise<{ report: string }> => {
|
||||
return callApi<{ report: string }>('run', 'translate', { reportMarkdown });
|
||||
};
|
||||
|
||||
export const generateConceptImage = async (prompt: string, referenceImagesBase64?: string[]): Promise<string> => {
|
||||
const result = await callApi<{ imageBase64: string }>('run', 'image', { prompt, referenceImagesBase64 });
|
||||
return result.imageBase64;
|
||||
export const generateConceptImage = async (prompt: string, referenceImagesBase64?: string[], projectId?: string): Promise<string> => {
|
||||
return (await callApi<{ imageBase64: string }>('run', 'image', { prompt, referenceImagesBase64, projectId })).imageBase64;
|
||||
};
|
||||
|
||||
export const listSessions = async (): Promise<{ projects: ProjectHistoryItem[] }> => {
|
||||
|
||||
Reference in New Issue
Block a user