import React, { useState, useCallback } from 'react'; import { AudioInput } from './components/AudioInput'; import { ResultsView } from './components/ResultsView'; import { ApiKeySettings } from './components/ApiKeySettings'; import { analyzeAudio } from './services/geminiService'; import type { VocalProfile, EQSetting } from './types'; type Status = 'idle' | 'processing' | 'success' | 'error'; const blobToBase64 = (blob: Blob): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => { if (typeof reader.result === 'string') { resolve(reader.result.split(',')[1]); } else { reject(new Error('Failed to convert blob to base64')); } }; reader.onerror = reject; reader.readAsDataURL(blob); }); }; const Header: React.FC = () => (

EQ Template Creator

Your Personal AI Audio Engineer

); const Loader: React.FC<{ message: string }> = ({ message }) => (

{message}

); export default function App() { const [status, setStatus] = useState('idle'); const [error, setError] = useState(null); const [vocalProfile, setVocalProfile] = useState(null); const [eqSettings, setEqSettings] = useState(null); const [audioBlob, setAudioBlob] = useState(null); const [audacityXml, setAudacityXml] = useState(null); const [hasApiKey, setHasApiKey] = useState(false); const handleAudioSubmit = useCallback(async (blob: Blob, mimeType: string) => { setStatus('processing'); setError(null); setAudioBlob(blob); try { const base64Audio = await blobToBase64(blob); const result = await analyzeAudio(base64Audio, mimeType); setVocalProfile(result.vocalProfile); setEqSettings(result.eqPreset); setAudacityXml(result.audacityXml); setStatus('success'); } catch (err) { console.error(err); setError(err instanceof Error ? err.message : 'An unknown error occurred during analysis.'); setStatus('error'); } }, []); const handleReset = () => { setStatus('idle'); setError(null); setVocalProfile(null); setEqSettings(null); setAudioBlob(null); setAudacityXml(null); }; const renderContent = () => { switch (status) { case 'processing': return ; case 'success': return vocalProfile && eqSettings && audioBlob && audacityXml && ( ); case 'error': return (

Analysis Failed

{error}

); case 'idle': default: return ; } }; return (
{hasApiKey && (
{renderContent()}
)}
); }