Spaces:
Running
Running
File size: 3,702 Bytes
2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 193d4ed 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e 2b19ed8 a27839e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
// 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;
}
}; |