// Removed direct use of @google/generative-ai on the client // and switched to calling backend endpoints that securely use the API key at runtime. // Keep js-beautify formatting utilities and transformers for compatibility import { html as formatHtml } from "js-beautify"; export interface ChatMessage { role: string; content: string; } // Helper function to format HTML with proper indentation const formatCode = (code: string): string => { try { return formatHtml(code, { indent_size: 2, indent_char: ' ', max_preserve_newlines: 2, preserve_newlines: true, indent_inner_html: true, brace_style: 'collapse', indent_scripts: 'normal', wrap_line_length: 120, unformatted: ['code', 'pre', 'em', 'strong', 'span'], content_unformatted: ['pre', 'code'], }); } catch (error) { console.error('Error formatting code:', error); return code; } }; // Helper function to transform the AI's array response into the object format our app uses. const transformApiResponse = (response: { files: { fileName: string; code: string }[] }): Record => { const filesRecord: Record = {}; if (response && (response as any).files && Array.isArray((response as any).files)) { for (const file of (response as any).files) { if (file.fileName && file.code) { filesRecord[file.fileName] = formatCode(file.code); } } } return filesRecord; }; // Normalize server response to the same shape as before const normalizeResponse = (data: any): Record => { // If server already returns a Record if (data && typeof data === 'object' && !Array.isArray(data) && !('files' in data)) { return data as Record; } // If server returns { files: [...] } if (data && typeof data === 'object' && 'files' in data) { return transformApiResponse(data as { files: { fileName: string; code: string }[] }); } // Fallback to empty object return {}; }; const handleError = async (res: Response) => { let message = 'Unknown error'; try { const body = await res.json(); if (body && body.error) { message = String(body.error); } } catch { // ignore JSON parse errors message = res.statusText || message; } // Preserve prior UX message for missing key to avoid UI changes if (message.toLowerCase().includes('gemini api key is not configured')) { throw new Error('Gemini API key is not configured. Please set GEMINI_API_KEY in your Hugging Face Space secrets.'); } throw new Error(message); }; export const generateCode = async ( messages: ChatMessage[] ): Promise> => { try { const res = await fetch('/api/generate-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages }), }); if (!res.ok) { await handleError(res); } const data = await res.json(); return normalizeResponse(data); } catch (error) { console.error('Error in generateCode:', error); throw error; } }; export const modifyCode = async ( currentFiles: Record, modificationRequest: string ): Promise> => { try { const res = await fetch('/api/modify-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ currentFiles, modificationRequest }), }); if (!res.ok) { await handleError(res); } const data = await res.json(); return normalizeResponse(data); } catch (error) { console.error('Error in modifyCode:', error); throw error; } };