gemini.ts•5.5 kB
import { GoogleGenerativeAI } from "@google/generative-ai";
import { WebsiteGenerator, WebsiteComponents, LLMConfig } from "../types.js";
export class GeminiWebsiteGenerator implements WebsiteGenerator {
private client: GoogleGenerativeAI;
private config: LLMConfig;
constructor(config?: LLMConfig) {
this.config = {
model: "gemini-1.5-flash",
maxTokens: 4000,
temperature: 0.7,
...config
};
// Initialize Gemini client with API key from environment or config
const apiKey = config?.apiKey || process.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error("GEMINI_API_KEY environment variable is required");
}
this.client = new GoogleGenerativeAI(apiKey);
}
getAvailableModels(): string[] {
return [
"gemini-1.5-flash",
"gemini-1.5-pro",
"gemini-1.0-pro"
];
}
private async generateWithGemini(prompt: string, model?: string): Promise<string> {
try {
const genModel = this.client.getGenerativeModel({
model: model || this.config.model || "gemini-1.5-flash"
});
// Very short timeout for MCP compatibility (5 seconds)
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => reject(new Error('Request timeout after 5 seconds')), 5000);
});
const generatePromise = genModel.generateContent({
contents: [
{
role: "user",
parts: [{ text: prompt }]
}
],
generationConfig: {
maxOutputTokens: Math.min(this.config.maxTokens || 1000, 1000), // Limit to 1000 tokens for speed
temperature: this.config.temperature
}
});
const result = await Promise.race([generatePromise, timeoutPromise]);
return result.response.text() || "";
} catch (error) {
console.error('Gemini API Error:', error);
// If Gemini fails, fallback to a simple message indicating the issue
if (error instanceof Error && error.message.includes('timeout')) {
throw new Error(`Gemini API timeout - try using Groq instead (leave model field empty)`);
}
throw new Error(`Gemini API error: ${error instanceof Error ? error.message : String(error)}`);
}
}
async generateHTML(prompt: string, model?: string): Promise<string> {
const htmlPrompt = `Generate clean, semantic HTML5 code for the following request. Only return the HTML code without any explanations or markdown formatting:
${prompt}
Requirements:
- Use semantic HTML5 elements
- Include proper DOCTYPE and meta tags
- Make it responsive-ready
- Add appropriate accessibility attributes
- Only return the HTML code, no explanations`;
return this.generateWithGemini(htmlPrompt, model);
}
async generateCSS(prompt: string, model?: string): Promise<string> {
const cssPrompt = `Generate modern CSS code for the following styling request. Only return the CSS code without any explanations or markdown formatting:
${prompt}
Requirements:
- Use modern CSS features (flexbox, grid, custom properties)
- Make it responsive
- Include hover effects and transitions where appropriate
- Use a mobile-first approach
- Only return the CSS code, no explanations`;
return this.generateWithGemini(cssPrompt, model);
}
async generateJS(prompt: string, model?: string): Promise<string> {
const jsPrompt = `Generate clean, modern JavaScript code for the following functionality request. Only return the JavaScript code without any explanations or markdown formatting:
${prompt}
Requirements:
- Use modern ES6+ JavaScript
- Include proper error handling
- Add comments for complex logic
- Make it modular and reusable
- Follow best practices
- Only return the JavaScript code, no explanations`;
return this.generateWithGemini(jsPrompt, model);
}
async generateWebsite(prompt: string, includeJs: boolean = true, model?: string): Promise<string> {
// Generate HTML with placeholders
const htmlPrompt = `Generate a complete HTML5 webpage for: ${prompt}
Requirements:
- Complete HTML document with DOCTYPE, head, and body
- Include a <style> section placeholder: <style id="placeholder-css"></style>
- Include a <script> section placeholder: <script id="placeholder-js"></script>
- Make it responsive-ready
- Add proper meta tags and title
- Only return the HTML code, no explanations`;
let html = await this.generateWithGemini(htmlPrompt, model);
// Generate CSS
const cssPrompt = `Generate CSS styles for a webpage about: ${prompt}
Requirements:
- Modern, attractive styling
- Responsive design (mobile-first)
- Good color scheme and typography
- Smooth transitions and hover effects
- Professional appearance
- Only return the CSS code, no explanations`;
const css = await this.generateWithGemini(cssPrompt, model);
html = html.replace('<style id="placeholder-css"></style>', `<style>\n${css}\n</style>`);
if (includeJs) {
const jsPrompt = `Generate JavaScript functionality for a webpage about: ${prompt}
Requirements:
- Add interactive features
- Include smooth scrolling, animations, or form handling as appropriate
- Use modern ES6+ JavaScript
- Add event listeners and DOM manipulation
- Make it enhance the user experience
- Only return the JavaScript code, no explanations`;
const js = await this.generateWithGemini(jsPrompt, model);
html = html.replace('<script id="placeholder-js"></script>', `<script>\n${js}\n</script>`);
}
return html;
}
}