rocky1410's picture
Updated server again
193d4ed
// 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<string, string> => {
const filesRecord: Record<string, string> = {};
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<string, string> => {
// If server already returns a Record<string, string>
if (data && typeof data === 'object' && !Array.isArray(data) && !('files' in data)) {
return data as Record<string, string>;
}
// 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<Record<string, string>> => {
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<string, string>,
modificationRequest: string
): Promise<Record<string, string>> => {
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;
}
};