Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 62 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,28 @@ The purpose of Chaos Coder is to accelerate the development process by providing

## Features

- Generates five unique web application variations
- Generates multiple unique web application variations (1-6 apps)
- Real-time code preview for each variation
- Interactive interface with theme toggling
- Voice input support for hands-free prompting
- Keyboard shortcuts for quick access to tools
- **Multiple AI Provider Support**: Choose from Portkey, OpenAI, Groq, Anthropic, local Ollama, or custom OpenAI-compatible APIs
- **Flexible Configuration**: Easy-to-use interface for switching between AI providers
- **Fallback Support**: Automatic failover between multiple AI providers

## Tech Stack

- Next.js 14
- TypeScript
- Tailwind CSS
- Framer Motion
- Hugging Face Inference API
- Multiple AI Providers:
- Portkey (Multi-provider gateway)
- OpenAI API
- Groq
- Anthropic (via OpenRouter)
- Local Ollama
- Custom OpenAI-compatible APIs

## Setup

Expand All @@ -47,12 +56,37 @@ npm install

### 3. Set up environment variables

Create a `.env.local` file in the project root:
Create a `.env.local` file in the project root. You can copy from `.env.example`:

```bash
HF_API_TOKEN=your_huggingface_api_token
cp .env.example .env.local
```

Configure at least one AI provider:

**Option 1: Portkey (Recommended - Multi-provider with fallback)**
```bash
PORTKEY_API_KEY=your_portkey_api_key_here
```

**Option 2: OpenAI Direct**
```bash
OPENAI_API_KEY=your_openai_api_key_here
```

**Option 3: Groq**
```bash
GROQ_API_KEY=your_groq_api_key_here
```

**Option 4: Anthropic via OpenRouter**
```bash
OPENROUTER_API_KEY=your_openrouter_api_key_here
```

**Option 5: Local Ollama**
No API key required - just ensure Ollama is running locally on port 11434.

### 4. Run the development server

```bash
Expand All @@ -62,13 +96,33 @@ npm run dev
## Usage

1. Access the application in your web browser at http://localhost:3000
2. Enter your web application requirements or ideas in the input form
3. View and compare the five different application variations
4. Use the code preview panel to inspect and edit the generated code
5. Use keyboard shortcuts for quick access to tools:
2. **Configure AI Provider**: Click the AI configuration button to set up your preferred AI provider
3. Enter your web application requirements or ideas in the input form
4. Choose the number of variations to generate (1-6)
5. Click "Generate Web Apps" to create multiple variations
6. View and compare the different application variations
7. Use the code preview panel to inspect and edit the generated code
8. Use keyboard shortcuts for quick access to tools:
- Shift+L: Open prompt input
- Shift+P: Open performance metrics

### AI Provider Configuration

The application supports multiple AI providers. Click the gear icon to configure:

- **Portkey**: Multi-provider gateway with automatic fallback
- **OpenAI**: Direct OpenAI API integration
- **Groq**: Fast inference with Groq chips
- **Anthropic**: Claude models via OpenRouter
- **Local Ollama**: Use local Ollama installation
- **Custom**: Any OpenAI-compatible API endpoint

Each provider can be configured with:
- API endpoint URL
- API key (if required)
- Model selection
- Temperature and token limits

## Development

To start the development server:
Expand Down
241 changes: 77 additions & 164 deletions nextjs-web-app/src/app/api/generate/route.ts
Original file line number Diff line number Diff line change
@@ -1,188 +1,101 @@
import { Portkey } from "portkey-ai";
import { NextResponse, NextRequest } from "next/server";
import { AIService } from "@/lib/ai-service";
import { getProvider, AI_PROVIDERS, OpenAICompatibleConfig } from "@/lib/ai-config";

export const runtime = "edge";

// Simple in-memory store for rate limiting (replace with Redis in production)
const submissionCounts = new Map<string, number>();

const frameworkPrompts = {
tailwind:
"Use Tailwind CSS for styling with modern utility classes. Include the Tailwind CDN.",
materialize:
"Use Materialize CSS framework for a Material Design look. Include the Materialize CDN.",
bootstrap:
"Use Bootstrap 5 for responsive components and layout. Include the Bootstrap CDN.",
patternfly:
"Use PatternFly for enterprise-grade UI components. Include the PatternFly CDN.",
pure: "Use Pure CSS for minimalist, responsive design. Include the Pure CSS CDN.",
};

export async function POST(req: NextRequest) {
try {
const body = await req.json();
const { prompt, variation, framework } = body;

const portkeyApiKey = process.env.PORTKEY_API_KEY;
if (!portkeyApiKey) {
const {
prompt,
variation,
framework,
isUpdate,
existingCode,
aiProvider = 'portkey',
aiConfig
} = body;

// Get the AI provider configuration
const provider = getProvider(aiProvider);
if (!provider) {
return NextResponse.json(
{ error: "PORTKEY_API_KEY not configured" },
{ status: 500 }
{ error: `Unknown AI provider: ${aiProvider}` },
{ status: 400 }
);
}

// Configure Portkey with main provider (groq) and fallback (openrouter)
const portkey = new Portkey({
apiKey: portkeyApiKey,
config: {
strategy: {
mode: "fallback",
},
targets: [
{
virtual_key: "cerebras-b79172",
override_params: {
model: "qwen-3-32b",
},
},
{
virtual_key: "groq-virtual-ke-9479cd",
override_params: {
model: "llama-3.2-1b-preview",
},
},
{
virtual_key: "openrouter-07e727",
override_params: {
model: "google/gemini-flash-1.5-8b",
},
},
{
virtual_key: "openai-9c929c",
override_params: {
model: "gpt-4o-mini",
},
}
],
},
});

const frameworkInstructions = framework
? frameworkPrompts[framework as keyof typeof frameworkPrompts]
: "";

// Determine if this is an update request
const isUpdate = body.isUpdate === true;
const existingCode = body.existingCode || "";

let fullPrompt;

if (isUpdate) {
fullPrompt = `Update the following web application based on these instructions:

Instructions:
1. Update request: ${prompt}
2. Framework: ${frameworkInstructions}

EXISTING CODE TO MODIFY:
\`\`\`html
${existingCode}
\`\`\`

Technical Requirements:
- Maintain the overall structure of the existing code
- Make targeted changes based on the update request
- Keep all working functionality that isn't explicitly changed
- Preserve the existing styling approach and framework
- Ensure all interactive elements continue to work
- Add clear comments for any new or modified sections

Additional Notes:
- Return the COMPLETE updated HTML file content
- Do not remove existing functionality unless specifically requested
- Ensure the code remains well-structured and maintainable
- Return ONLY the HTML file content without any explanations

Format the code with proper indentation and spacing for readability.`;
// Prepare AI configuration
let config: OpenAICompatibleConfig;

if (provider.type === 'portkey') {
// For Portkey, we still use the original configuration
const portkeyApiKey = process.env.PORTKEY_API_KEY;
if (!portkeyApiKey) {
return NextResponse.json(
{ error: "PORTKEY_API_KEY not configured" },
{ status: 500 }
);
}
config = {
baseUrl: '',
apiKey: portkeyApiKey,
model: provider.defaultModel,
};
} else {
fullPrompt = `Create a well-structured, modern web application based on the specific requirements below:

CORE FUNCTIONALITY REQUEST:
${prompt}

IMPORTANT: Interpret the request literally and specifically. Do not default to generic patterns like to-do lists unless explicitly requested. Be creative and think about what the user actually wants.

VARIATION INSTRUCTIONS:
${variation}

FRAMEWORK REQUIREMENTS:
${frameworkInstructions}

CREATIVE INTERPRETATION GUIDELINES:
- If the request mentions "organize" or "productivity", consider alternatives to to-do lists such as:
* Calendar/scheduling apps
* Dashboard with widgets
* Time tracking applications
* Habit tracking systems
* Note-taking or journaling apps
* Project management boards
* Goal setting interfaces
- Focus on the specific domain or context mentioned in the request
- Add unique features that make the application interesting and functional
- Think about what would genuinely solve the user's stated problem

Technical Requirements:
- Create a single HTML file with clean, indented code structure
- Organize the code in this order:
1. <!DOCTYPE html> and meta tags
2. <title> and other head elements
3. Framework CSS and JS imports
4. Custom CSS styles in a <style> tag
5. HTML body with semantic markup
6. JavaScript in a <script> tag at the end of body
- Use proper HTML5 semantic elements
- Include clear spacing between sections
- Add descriptive comments for each major component
- Ensure responsive design with mobile-first approach
- Use modern ES6+ JavaScript features
- Keep the code modular and well-organized
- Ensure all interactive elements have proper styling states (hover, active, etc.)
- Implement the framework-specific best practices and components
// For OpenAI-compatible providers
if (!aiConfig) {
return NextResponse.json(
{ error: "AI configuration required for OpenAI-compatible providers" },
{ status: 400 }
);
}

Additional Notes:
- The code must be complete and immediately runnable
- All custom CSS and JavaScript should be included inline
- Code must work properly when rendered in an iframe
- Focus on clean, maintainable code structure
- Return ONLY the HTML file content without any explanations
config = {
baseUrl: aiConfig.baseUrl || provider.baseUrl || '',
apiKey: aiConfig.apiKey || '',
model: aiConfig.model || provider.defaultModel,
temperature: aiConfig.temperature,
maxTokens: aiConfig.maxTokens,
};

// Validate required fields
if (provider.requiresApiKey && !config.apiKey) {
return NextResponse.json(
{ error: `API key required for ${provider.name}` },
{ status: 400 }
);
}

Format the code with proper indentation and spacing for readability.`;
if (!config.baseUrl) {
return NextResponse.json(
{ error: `Base URL required for ${provider.name}` },
{ status: 400 }
);
}
}

const response = await portkey.chat.completions.create({
messages: [{ role: "user", content: fullPrompt }],
temperature: 0.7,
max_tokens: 4096,
});

// Get the response content
let code = response.choices[0].message.content || "";
// Create AI service instance
const aiService = new AIService(provider, config);

// Trim out any markdown code blocks (```html, ```, etc.)
code = code
.replace(/^```(?:html|javascript|js)?\n([\s\S]*?)```$/m, "$1")
.trim();

// Strip everything before the starting <html> tag (case insensitive)
if (typeof code === 'string') {
const htmlStartMatch = code.match(/<html[^>]*>/i);
if (htmlStartMatch) {
const htmlStartIndex = code.indexOf(htmlStartMatch[0]);
code = code.substring(htmlStartIndex);
}
}
// Generate the application using the AI service
const result = await aiService.generate({
prompt,
variation,
framework,
isUpdate,
existingCode,
});

return NextResponse.json({ code });
return NextResponse.json({
code: result.code,
provider: result.provider,
model: result.model,
});
} catch (error) {
console.error("Error:", error);
return NextResponse.json(
Expand Down
Loading