akhaliq HF Staff commited on
Commit
b42dfef
Β·
1 Parent(s): a8247a1
.dockerignore ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ venv/
8
+ .venv/
9
+ ENV/
10
+ env/
11
+ *.egg-info/
12
+ dist/
13
+ build/
14
+
15
+ # Node
16
+ node_modules/
17
+ npm-debug.log*
18
+ yarn-debug.log*
19
+ yarn-error.log*
20
+ .pnpm-debug.log*
21
+
22
+ # Next.js
23
+ frontend/.next/
24
+ frontend/out/
25
+ frontend/build/
26
+
27
+ # Git
28
+ .git/
29
+ .gitignore
30
+
31
+ # IDE
32
+ .vscode/
33
+ .idea/
34
+ *.swp
35
+ *.swo
36
+ *~
37
+
38
+ # OS
39
+ .DS_Store
40
+ Thumbs.db
41
+
42
+ # Documentation
43
+ *.md
44
+ !README.md
45
+
46
+ # Docker
47
+ Dockerfile*
48
+ docker-compose*.yml
49
+ .dockerignore
50
+
51
+ # Logs
52
+ *.log
53
+ logs/
54
+ log/
55
+
56
+ # Generated
57
+ generated_projects/
58
+
59
+ # Tests
60
+ test/
61
+ tests/
62
+ __tests__/
63
+
64
+ # Lock files (will be regenerated)
65
+ uv.lock
66
+ poetry.lock
67
+
Dockerfile ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Multi-stage build for AnyCoder Docker Space
2
+
3
+ # Stage 1: Build frontend
4
+ FROM node:18-slim AS frontend-builder
5
+
6
+ WORKDIR /build
7
+
8
+ # Copy frontend package files
9
+ COPY frontend/package*.json ./
10
+ RUN npm ci
11
+
12
+ # Copy frontend source
13
+ COPY frontend/ ./
14
+
15
+ # Build frontend
16
+ RUN npm run build
17
+
18
+ # Stage 2: Production image
19
+ FROM python:3.11-slim
20
+
21
+ # Set up a new user named "user" with user ID 1000
22
+ RUN useradd -m -u 1000 user
23
+
24
+ # Switch to the "user" user
25
+ USER user
26
+
27
+ # Set home to the user's home directory
28
+ ENV HOME=/home/user \
29
+ PATH=/home/user/.local/bin:$PATH \
30
+ PYTHONUNBUFFERED=1
31
+
32
+ # Set the working directory to the user's home directory
33
+ WORKDIR $HOME/app
34
+
35
+ # Copy Python requirements and install dependencies
36
+ COPY --chown=user:user requirements.txt .
37
+ RUN pip install --no-cache-dir --upgrade pip && \
38
+ pip install --no-cache-dir -r requirements.txt
39
+
40
+ # Copy application code
41
+ COPY --chown=user:user anycoder_app/ ./anycoder_app/
42
+ COPY --chown=user:user backend_api.py .
43
+ COPY --chown=user:user app.py .
44
+
45
+ # Copy built frontend from builder stage
46
+ COPY --chown=user:user --from=frontend-builder /build/.next ./frontend/.next
47
+ COPY --chown=user:user --from=frontend-builder /build/public ./frontend/public
48
+ COPY --chown=user:user --from=frontend-builder /build/package*.json ./frontend/
49
+ COPY --chown=user:user --from=frontend-builder /build/next.config.js ./frontend/
50
+ COPY --chown=user:user --from=frontend-builder /build/node_modules ./frontend/node_modules
51
+
52
+ # Install Node.js for running frontend
53
+ USER root
54
+ RUN apt-get update && \
55
+ apt-get install -y --no-install-recommends nodejs npm && \
56
+ rm -rf /var/lib/apt/lists/*
57
+ USER user
58
+
59
+ # Set environment variables for the application
60
+ ENV BACKEND_HOST=http://localhost:8000 \
61
+ PORT=7860
62
+
63
+ # Create startup script that runs both services
64
+ # Backend on 8000, Frontend on 7860 (exposed port)
65
+ RUN echo '#!/bin/bash\n\
66
+ set -e\n\
67
+ \n\
68
+ echo "πŸš€ Starting AnyCoder Docker Space..."\n\
69
+ \n\
70
+ # Start backend on port 8000 in background\n\
71
+ echo "πŸ“‘ Starting FastAPI backend on port 8000..."\n\
72
+ cd $HOME/app\n\
73
+ uvicorn backend_api:app --host 0.0.0.0 --port 8000 &\n\
74
+ BACKEND_PID=$!\n\
75
+ \n\
76
+ # Wait for backend to be ready\n\
77
+ echo "⏳ Waiting for backend to start..."\n\
78
+ sleep 5\n\
79
+ \n\
80
+ # Start frontend on port 7860 (HF Spaces exposed port)\n\
81
+ echo "🎨 Starting Next.js frontend on port 7860..."\n\
82
+ cd $HOME/app/frontend\n\
83
+ PORT=7860 BACKEND_HOST=http://localhost:8000 npm start\n\
84
+ ' > $HOME/app/start.sh && chmod +x $HOME/app/start.sh
85
+
86
+ # Expose port 7860 (HF Spaces default)
87
+ EXPOSE 7860
88
+
89
+ # Run the startup script
90
+ CMD ["./start.sh"]
91
+
README.md CHANGED
@@ -1,143 +1,135 @@
1
  ---
2
- title: Anycoder
3
- emoji: πŸ”₯
4
- colorFrom: indigo
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 5.49.1
8
- app_file: app.py
9
  pinned: false
10
- disable_embedding: true
11
  hf_oauth: true
12
  hf_oauth_scopes:
13
- - manage-repos
14
  ---
15
 
16
- # AnyCoder - AI Code Generator
 
17
 
18
- AnyCoder is an AI-powered code generator that helps you create applications by describing them in plain English. It supports multiple AI models, multimodal input, website redesign, and one-click deployment to Hugging Face Spaces. The UI is built with Gradio theming for a minimal, modern experience.
19
 
20
- ## Features
21
 
22
- - **Multi-Model Support**: Choose from Moonshot Kimi-K2, Kimi K2 Turbo (Preview), Kimi K2 Thinking, DeepSeek V3, DeepSeek R1, ERNIE-4.5-VL, MiniMax M2, Qwen3-235B-A22B, Qwen3-30B-A3B-Instruct-2507, Qwen3-30B-A3B-Thinking-2507, SmolLM3-3B, GLM-4.1V-9B-Thinking, Gemini 2.5 Flash and Gemini 2.5 Pro (OpenAI-compatible)
23
- - Claude-Opus-4.1 (via Poe)
24
- - **Flexible Input**: Describe your app in text, upload a UI design image (for multimodal models), provide a reference file (PDF, TXT, MD, CSV, DOCX, or image), or enter a website URL for redesign
25
- - **Web Search Integration**: Enable real-time web search (Tavily, with advanced search depth) to enhance code generation with up-to-date information and best practices
26
- - **Code Generation**: Generate code in HTML, Python, JS, and more. Special support for transformers.js apps (outputs index.html, index.js, style.css)
27
- - **Live Preview**: Instantly preview generated HTML in a sandboxed iframe
28
- - **Modify Existing Code**: Use search/replace block format to update generated HTML
29
- - **One-Click Deployment**: Deploy your app to Hugging Face Spaces (Gradio, Streamlit, Static HTML, or Transformers.js) with OAuth login
30
- - **History & Examples**: Chat-like history of all interactions and quick example prompts for fast prototyping
31
- - **Minimal, Modern UI**: Built with Gradio 5.x, using only built-in theming and styling (no custom CSS)
32
 
33
- ## Installation
 
 
 
 
 
 
 
34
 
35
- 1. Clone the repository:
36
- ```bash
37
- git clone <repository-url>
38
- cd anycoder
39
  ```
40
- 2. Install dependencies:
41
- ```bash
42
- pip install -r requirements.txt
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  ```
44
- 3. Set up environment variables:
 
 
 
 
 
45
  ```bash
46
  export HF_TOKEN="your_huggingface_token"
47
- export DASHSCOPE_API_KEY="your_dashscope_api_key" # Required for Qwen3-30B models via DashScope
48
- export POE_API_KEY="your_poe_api_key" # Required for GPT-5, Grok-4, and Grok-Code-Fast-1 via Poe
49
- export GEMINI_API_KEY="your_gemini_api_key" # Required for Gemini models
50
- export MOONSHOT_API_KEY="your_moonshot_api_key" # Required for Kimi models
51
- export MINIMAX_API_KEY="your_minimax_api_key" # Required for MiniMax M2 model
 
 
 
52
  ```
53
 
54
- ## Usage
55
 
56
- 1. Run the application:
57
  ```bash
58
- python app.py
 
59
  ```
60
- 2. Open your browser and navigate to the provided URL
61
- 3. Describe your application in the text input field, or:
62
- - Upload a UI design image (for multimodal models)
63
- - Upload a reference file (PDF, TXT, MD, CSV, DOCX, or image)
64
- - Enter a website URL for redesign (the app will extract and analyze the HTML and content)
65
- - Enable web search for up-to-date information
66
- - Choose a different AI model or code language
67
- 4. Click "Generate" to create your code
68
- 5. View the generated code in the Code tab or see it in action in the Preview tab
69
- 6. Use the History tab to review previous generations
70
- 7. **Deploy to Space**: Enter a title and click "πŸš€ Deploy App" to publish your application (OAuth login required) - the SDK is automatically matched to your selected code language
71
-
72
- ## Supported Models
73
-
74
- - Moonshot Kimi-K2
75
- - Kimi K2 Turbo (Preview)
76
- - Kimi K2 Thinking
77
- - DeepSeek V3
78
- - DeepSeek V3.1
79
- - DeepSeek V3.1 Terminus
80
- - DeepSeek V3.2-Exp
81
- - DeepSeek R1
82
- - MiniMax M2
83
- - Qwen3-235B-A22B
84
- - Qwen3-4B-Instruct-2507
85
- - Qwen3-4B-Thinking-2507
86
- - Qwen3-30B-A3B-Instruct-2507 (via DashScope)
87
- - Qwen3-30B-A3B-Thinking-2507 (via DashScope)
88
- - GPT-5 (via Poe)
89
- - Grok-4 (via Poe)
90
- - Claude-Opus-4.1 (via Poe)
91
- - Gemini 2.5 Flash (OpenAI-compatible)
92
- - Gemini 2.5 Pro (OpenAI-compatible)
93
 
94
- ## Input Options
 
 
 
 
 
 
95
 
96
- - **Text Prompt**: Describe your app or code requirements
97
- - **Image Upload**: For multimodal models, upload a UI design image to generate code from visuals
98
- - **File Upload**: Provide a reference file (PDF, TXT, MD, CSV, DOCX, or image) for code generation or text extraction (OCR for images)
99
- - **Website URL**: Enter a URL to extract and redesign the website (HTML and content are analyzed and modernized)
100
 
101
- ## Code Generation & Modification
 
102
 
103
- - Generates code in HTML, Python, JS, and more (selectable via dropdown)
104
- - Special support for transformers.js apps (outputs index.html, index.js, style.css)
105
- - Svelte apps
106
- - For HTML, provides a live preview in a sandboxed iframe
107
- - For modification requests, uses a search/replace block format to update existing HTML
108
 
109
- ## Deployment
 
 
 
 
 
110
 
111
- - Deploy generated apps to Hugging Face Spaces directly from the UI
112
- - Supported SDKs: Gradio (Python), Streamlit (Python), Static (HTML), Transformers.js
113
- - OAuth login with Hugging Face is required for deployment to user-owned Spaces
114
 
115
- ## History & Examples
 
 
 
116
 
117
- - Maintains a chat-like history of user/assistant interactions
118
- - Quick example prompts are available in the sidebar for fast prototyping
119
 
120
- ## UI/UX
 
 
 
 
121
 
122
- - Built with Gradio 5.x, using only Gradio's built-in theming and styling (no custom CSS)
123
- - Minimal, uncluttered sidebar and interface
124
 
125
- ## Environment Variables
126
 
127
- - `HF_TOKEN`: Your Hugging Face API token (required)
128
- - `GEMINI_API_KEY`: Your Google Gemini API key (required to use Gemini models)
129
- - `MOONSHOT_API_KEY`: Your Moonshot AI API key (required to use Kimi models)
130
- - `MINIMAX_API_KEY`: Your MiniMax API key (required to use MiniMax M2 model)
131
 
132
- ## Project Structure
 
 
 
 
133
 
134
- ```
135
- anycoder/
136
- β”œβ”€β”€ app.py # Main application (all logic and UI)
137
- β”œβ”€β”€ requirements.txt
138
- β”œβ”€β”€ README.md # This file
139
- ```
140
 
141
- ## License
142
 
143
- [Add your license information here]
 
1
  ---
2
+ title: AnyCoder
3
+ emoji: πŸš€
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: docker
7
+ app_port: 7860
 
8
  pinned: false
9
+ disable_embedding: false
10
  hf_oauth: true
11
  hf_oauth_scopes:
12
+ - manage-repos
13
  ---
14
 
15
+ > **Note:** This is the Docker Space configuration for the React frontend version.
16
+ > For the original Gradio app, see `README_GRADIO.md`.
17
 
18
+ # AnyCoder - AI Code Generator with React Frontend
19
 
20
+ AnyCoder is a full-stack AI-powered code generator with a modern React/TypeScript frontend and FastAPI backend. Generate applications by describing them in plain English, with support for multiple AI models and one-click deployment to Hugging Face Spaces.
21
 
22
+ ## 🎨 Features
 
 
 
 
 
 
 
 
 
23
 
24
+ - **Modern React UI**: Apple-inspired design with VS Code layout
25
+ - **Real-time Streaming**: Server-Sent Events for live code generation
26
+ - **Multi-Model Support**: MiniMax M2, DeepSeek V3, and more via HuggingFace InferenceClient
27
+ - **Multiple Languages**: HTML, Gradio, Streamlit, React, Transformers.js, ComfyUI
28
+ - **Authentication**: HuggingFace OAuth + Dev mode for local testing
29
+ - **One-Click Deployment**: Deploy generated apps directly to HF Spaces
30
+
31
+ ## πŸ—οΈ Architecture
32
 
 
 
 
 
33
  ```
34
+ anycoder/
35
+ β”œβ”€β”€ backend_api.py # FastAPI backend with streaming
36
+ β”œβ”€β”€ frontend/ # Next.js React frontend
37
+ β”‚ β”œβ”€β”€ src/
38
+ β”‚ β”‚ β”œβ”€β”€ app/ # Pages (page.tsx, layout.tsx, globals.css)
39
+ β”‚ β”‚ β”œβ”€β”€ components/ # React components
40
+ β”‚ β”‚ β”œβ”€β”€ lib/ # API client, auth utilities
41
+ β”‚ β”‚ └── types/ # TypeScript types
42
+ β”‚ └── package.json
43
+ β”œβ”€β”€ anycoder_app/ # Original Gradio app modules
44
+ β”‚ β”œβ”€β”€ agent.py
45
+ β”‚ β”œβ”€β”€ config.py
46
+ β”‚ β”œβ”€β”€ deploy.py
47
+ β”‚ └── ...
48
+ β”œβ”€β”€ app.py # Original Gradio interface
49
+ β”œβ”€β”€ requirements.txt # Python dependencies
50
+ β”œβ”€β”€ Dockerfile # Docker Space configuration
51
+ └── start_fullstack.sh # Local development script
52
  ```
53
+
54
+ ## πŸš€ Quick Start
55
+
56
+ ### Local Development
57
+
58
+ 1. **Backend**:
59
  ```bash
60
  export HF_TOKEN="your_huggingface_token"
61
+ python backend_api.py
62
+ ```
63
+
64
+ 2. **Frontend** (new terminal):
65
+ ```bash
66
+ cd frontend
67
+ npm install
68
+ npm run dev
69
  ```
70
 
71
+ 3. Open `http://localhost:3000`
72
 
73
+ ### Using start script:
74
  ```bash
75
+ export HF_TOKEN="your_token"
76
+ ./start_fullstack.sh
77
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ ## 🐳 Docker Space Deployment
80
+
81
+ This app runs as a Docker Space on HuggingFace. The Dockerfile:
82
+ - Builds the Next.js frontend
83
+ - Runs FastAPI backend on port 7860
84
+ - Uses proper user permissions (UID 1000)
85
+ - Handles environment variables securely
86
 
87
+ ## πŸ”‘ Authentication
 
 
 
88
 
89
+ - **Dev Mode** (localhost): Mock login for testing
90
+ - **Production**: HuggingFace OAuth with manage-repos scope
91
 
92
+ ## πŸ“ Supported Languages
 
 
 
 
93
 
94
+ - `html` - Static HTML pages
95
+ - `gradio` - Python Gradio apps
96
+ - `streamlit` - Python Streamlit apps
97
+ - `react` - React/Next.js apps
98
+ - `transformers.js` - Browser ML apps
99
+ - `comfyui` - ComfyUI workflows
100
 
101
+ ## πŸ€– Available Models
 
 
102
 
103
+ - MiniMax M2 (via HF router with Novita)
104
+ - DeepSeek V3/V3.1
105
+ - DeepSeek R1
106
+ - And more via HuggingFace InferenceClient
107
 
108
+ ## 🎯 Usage
 
109
 
110
+ 1. Sign in with HuggingFace (or use Dev Login locally)
111
+ 2. Select a language and AI model
112
+ 3. Describe your app in the chat
113
+ 4. Watch code generate in real-time
114
+ 5. Click **πŸš€ Deploy** to publish to HF Spaces
115
 
116
+ ## πŸ› οΈ Environment Variables
 
117
 
118
+ - `HF_TOKEN` - HuggingFace API token (required)
119
 
120
+ ## πŸ“¦ Tech Stack
 
 
 
121
 
122
+ **Frontend:**
123
+ - Next.js 14
124
+ - TypeScript
125
+ - Tailwind CSS
126
+ - Monaco Editor
127
 
128
+ **Backend:**
129
+ - FastAPI
130
+ - HuggingFace Hub
131
+ - Server-Sent Events (SSE)
 
 
132
 
133
+ ## πŸ“„ License
134
 
135
+ MIT
README_GRADIO.md ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Anycoder
3
+ emoji: πŸ”₯
4
+ colorFrom: indigo
5
+ colorTo: indigo
6
+ sdk: gradio
7
+ sdk_version: 5.49.1
8
+ app_file: app.py
9
+ pinned: false
10
+ disable_embedding: true
11
+ hf_oauth: true
12
+ hf_oauth_scopes:
13
+ - manage-repos
14
+ ---
15
+
16
+ # AnyCoder - AI Code Generator
17
+
18
+ > **πŸ“± New:** A React/TypeScript frontend version is now the default! This file is the backup Gradio version. For the Docker Space with modern React UI, see `README.md`.
19
+
20
+ AnyCoder is an AI-powered code generator that helps you create applications by describing them in plain English. It supports multiple AI models, multimodal input, website redesign, and one-click deployment to Hugging Face Spaces. The UI is built with Gradio theming for a minimal, modern experience.
21
+
22
+ ## Features
23
+
24
+ - **Multi-Model Support**: Choose from Moonshot Kimi-K2, Kimi K2 Turbo (Preview), Kimi K2 Thinking, DeepSeek V3, DeepSeek R1, ERNIE-4.5-VL, MiniMax M2, Qwen3-235B-A22B, Qwen3-30B-A3B-Instruct-2507, Qwen3-30B-A3B-Thinking-2507, SmolLM3-3B, GLM-4.1V-9B-Thinking, Gemini 2.5 Flash and Gemini 2.5 Pro (OpenAI-compatible)
25
+ - Claude-Opus-4.1 (via Poe)
26
+ - **Flexible Input**: Describe your app in text, upload a UI design image (for multimodal models), provide a reference file (PDF, TXT, MD, CSV, DOCX, or image), or enter a website URL for redesign
27
+ - **Web Search Integration**: Enable real-time web search (Tavily, with advanced search depth) to enhance code generation with up-to-date information and best practices
28
+ - **Code Generation**: Generate code in HTML, Python, JS, and more. Special support for transformers.js apps (outputs index.html, index.js, style.css)
29
+ - **Live Preview**: Instantly preview generated HTML in a sandboxed iframe
30
+ - **Modify Existing Code**: Use search/replace block format to update generated HTML
31
+ - **One-Click Deployment**: Deploy your app to Hugging Face Spaces (Gradio, Streamlit, Static HTML, or Transformers.js) with OAuth login
32
+ - **History & Examples**: Chat-like history of all interactions and quick example prompts for fast prototyping
33
+ - **Minimal, Modern UI**: Built with Gradio 5.x, using only built-in theming and styling (no custom CSS)
34
+
35
+ ## Installation
36
+
37
+ 1. Clone the repository:
38
+ ```bash
39
+ git clone <repository-url>
40
+ cd anycoder
41
+ ```
42
+ 2. Install dependencies:
43
+ ```bash
44
+ pip install -r requirements.txt
45
+ ```
46
+ 3. Set up environment variables:
47
+ ```bash
48
+ export HF_TOKEN="your_huggingface_token"
49
+ export DASHSCOPE_API_KEY="your_dashscope_api_key" # Required for Qwen3-30B models via DashScope
50
+ export POE_API_KEY="your_poe_api_key" # Required for GPT-5, Grok-4, and Grok-Code-Fast-1 via Poe
51
+ export GEMINI_API_KEY="your_gemini_api_key" # Required for Gemini models
52
+ export MOONSHOT_API_KEY="your_moonshot_api_key" # Required for Kimi models
53
+ export MINIMAX_API_KEY="your_minimax_api_key" # Required for MiniMax M2 model
54
+ ```
55
+
56
+ ## Usage
57
+
58
+ 1. Run the application:
59
+ ```bash
60
+ python app.py
61
+ ```
62
+ 2. Open your browser and navigate to the provided URL
63
+ 3. Describe your application in the text input field, or:
64
+ - Upload a UI design image (for multimodal models)
65
+ - Upload a reference file (PDF, TXT, MD, CSV, DOCX, or image)
66
+ - Enter a website URL for redesign (the app will extract and analyze the HTML and content)
67
+ - Enable web search for up-to-date information
68
+ - Choose a different AI model or code language
69
+ 4. Click "Generate" to create your code
70
+ 5. View the generated code in the Code tab or see it in action in the Preview tab
71
+ 6. Use the History tab to review previous generations
72
+ 7. **Deploy to Space**: Enter a title and click "πŸš€ Deploy App" to publish your application (OAuth login required) - the SDK is automatically matched to your selected code language
73
+
74
+ ## Supported Models
75
+
76
+ - Moonshot Kimi-K2
77
+ - Kimi K2 Turbo (Preview)
78
+ - Kimi K2 Thinking
79
+ - DeepSeek V3
80
+ - DeepSeek V3.1
81
+ - DeepSeek V3.1 Terminus
82
+ - DeepSeek V3.2-Exp
83
+ - DeepSeek R1
84
+ - MiniMax M2
85
+ - Qwen3-235B-A22B
86
+ - Qwen3-4B-Instruct-2507
87
+ - Qwen3-4B-Thinking-2507
88
+ - Qwen3-30B-A3B-Instruct-2507 (via DashScope)
89
+ - Qwen3-30B-A3B-Thinking-2507 (via DashScope)
90
+ - GPT-5 (via Poe)
91
+ - Grok-4 (via Poe)
92
+ - Claude-Opus-4.1 (via Poe)
93
+ - Gemini 2.5 Flash (OpenAI-compatible)
94
+ - Gemini 2.5 Pro (OpenAI-compatible)
95
+
96
+ ## Input Options
97
+
98
+ - **Text Prompt**: Describe your app or code requirements
99
+ - **Image Upload**: For multimodal models, upload a UI design image to generate code from visuals
100
+ - **File Upload**: Provide a reference file (PDF, TXT, MD, CSV, DOCX, or image) for code generation or text extraction (OCR for images)
101
+ - **Website URL**: Enter a URL to extract and redesign the website (HTML and content are analyzed and modernized)
102
+
103
+ ## Code Generation & Modification
104
+
105
+ - Generates code in HTML, Python, JS, and more (selectable via dropdown)
106
+ - Special support for transformers.js apps (outputs index.html, index.js, style.css)
107
+ - Svelte apps
108
+ - For HTML, provides a live preview in a sandboxed iframe
109
+ - For modification requests, uses a search/replace block format to update existing HTML
110
+
111
+ ## Deployment
112
+
113
+ - Deploy generated apps to Hugging Face Spaces directly from the UI
114
+ - Supported SDKs: Gradio (Python), Streamlit (Python), Static (HTML), Transformers.js
115
+ - OAuth login with Hugging Face is required for deployment to user-owned Spaces
116
+
117
+ ## History & Examples
118
+
119
+ - Maintains a chat-like history of user/assistant interactions
120
+ - Quick example prompts are available in the sidebar for fast prototyping
121
+
122
+ ## UI/UX
123
+
124
+ - Built with Gradio 5.x, using only Gradio's built-in theming and styling (no custom CSS)
125
+ - Minimal, uncluttered sidebar and interface
126
+
127
+ ## Environment Variables
128
+
129
+ - `HF_TOKEN`: Your Hugging Face API token (required)
130
+ - `GEMINI_API_KEY`: Your Google Gemini API key (required to use Gemini models)
131
+ - `MOONSHOT_API_KEY`: Your Moonshot AI API key (required to use Kimi models)
132
+ - `MINIMAX_API_KEY`: Your MiniMax API key (required to use MiniMax M2 model)
133
+
134
+ ## Project Structure
135
+
136
+ ```
137
+ anycoder/
138
+ β”œβ”€β”€ app.py # Main application (all logic and UI)
139
+ β”œβ”€β”€ requirements.txt
140
+ β”œβ”€β”€ README.md # This file
141
+ ```
142
+
143
+ ## License
144
+
145
+ [Add your license information here]
backend_api.py ADDED
@@ -0,0 +1,499 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ FastAPI backend for AnyCoder - provides REST API endpoints
3
+ """
4
+ from fastapi import FastAPI, HTTPException, Header, WebSocket, WebSocketDisconnect
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from fastapi.responses import StreamingResponse
7
+ from pydantic import BaseModel
8
+ from typing import Optional, List, Dict, AsyncGenerator
9
+ import json
10
+ import asyncio
11
+ from datetime import datetime
12
+
13
+ # Import only what we need, avoiding Gradio UI imports
14
+ import sys
15
+ import os
16
+ from huggingface_hub import InferenceClient
17
+
18
+ # Define models and languages here to avoid importing Gradio UI
19
+ AVAILABLE_MODELS = [
20
+ {"name": "Sherlock Dash Alpha", "id": "openrouter/sherlock-dash-alpha", "description": "Sherlock Dash Alpha model via OpenRouter"},
21
+ {"name": "MiniMax M2", "id": "MiniMaxAI/MiniMax-M2", "description": "MiniMax M2 model via HuggingFace InferenceClient with Novita provider"},
22
+ {"name": "DeepSeek V3.2-Exp", "id": "deepseek-ai/DeepSeek-V3.2-Exp", "description": "DeepSeek V3.2 Experimental via HuggingFace"},
23
+ {"name": "DeepSeek R1", "id": "deepseek-ai/DeepSeek-R1-0528", "description": "DeepSeek R1 model for code generation"},
24
+ {"name": "GPT-5", "id": "gpt-5", "description": "OpenAI GPT-5 via OpenRouter"},
25
+ {"name": "Gemini Flash Latest", "id": "gemini-flash-latest", "description": "Google Gemini Flash via OpenRouter"},
26
+ {"name": "Qwen3 Max Preview", "id": "qwen3-max-preview", "description": "Qwen3 Max Preview via DashScope API"},
27
+ ]
28
+
29
+ LANGUAGE_CHOICES = ["html", "gradio", "transformers.js", "streamlit", "comfyui", "react"]
30
+
31
+ app = FastAPI(title="AnyCoder API", version="1.0.0")
32
+
33
+ # Configure CORS
34
+ app.add_middleware(
35
+ CORSMiddleware,
36
+ allow_origins=["http://localhost:3000", "http://localhost:3001"], # Frontend URLs
37
+ allow_credentials=True,
38
+ allow_methods=["*"],
39
+ allow_headers=["*"],
40
+ )
41
+
42
+
43
+ # Pydantic models for request/response
44
+ class CodeGenerationRequest(BaseModel):
45
+ query: str
46
+ language: str = "html"
47
+ model_id: str = "openrouter/sherlock-dash-alpha"
48
+ provider: str = "auto"
49
+ history: List[List[str]] = []
50
+ agent_mode: bool = False
51
+
52
+
53
+ class DeploymentRequest(BaseModel):
54
+ code: str
55
+ space_name: str
56
+ language: str
57
+ requirements: Optional[str] = None
58
+
59
+
60
+ class AuthStatus(BaseModel):
61
+ authenticated: bool
62
+ username: Optional[str] = None
63
+ message: str
64
+
65
+
66
+ class ModelInfo(BaseModel):
67
+ name: str
68
+ id: str
69
+ description: str
70
+
71
+
72
+ class CodeGenerationResponse(BaseModel):
73
+ code: str
74
+ history: List[List[str]]
75
+ status: str
76
+
77
+
78
+ # Mock authentication for development
79
+ # In production, integrate with HuggingFace OAuth
80
+ class MockAuth:
81
+ def __init__(self, token: Optional[str] = None):
82
+ self.token = token
83
+ # Extract username from dev token or use generic name
84
+ if token and token.startswith("dev_token_"):
85
+ # Extract username from dev token format: dev_token_<username>_<timestamp>
86
+ parts = token.split("_")
87
+ self.username = parts[2] if len(parts) > 2 else "user"
88
+ else:
89
+ self.username = "user" if token else None
90
+
91
+ def is_authenticated(self):
92
+ # Accept any token (for dev mode)
93
+ return bool(self.token)
94
+
95
+
96
+ def get_auth_from_header(authorization: Optional[str] = None):
97
+ """Extract authentication from header"""
98
+ if not authorization:
99
+ return MockAuth(None)
100
+
101
+ # Handle "Bearer " prefix
102
+ if authorization.startswith("Bearer "):
103
+ token = authorization.replace("Bearer ", "")
104
+ else:
105
+ token = authorization
106
+
107
+ return MockAuth(token)
108
+
109
+
110
+ @app.get("/")
111
+ async def root():
112
+ """Health check endpoint"""
113
+ return {"status": "ok", "message": "AnyCoder API is running"}
114
+
115
+
116
+ @app.get("/api/models", response_model=List[ModelInfo])
117
+ async def get_models():
118
+ """Get available AI models"""
119
+ return [
120
+ ModelInfo(
121
+ name=model["name"],
122
+ id=model["id"],
123
+ description=model["description"]
124
+ )
125
+ for model in AVAILABLE_MODELS
126
+ ]
127
+
128
+
129
+ @app.get("/api/languages")
130
+ async def get_languages():
131
+ """Get available programming languages/frameworks"""
132
+ return {"languages": LANGUAGE_CHOICES}
133
+
134
+
135
+ @app.get("/api/auth/status")
136
+ async def auth_status(authorization: Optional[str] = Header(None)):
137
+ """Check authentication status"""
138
+ auth = get_auth_from_header(authorization)
139
+ if auth.is_authenticated():
140
+ return AuthStatus(
141
+ authenticated=True,
142
+ username=auth.username,
143
+ message=f"Authenticated as {auth.username}"
144
+ )
145
+ return AuthStatus(
146
+ authenticated=False,
147
+ username=None,
148
+ message="Not authenticated"
149
+ )
150
+
151
+
152
+ @app.get("/api/generate")
153
+ async def generate_code(
154
+ query: str,
155
+ language: str = "html",
156
+ model_id: str = "openrouter/sherlock-dash-alpha",
157
+ provider: str = "auto",
158
+ authorization: Optional[str] = Header(None)
159
+ ):
160
+ """Generate code based on user query - returns streaming response"""
161
+ # Dev mode: No authentication required - just use server's HF_TOKEN
162
+ # In production, you would check real OAuth tokens here
163
+
164
+ async def event_stream() -> AsyncGenerator[str, None]:
165
+ """Stream generated code chunks"""
166
+ try:
167
+ # Find the selected model
168
+ selected_model = None
169
+ for model in AVAILABLE_MODELS:
170
+ if model["id"] == model_id:
171
+ selected_model = model
172
+ break
173
+
174
+ if not selected_model:
175
+ selected_model = AVAILABLE_MODELS[0]
176
+
177
+ # Track generated code
178
+ generated_code = ""
179
+
180
+ # Use a simple system prompt
181
+ system_prompt = "You are a helpful AI assistant that generates code based on user requirements. Generate clean, well-commented code."
182
+
183
+ # Get the real model ID
184
+ actual_model_id = selected_model["id"]
185
+
186
+ # Determine which provider/API to use based on model ID
187
+ if actual_model_id.startswith("openrouter/"):
188
+ # OpenRouter models - use via OpenAI-compatible API
189
+ api_key = os.getenv("OPENROUTER_API_KEY") or os.getenv("HF_TOKEN")
190
+ client = InferenceClient(api_key=api_key, provider="openai", base_url="https://openrouter.ai/api/v1")
191
+ # Keep the model_id as-is for OpenRouter
192
+ elif actual_model_id == "MiniMaxAI/MiniMax-M2":
193
+ # MiniMax M2 via HuggingFace with Novita provider
194
+ hf_token = os.getenv("HF_TOKEN")
195
+ if not hf_token:
196
+ error_data = json.dumps({
197
+ "type": "error",
198
+ "message": "HF_TOKEN environment variable not set. Please set it in your terminal.",
199
+ "timestamp": datetime.now().isoformat()
200
+ })
201
+ yield f"data: {error_data}\n\n"
202
+ return
203
+
204
+ # Use OpenAI client with HuggingFace router
205
+ from openai import OpenAI
206
+ client = OpenAI(
207
+ base_url="https://router.huggingface.co/v1",
208
+ api_key=hf_token,
209
+ default_headers={
210
+ "X-HF-Bill-To": "huggingface"
211
+ }
212
+ )
213
+ # Add :novita suffix for the API call
214
+ actual_model_id = "MiniMaxAI/MiniMax-M2:novita"
215
+ elif actual_model_id.startswith("deepseek-ai/"):
216
+ # DeepSeek models via HuggingFace
217
+ client = InferenceClient(token=os.getenv("HF_TOKEN"))
218
+ elif actual_model_id == "qwen3-max-preview":
219
+ # Qwen via DashScope (would need separate implementation)
220
+ # For now, fall back to HF
221
+ client = InferenceClient(token=os.getenv("HF_TOKEN"))
222
+ else:
223
+ # Default: HuggingFace models
224
+ client = InferenceClient(token=os.getenv("HF_TOKEN"))
225
+
226
+ # Prepare messages
227
+ messages = [
228
+ {"role": "system", "content": system_prompt},
229
+ {"role": "user", "content": f"Generate a {language} application: {query}"}
230
+ ]
231
+
232
+ # Stream the response
233
+ try:
234
+ stream = client.chat.completions.create(
235
+ model=actual_model_id,
236
+ messages=messages,
237
+ temperature=0.7,
238
+ max_tokens=10000,
239
+ stream=True
240
+ )
241
+
242
+ for chunk in stream:
243
+ # Check if choices array has elements before accessing
244
+ if (hasattr(chunk, 'choices') and
245
+ chunk.choices and
246
+ len(chunk.choices) > 0 and
247
+ hasattr(chunk.choices[0], 'delta') and
248
+ hasattr(chunk.choices[0].delta, 'content') and
249
+ chunk.choices[0].delta.content):
250
+ content = chunk.choices[0].delta.content
251
+ generated_code += content
252
+
253
+ # Send chunk as Server-Sent Event
254
+ event_data = json.dumps({
255
+ "type": "chunk",
256
+ "content": content,
257
+ "timestamp": datetime.now().isoformat()
258
+ })
259
+ yield f"data: {event_data}\n\n"
260
+ await asyncio.sleep(0) # Allow other tasks to run
261
+
262
+ # Send completion event
263
+ completion_data = json.dumps({
264
+ "type": "complete",
265
+ "code": generated_code,
266
+ "timestamp": datetime.now().isoformat()
267
+ })
268
+ yield f"data: {completion_data}\n\n"
269
+
270
+ except Exception as e:
271
+ error_data = json.dumps({
272
+ "type": "error",
273
+ "message": str(e),
274
+ "timestamp": datetime.now().isoformat()
275
+ })
276
+ yield f"data: {error_data}\n\n"
277
+
278
+ except Exception as e:
279
+ error_data = json.dumps({
280
+ "type": "error",
281
+ "message": f"Generation error: {str(e)}",
282
+ "timestamp": datetime.now().isoformat()
283
+ })
284
+ yield f"data: {error_data}\n\n"
285
+
286
+ return StreamingResponse(
287
+ event_stream(),
288
+ media_type="text/event-stream",
289
+ headers={
290
+ "Cache-Control": "no-cache",
291
+ "Connection": "keep-alive",
292
+ "X-Accel-Buffering": "no"
293
+ }
294
+ )
295
+
296
+
297
+ @app.post("/api/deploy")
298
+ async def deploy(
299
+ request: DeploymentRequest,
300
+ authorization: Optional[str] = Header(None)
301
+ ):
302
+ """Deploy generated code to HuggingFace Spaces"""
303
+ auth = get_auth_from_header(authorization)
304
+
305
+ if not auth.is_authenticated():
306
+ raise HTTPException(status_code=401, detail="Authentication required")
307
+
308
+ # Check if this is dev mode (no real token)
309
+ if auth.token and auth.token.startswith("dev_token_"):
310
+ # In dev mode, open HF Spaces creation page
311
+ import urllib.parse
312
+ base_url = "https://huggingface.co/new-space"
313
+
314
+ # Map language to SDK
315
+ language_to_sdk = {
316
+ "gradio": "gradio",
317
+ "streamlit": "docker",
318
+ "react": "docker",
319
+ "html": "static",
320
+ "transformers.js": "static",
321
+ "comfyui": "static"
322
+ }
323
+ sdk = language_to_sdk.get(request.language, "gradio")
324
+
325
+ params = urllib.parse.urlencode({
326
+ "name": request.space_name or "my-anycoder-app",
327
+ "sdk": sdk
328
+ })
329
+
330
+ # Prepare file content based on language
331
+ if request.language in ["html", "transformers.js", "comfyui"]:
332
+ file_path = "index.html"
333
+ else:
334
+ file_path = "app.py"
335
+
336
+ files_params = urllib.parse.urlencode({
337
+ "files[0][path]": file_path,
338
+ "files[0][content]": request.code
339
+ })
340
+
341
+ space_url = f"{base_url}?{params}&{files_params}"
342
+
343
+ return {
344
+ "success": True,
345
+ "space_url": space_url,
346
+ "message": "Dev mode: Please create the space manually",
347
+ "dev_mode": True
348
+ }
349
+
350
+ # Production mode with real token
351
+ try:
352
+ from huggingface_hub import HfApi
353
+ import tempfile
354
+ import uuid
355
+
356
+ # Get user token from header or use server token
357
+ user_token = auth.token if auth.token else os.getenv("HF_TOKEN")
358
+
359
+ if not user_token:
360
+ raise HTTPException(status_code=401, detail="No HuggingFace token available")
361
+
362
+ # Create API client
363
+ api = HfApi(token=user_token)
364
+
365
+ # Generate space name if not provided
366
+ space_name = request.space_name or f"anycoder-{uuid.uuid4().hex[:8]}"
367
+ repo_id = f"{auth.username}/{space_name}"
368
+
369
+ # Map language to SDK
370
+ language_to_sdk = {
371
+ "gradio": "gradio",
372
+ "streamlit": "docker",
373
+ "react": "docker",
374
+ "html": "static",
375
+ "transformers.js": "static",
376
+ "comfyui": "static"
377
+ }
378
+ sdk = language_to_sdk.get(request.language, "gradio")
379
+
380
+ # Create the space
381
+ try:
382
+ api.create_repo(
383
+ repo_id=repo_id,
384
+ repo_type="space",
385
+ space_sdk=sdk,
386
+ exist_ok=False
387
+ )
388
+ except Exception as e:
389
+ if "already exists" in str(e).lower():
390
+ # Space exists, we'll update it
391
+ pass
392
+ else:
393
+ raise
394
+
395
+ # Upload the code file
396
+ if request.language in ["html", "transformers.js", "comfyui"]:
397
+ file_name = "index.html"
398
+ else:
399
+ file_name = "app.py"
400
+
401
+ with tempfile.NamedTemporaryFile("w", suffix=f".{file_name.split('.')[-1]}", delete=False) as f:
402
+ f.write(request.code)
403
+ temp_path = f.name
404
+
405
+ try:
406
+ api.upload_file(
407
+ path_or_fileobj=temp_path,
408
+ path_in_repo=file_name,
409
+ repo_id=repo_id,
410
+ repo_type="space"
411
+ )
412
+
413
+ # For Gradio apps, also upload requirements.txt if needed
414
+ if request.language == "gradio":
415
+ # Simple requirements for basic Gradio app
416
+ requirements = "gradio>=4.0.0\n"
417
+ with tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False) as req_f:
418
+ req_f.write(requirements)
419
+ req_temp_path = req_f.name
420
+
421
+ try:
422
+ api.upload_file(
423
+ path_or_fileobj=req_temp_path,
424
+ path_in_repo="requirements.txt",
425
+ repo_id=repo_id,
426
+ repo_type="space"
427
+ )
428
+ finally:
429
+ os.unlink(req_temp_path)
430
+
431
+ space_url = f"https://huggingface.co/spaces/{repo_id}"
432
+
433
+ return {
434
+ "success": True,
435
+ "space_url": space_url,
436
+ "message": f"βœ… Deployed successfully to {repo_id}!"
437
+ }
438
+
439
+ finally:
440
+ os.unlink(temp_path)
441
+
442
+ except Exception as e:
443
+ raise HTTPException(status_code=500, detail=f"Deployment failed: {str(e)}")
444
+
445
+
446
+ @app.websocket("/ws/generate")
447
+ async def websocket_generate(websocket: WebSocket):
448
+ """WebSocket endpoint for real-time code generation"""
449
+ await websocket.accept()
450
+
451
+ try:
452
+ while True:
453
+ # Receive message from client
454
+ data = await websocket.receive_json()
455
+
456
+ query = data.get("query")
457
+ language = data.get("language", "html")
458
+ model_id = data.get("model_id", "openrouter/sherlock-dash-alpha")
459
+
460
+ # Send acknowledgment
461
+ await websocket.send_json({
462
+ "type": "status",
463
+ "message": "Generating code..."
464
+ })
465
+
466
+ # Mock code generation for now
467
+ await asyncio.sleep(0.5)
468
+
469
+ # Send generated code in chunks
470
+ sample_code = f"<!-- Generated {language} code -->\n<h1>Hello from AnyCoder!</h1>"
471
+
472
+ for i, char in enumerate(sample_code):
473
+ await websocket.send_json({
474
+ "type": "chunk",
475
+ "content": char,
476
+ "progress": (i + 1) / len(sample_code) * 100
477
+ })
478
+ await asyncio.sleep(0.01)
479
+
480
+ # Send completion
481
+ await websocket.send_json({
482
+ "type": "complete",
483
+ "code": sample_code
484
+ })
485
+
486
+ except WebSocketDisconnect:
487
+ print("Client disconnected")
488
+ except Exception as e:
489
+ await websocket.send_json({
490
+ "type": "error",
491
+ "message": str(e)
492
+ })
493
+ await websocket.close()
494
+
495
+
496
+ if __name__ == "__main__":
497
+ import uvicorn
498
+ uvicorn.run("backend_api:app", host="0.0.0.0", port=8000, reload=True)
499
+
frontend/.gitignore ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # dependencies
2
+ /node_modules
3
+ /.pnp
4
+ .pnp.js
5
+
6
+ # testing
7
+ /coverage
8
+
9
+ # next.js
10
+ /.next/
11
+ /out/
12
+
13
+ # production
14
+ /build
15
+
16
+ # misc
17
+ .DS_Store
18
+ *.pem
19
+
20
+ # debug
21
+ npm-debug.log*
22
+ yarn-debug.log*
23
+ yarn-error.log*
24
+
25
+ # local env files
26
+ .env*.local
27
+ .env
28
+
29
+ # vercel
30
+ .vercel
31
+
32
+ # typescript
33
+ *.tsbuildinfo
34
+ next-env.d.ts
35
+
frontend/next.config.js ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {
3
+ output: 'standalone',
4
+ reactStrictMode: true,
5
+ env: {
6
+ NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000',
7
+ },
8
+ async rewrites() {
9
+ // In Docker Space, proxy /api/* requests to backend on port 8000
10
+ // This allows frontend (7860) to communicate with backend (8000) internally
11
+ const API_HOST = process.env.BACKEND_HOST || 'http://localhost:8000';
12
+ return [
13
+ {
14
+ source: '/api/:path*',
15
+ destination: `${API_HOST}/api/:path*`,
16
+ },
17
+ {
18
+ source: '/ws/:path*',
19
+ destination: `${API_HOST}/ws/:path*`,
20
+ },
21
+ ];
22
+ },
23
+ }
24
+
25
+ module.exports = nextConfig
26
+
frontend/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
frontend/package.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "anycoder-frontend",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start -p 7860",
9
+ "lint": "next lint"
10
+ },
11
+ "dependencies": {
12
+ "next": "14.2.5",
13
+ "react": "^18.3.1",
14
+ "react-dom": "^18.3.1",
15
+ "axios": "^1.7.2",
16
+ "@monaco-editor/react": "^4.6.0",
17
+ "@huggingface/hub": "^0.15.1",
18
+ "prismjs": "^1.29.0",
19
+ "react-markdown": "^9.0.1",
20
+ "remark-gfm": "^4.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^20",
24
+ "@types/react": "^18",
25
+ "@types/react-dom": "^18",
26
+ "@types/prismjs": "^1.26.4",
27
+ "typescript": "^5",
28
+ "eslint": "^8",
29
+ "eslint-config-next": "14.2.5",
30
+ "autoprefixer": "^10.4.19",
31
+ "postcss": "^8.4.39",
32
+ "tailwindcss": "^3.4.4"
33
+ }
34
+ }
35
+
frontend/postcss.config.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
7
+
frontend/src/app/globals.css ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ * {
6
+ box-sizing: border-box;
7
+ padding: 0;
8
+ margin: 0;
9
+ }
10
+
11
+ html,
12
+ body {
13
+ height: 100%;
14
+ overflow: hidden;
15
+ }
16
+
17
+ body {
18
+ color: #e5e5e7;
19
+ background: #1d1d1f;
20
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', sans-serif;
21
+ -webkit-font-smoothing: antialiased;
22
+ -moz-osx-font-smoothing: grayscale;
23
+ letter-spacing: -0.01em;
24
+ }
25
+
26
+ /* Apple-style scrollbar */
27
+ ::-webkit-scrollbar {
28
+ width: 12px;
29
+ height: 12px;
30
+ }
31
+
32
+ ::-webkit-scrollbar-track {
33
+ background: transparent;
34
+ }
35
+
36
+ ::-webkit-scrollbar-thumb {
37
+ background: rgba(255, 255, 255, 0.2);
38
+ border-radius: 10px;
39
+ border: 3px solid #1d1d1f;
40
+ }
41
+
42
+ ::-webkit-scrollbar-thumb:hover {
43
+ background: rgba(255, 255, 255, 0.3);
44
+ }
45
+
46
+ ::-webkit-scrollbar-corner {
47
+ background: #1d1d1f;
48
+ }
49
+
50
+ /* Markdown styling in chat - VS Code style */
51
+ .prose {
52
+ max-width: none;
53
+ color: #cccccc;
54
+ }
55
+
56
+ .prose code {
57
+ background-color: #2d2d30;
58
+ color: #d4d4d4;
59
+ padding: 0.2em 0.4em;
60
+ border-radius: 3px;
61
+ font-size: 0.875em;
62
+ font-family: 'SF Mono', 'Monaco', 'Menlo', 'Courier New', monospace;
63
+ }
64
+
65
+ .prose pre {
66
+ background-color: #1e1e1e;
67
+ padding: 1em;
68
+ border-radius: 4px;
69
+ overflow-x: auto;
70
+ border: 1px solid #3e3e42;
71
+ }
72
+
73
+ .prose pre code {
74
+ background-color: transparent;
75
+ padding: 0;
76
+ }
77
+
78
+ .prose p {
79
+ margin: 0.5em 0;
80
+ }
81
+
82
+ .prose a {
83
+ color: #3794ff;
84
+ text-decoration: none;
85
+ }
86
+
87
+ .prose a:hover {
88
+ text-decoration: underline;
89
+ }
90
+
91
+ /* Selection color - Apple style */
92
+ ::selection {
93
+ background-color: rgba(0, 122, 255, 0.3);
94
+ color: #ffffff;
95
+ }
96
+
97
+ ::-moz-selection {
98
+ background-color: rgba(0, 122, 255, 0.3);
99
+ color: #ffffff;
100
+ }
101
+
102
+ /* Apple-style focus rings */
103
+ button:focus-visible,
104
+ input:focus-visible,
105
+ select:focus-visible {
106
+ outline: 2px solid rgba(0, 122, 255, 0.6);
107
+ outline-offset: 2px;
108
+ }
109
+
110
+ /* Smooth transitions */
111
+ * {
112
+ transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
113
+ }
114
+
frontend/src/app/layout.tsx ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Metadata } from 'next';
2
+ import { Inter } from 'next/font/google';
3
+ import './globals.css';
4
+
5
+ const inter = Inter({ subsets: ['latin'] });
6
+
7
+ export const metadata: Metadata = {
8
+ title: 'AnyCoder - AI Code Generator',
9
+ description: 'Generate code with AI - supports HTML, Gradio, React, Streamlit, and more',
10
+ };
11
+
12
+ export default function RootLayout({
13
+ children,
14
+ }: {
15
+ children: React.ReactNode;
16
+ }) {
17
+ return (
18
+ <html lang="en">
19
+ <body className={inter.className}>{children}</body>
20
+ </html>
21
+ );
22
+ }
23
+
frontend/src/app/page.tsx ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import Header from '@/components/Header';
5
+ import ChatInterface from '@/components/ChatInterface';
6
+ import CodeEditor from '@/components/CodeEditor';
7
+ import ControlPanel from '@/components/ControlPanel';
8
+ import { apiClient } from '@/lib/api';
9
+ import { isAuthenticated as checkIsAuthenticated, getStoredToken } from '@/lib/auth';
10
+ import type { Message, Language, CodeGenerationRequest } from '@/types';
11
+
12
+ export default function Home() {
13
+ const [messages, setMessages] = useState<Message[]>([]);
14
+ const [generatedCode, setGeneratedCode] = useState('');
15
+ const [selectedLanguage, setSelectedLanguage] = useState<Language>('html');
16
+ const [selectedModel, setSelectedModel] = useState('openrouter/sherlock-dash-alpha');
17
+ const [isGenerating, setIsGenerating] = useState(false);
18
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
19
+
20
+ useEffect(() => {
21
+ checkAuth();
22
+ // Check auth status every second to catch OAuth redirects
23
+ const interval = setInterval(checkAuth, 1000);
24
+ return () => clearInterval(interval);
25
+ }, []);
26
+
27
+ const checkAuth = () => {
28
+ const authenticated = checkIsAuthenticated();
29
+ setIsAuthenticated(authenticated);
30
+
31
+ // Make sure API client has the token
32
+ if (authenticated) {
33
+ const token = getStoredToken();
34
+ if (token) {
35
+ apiClient.setToken(token);
36
+ }
37
+ }
38
+ };
39
+
40
+ const handleSendMessage = async (message: string) => {
41
+ if (!isAuthenticated) {
42
+ alert('Please sign in with HuggingFace first! Click the "Sign in with Hugging Face" button in the header.');
43
+ return;
44
+ }
45
+
46
+ // Add user message
47
+ const userMessage: Message = {
48
+ role: 'user',
49
+ content: message,
50
+ timestamp: new Date().toISOString(),
51
+ };
52
+ setMessages((prev) => [...prev, userMessage]);
53
+ setIsGenerating(true);
54
+
55
+ // Prepare request
56
+ const request: CodeGenerationRequest = {
57
+ query: message,
58
+ language: selectedLanguage,
59
+ model_id: selectedModel,
60
+ provider: 'auto',
61
+ history: messages.map((m) => [m.role, m.content]),
62
+ agent_mode: false,
63
+ };
64
+
65
+ let generatedCodeBuffer = '';
66
+ const assistantMessage: Message = {
67
+ role: 'assistant',
68
+ content: '⏳ Generating code...',
69
+ timestamp: new Date().toISOString(),
70
+ };
71
+
72
+ // Add placeholder for assistant message
73
+ setMessages((prev) => [...prev, assistantMessage]);
74
+
75
+ // Stream the response
76
+ try {
77
+ apiClient.generateCodeStream(
78
+ request,
79
+ // onChunk - Update code editor in real-time, NOT the chat
80
+ (chunk: string) => {
81
+ generatedCodeBuffer += chunk;
82
+ setGeneratedCode(generatedCodeBuffer);
83
+ },
84
+ // onComplete
85
+ (code: string) => {
86
+ setGeneratedCode(code);
87
+ setIsGenerating(false);
88
+
89
+ // Update final message - just show success, not the code
90
+ setMessages((prev) => {
91
+ const newMessages = [...prev];
92
+ newMessages[newMessages.length - 1] = {
93
+ ...assistantMessage,
94
+ content: 'βœ… Code generated successfully! Check the editor β†’',
95
+ };
96
+ return newMessages;
97
+ });
98
+ },
99
+ // onError
100
+ (error: string) => {
101
+ setIsGenerating(false);
102
+ setMessages((prev) => {
103
+ const newMessages = [...prev];
104
+ newMessages[newMessages.length - 1] = {
105
+ ...assistantMessage,
106
+ content: `❌ Error: ${error}`,
107
+ };
108
+ return newMessages;
109
+ });
110
+ }
111
+ );
112
+ } catch (error) {
113
+ setIsGenerating(false);
114
+ setMessages((prev) => {
115
+ const newMessages = [...prev];
116
+ newMessages[newMessages.length - 1] = {
117
+ ...assistantMessage,
118
+ content: `❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
119
+ };
120
+ return newMessages;
121
+ });
122
+ }
123
+ };
124
+
125
+ const handleDeploy = async () => {
126
+ if (!generatedCode) {
127
+ alert('No code to deploy! Generate some code first.');
128
+ return;
129
+ }
130
+
131
+ const spaceName = prompt('Enter HuggingFace Space name (or leave empty for auto-generated):');
132
+ if (spaceName === null) return; // User cancelled
133
+
134
+ try {
135
+ const response = await apiClient.deploy({
136
+ code: generatedCode,
137
+ space_name: spaceName || undefined,
138
+ language: selectedLanguage,
139
+ });
140
+
141
+ if (response.success) {
142
+ // Open the space URL in a new tab
143
+ window.open(response.space_url, '_blank');
144
+
145
+ // Show success message
146
+ const isDev = response.dev_mode;
147
+ const message = isDev
148
+ ? 'πŸš€ Opening HuggingFace Spaces creation page...\nPlease complete the space setup in the new tab.'
149
+ : `βœ… Deployed successfully!\n\nOpening: ${response.space_url}`;
150
+ alert(message);
151
+ } else {
152
+ alert(`Deployment failed: ${response.message}`);
153
+ }
154
+ } catch (error) {
155
+ alert(`Deployment error: ${error instanceof Error ? error.message : 'Unknown error'}`);
156
+ }
157
+ };
158
+
159
+ const handleClear = () => {
160
+ if (confirm('Clear all messages and code?')) {
161
+ setMessages([]);
162
+ setGeneratedCode('');
163
+ }
164
+ };
165
+
166
+ return (
167
+ <div className="h-screen flex flex-col bg-[#1d1d1f]">
168
+ <Header />
169
+
170
+ {/* VS Code layout with Apple styling */}
171
+ <main className="flex-1 flex overflow-hidden">
172
+ {/* Left Sidebar - Chat Panel */}
173
+ <div className="w-80 bg-[#28282a] border-r border-[#48484a] flex flex-col shadow-xl">
174
+ {/* Panel Header */}
175
+ <div className="flex items-center px-5 py-4 bg-[#28282a] border-b border-[#48484a]">
176
+ <div className="flex space-x-2">
177
+ <div className="w-3 h-3 rounded-full bg-[#ff5f57] shadow-sm"></div>
178
+ <div className="w-3 h-3 rounded-full bg-[#ffbd2e] shadow-sm"></div>
179
+ <div className="w-3 h-3 rounded-full bg-[#28ca41] shadow-sm"></div>
180
+ </div>
181
+ <span className="ml-4 text-sm font-semibold text-[#e5e5e7] tracking-tight">Chat</span>
182
+ </div>
183
+
184
+ {/* Chat Panel */}
185
+ <div className="flex-1 overflow-hidden">
186
+ <ChatInterface
187
+ messages={messages}
188
+ onSendMessage={handleSendMessage}
189
+ isGenerating={isGenerating}
190
+ isAuthenticated={isAuthenticated}
191
+ />
192
+ </div>
193
+ </div>
194
+
195
+ {/* Center - Editor Group */}
196
+ <div className="flex-1 flex flex-col bg-[#1d1d1f]">
197
+ {/* Tab Bar */}
198
+ <div className="flex items-center px-5 h-11 bg-[#28282a] border-b border-[#48484a]">
199
+ <div className="flex items-center space-x-2">
200
+ <div className="px-4 py-1.5 bg-[#1d1d1f] border-t-2 border-[#007aff] text-sm text-[#e5e5e7] rounded-t-lg shadow-sm font-medium">
201
+ {selectedLanguage}.{selectedLanguage === 'html' ? 'html' : selectedLanguage === 'python' ? 'py' : 'js'}
202
+ </div>
203
+ </div>
204
+ <div className="ml-auto flex items-center space-x-3 text-xs text-[#a1a1a6]">
205
+ {isGenerating && (
206
+ <span className="flex items-center space-x-1.5 animate-pulse">
207
+ <div className="w-2 h-2 bg-[#007aff] rounded-full shadow-lg"></div>
208
+ <span className="font-medium">Generating...</span>
209
+ </span>
210
+ )}
211
+ <span className="font-semibold tracking-wide">{selectedLanguage.toUpperCase()}</span>
212
+ </div>
213
+ </div>
214
+
215
+ {/* Editor */}
216
+ <div className="flex-1">
217
+ <CodeEditor
218
+ code={generatedCode || '// Your generated code will appear here...\n// Select a model and start chatting to generate code'}
219
+ language={selectedLanguage}
220
+ onChange={setGeneratedCode}
221
+ readOnly={isGenerating}
222
+ />
223
+ </div>
224
+ </div>
225
+
226
+ {/* Right Sidebar - Configuration Panel */}
227
+ <div className="w-72 bg-[#28282a] border-l border-[#48484a] overflow-y-auto shadow-xl">
228
+ <ControlPanel
229
+ selectedLanguage={selectedLanguage}
230
+ selectedModel={selectedModel}
231
+ onLanguageChange={setSelectedLanguage}
232
+ onModelChange={setSelectedModel}
233
+ onDeploy={handleDeploy}
234
+ onClear={handleClear}
235
+ isGenerating={isGenerating}
236
+ />
237
+ </div>
238
+ </main>
239
+
240
+ {/* Status Bar - Apple style */}
241
+ <footer className="h-7 bg-[#28282a] border-t border-[#48484a] text-[#a1a1a6] text-xs flex items-center px-5 justify-between font-medium">
242
+ <div className="flex items-center space-x-5">
243
+ <span className="flex items-center space-x-1.5">
244
+ <svg className="w-3 h-3" fill="currentColor" viewBox="0 0 16 16">
245
+ <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0zM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0z"/>
246
+ </svg>
247
+ <span>AnyCoder</span>
248
+ </span>
249
+ <span className="flex items-center space-x-1.5">
250
+ {isAuthenticated ? (
251
+ <>
252
+ <span className="w-1.5 h-1.5 bg-[#30d158] rounded-full"></span>
253
+ <span>Connected</span>
254
+ </>
255
+ ) : (
256
+ <>
257
+ <span className="w-1.5 h-1.5 bg-[#ff9f0a] rounded-full"></span>
258
+ <span>Not authenticated</span>
259
+ </>
260
+ )}
261
+ </span>
262
+ </div>
263
+ <div className="flex items-center space-x-5">
264
+ <span>{messages.length} messages</span>
265
+ <a
266
+ href="https://huggingface.co/spaces/akhaliq/anycoder"
267
+ target="_blank"
268
+ rel="noopener noreferrer"
269
+ className="hover:text-[#e5e5e7] transition-colors"
270
+ >
271
+ Built with anycoder
272
+ </a>
273
+ </div>
274
+ </footer>
275
+ </div>
276
+ );
277
+ }
278
+
frontend/src/components/ChatInterface.tsx ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useRef, useEffect } from 'react';
4
+ import type { Message } from '@/types';
5
+ import ReactMarkdown from 'react-markdown';
6
+ import remarkGfm from 'remark-gfm';
7
+
8
+ interface ChatInterfaceProps {
9
+ messages: Message[];
10
+ onSendMessage: (message: string) => void;
11
+ isGenerating: boolean;
12
+ isAuthenticated?: boolean;
13
+ }
14
+
15
+ export default function ChatInterface({ messages, onSendMessage, isGenerating, isAuthenticated = false }: ChatInterfaceProps) {
16
+ const [input, setInput] = useState('');
17
+ const messagesEndRef = useRef<HTMLDivElement>(null);
18
+
19
+ const scrollToBottom = () => {
20
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
21
+ };
22
+
23
+ useEffect(() => {
24
+ scrollToBottom();
25
+ }, [messages]);
26
+
27
+ const handleSubmit = (e: React.FormEvent) => {
28
+ e.preventDefault();
29
+ if (input.trim() && !isGenerating) {
30
+ onSendMessage(input);
31
+ setInput('');
32
+ }
33
+ };
34
+
35
+ return (
36
+ <div className="flex flex-col h-full bg-[#1d1d1f]">
37
+ {/* Messages */}
38
+ <div className="flex-1 overflow-y-auto p-5 space-y-4">
39
+ {messages.length === 0 ? (
40
+ <div className="text-center text-[#a1a1a6] mt-12">
41
+ <div className="text-5xl mb-5">πŸ’¬</div>
42
+ {isAuthenticated ? (
43
+ <>
44
+ <p className="text-lg font-semibold text-[#e5e5e7] tracking-tight">Start a conversation</p>
45
+ <p className="text-sm mt-3 text-[#86868b] leading-relaxed">Describe what you want to build and I'll generate the code</p>
46
+ </>
47
+ ) : (
48
+ <>
49
+ <p className="text-lg font-semibold text-[#ff9f0a]">πŸ”’ Sign in to get started</p>
50
+ <p className="text-sm mt-3 text-[#86868b] leading-relaxed">Use Dev Login or sign in with Hugging Face</p>
51
+ </>
52
+ )}
53
+ </div>
54
+ ) : (
55
+ messages.map((message, index) => (
56
+ <div
57
+ key={index}
58
+ className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
59
+ >
60
+ <div
61
+ className={`max-w-[85%] rounded-2xl p-4 shadow-sm ${
62
+ message.role === 'user'
63
+ ? 'bg-[#007aff] text-white'
64
+ : 'bg-[#2c2c2e] text-[#e5e5e7] border border-[#48484a]'
65
+ }`}
66
+ >
67
+ <div className="flex items-start space-x-3">
68
+ <div className="text-base flex-shrink-0">
69
+ {message.role === 'user' ? 'πŸ‘€' : 'πŸ€–'}
70
+ </div>
71
+ <div className="flex-1 text-sm leading-relaxed">
72
+ {message.role === 'assistant' ? (
73
+ <ReactMarkdown
74
+ remarkPlugins={[remarkGfm]}
75
+ className="prose prose-invert prose-sm max-w-none"
76
+ >
77
+ {message.content}
78
+ </ReactMarkdown>
79
+ ) : (
80
+ <p className="whitespace-pre-wrap font-medium">{message.content}</p>
81
+ )}
82
+ </div>
83
+ </div>
84
+ {message.timestamp && (
85
+ <div className="text-xs opacity-50 mt-2 text-right font-medium">
86
+ {new Date(message.timestamp).toLocaleTimeString()}
87
+ </div>
88
+ )}
89
+ </div>
90
+ </div>
91
+ ))
92
+ )}
93
+ <div ref={messagesEndRef} />
94
+ </div>
95
+
96
+ {/* Input */}
97
+ <div className="border-t border-[#48484a] p-4 bg-[#28282a]">
98
+ <form onSubmit={handleSubmit} className="flex space-x-3">
99
+ <input
100
+ type="text"
101
+ value={input}
102
+ onChange={(e) => setInput(e.target.value)}
103
+ placeholder={isAuthenticated ? "Message AnyCoder..." : "πŸ”’ Please sign in first..."}
104
+ disabled={isGenerating || !isAuthenticated}
105
+ className="flex-1 px-4 py-3 bg-[#3a3a3c] text-[#e5e5e7] text-sm border border-[#48484a] rounded-xl focus:outline-none focus:ring-2 focus:ring-[#007aff] focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed placeholder-[#86868b] font-medium shadow-sm"
106
+ />
107
+ <button
108
+ type="submit"
109
+ disabled={isGenerating || !input.trim() || !isAuthenticated}
110
+ className="px-5 py-3 bg-[#007aff] text-white text-sm rounded-xl hover:bg-[#0051d5] disabled:bg-[#48484a] disabled:cursor-not-allowed transition-all font-semibold shadow-md disabled:shadow-none active:scale-95"
111
+ >
112
+ {isGenerating ? '⏳' : '↑'}
113
+ </button>
114
+ </form>
115
+ </div>
116
+ </div>
117
+ );
118
+ }
119
+
frontend/src/components/CodeEditor.tsx ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useEffect, useRef } from 'react';
4
+ import Editor from '@monaco-editor/react';
5
+
6
+ interface CodeEditorProps {
7
+ code: string;
8
+ language: string;
9
+ onChange?: (value: string) => void;
10
+ readOnly?: boolean;
11
+ }
12
+
13
+ export default function CodeEditor({ code, language, onChange, readOnly = false }: CodeEditorProps) {
14
+ const editorRef = useRef<any>(null);
15
+
16
+ // Map our language names to Monaco language IDs
17
+ const getMonacoLanguage = (lang: string): string => {
18
+ const languageMap: Record<string, string> = {
19
+ 'html': 'html',
20
+ 'gradio': 'python',
21
+ 'streamlit': 'python',
22
+ 'transformers.js': 'javascript',
23
+ 'react': 'typescript',
24
+ 'comfyui': 'json',
25
+ };
26
+ return languageMap[lang] || 'plaintext';
27
+ };
28
+
29
+ const handleEditorDidMount = (editor: any) => {
30
+ editorRef.current = editor;
31
+ };
32
+
33
+ return (
34
+ <div className="h-full overflow-hidden">
35
+ <Editor
36
+ height="100%"
37
+ language={getMonacoLanguage(language)}
38
+ value={code}
39
+ onChange={(value) => onChange && onChange(value || '')}
40
+ theme="vs-dark"
41
+ options={{
42
+ readOnly,
43
+ minimap: { enabled: true },
44
+ fontSize: 14,
45
+ fontFamily: "'SF Mono', 'JetBrains Mono', 'Menlo', 'Monaco', 'Courier New', monospace",
46
+ wordWrap: 'on',
47
+ lineNumbers: 'on',
48
+ scrollBeyondLastLine: false,
49
+ automaticLayout: true,
50
+ tabSize: 2,
51
+ padding: { top: 16, bottom: 16 },
52
+ lineHeight: 22,
53
+ letterSpacing: 0.5,
54
+ }}
55
+ onMount={handleEditorDidMount}
56
+ />
57
+ </div>
58
+ );
59
+ }
60
+
frontend/src/components/ControlPanel.tsx ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { apiClient } from '@/lib/api';
5
+ import type { Model, Language } from '@/types';
6
+
7
+ interface ControlPanelProps {
8
+ selectedLanguage: Language;
9
+ selectedModel: string;
10
+ onLanguageChange: (language: Language) => void;
11
+ onModelChange: (modelId: string) => void;
12
+ onDeploy: () => void;
13
+ onClear: () => void;
14
+ isGenerating: boolean;
15
+ }
16
+
17
+ export default function ControlPanel({
18
+ selectedLanguage,
19
+ selectedModel,
20
+ onLanguageChange,
21
+ onModelChange,
22
+ onDeploy,
23
+ onClear,
24
+ isGenerating,
25
+ }: ControlPanelProps) {
26
+ const [models, setModels] = useState<Model[]>([]);
27
+ const [languages, setLanguages] = useState<Language[]>([]);
28
+
29
+ useEffect(() => {
30
+ loadModels();
31
+ loadLanguages();
32
+ }, []);
33
+
34
+ const loadModels = async () => {
35
+ try {
36
+ const modelsList = await apiClient.getModels();
37
+ setModels(modelsList);
38
+ } catch (error) {
39
+ console.error('Failed to load models:', error);
40
+ }
41
+ };
42
+
43
+ const loadLanguages = async () => {
44
+ try {
45
+ const { languages: languagesList } = await apiClient.getLanguages();
46
+ setLanguages(languagesList);
47
+ } catch (error) {
48
+ console.error('Failed to load languages:', error);
49
+ }
50
+ };
51
+
52
+ return (
53
+ <div className="bg-[#28282a] p-5 space-y-6 h-full">
54
+ <h3 className="text-base font-semibold text-[#e5e5e7] tracking-tight mb-2">Configuration</h3>
55
+
56
+ {/* Language Selection */}
57
+ <div>
58
+ <label className="block text-sm font-semibold text-[#e5e5e7] mb-3 tracking-tight">
59
+ Language
60
+ </label>
61
+ <select
62
+ value={selectedLanguage}
63
+ onChange={(e) => onLanguageChange(e.target.value as Language)}
64
+ disabled={isGenerating}
65
+ className="w-full px-4 py-3 bg-[#3a3a3c] text-[#e5e5e7] text-sm border border-[#48484a] rounded-xl focus:outline-none focus:ring-2 focus:ring-[#007aff] focus:border-transparent disabled:opacity-50 font-medium shadow-sm"
66
+ >
67
+ {languages.map((lang) => (
68
+ <option key={lang} value={lang} className="bg-[#3a3a3c]">
69
+ {lang.charAt(0).toUpperCase() + lang.slice(1)}
70
+ </option>
71
+ ))}
72
+ </select>
73
+ </div>
74
+
75
+ {/* Model Selection */}
76
+ <div>
77
+ <label className="block text-sm font-semibold text-[#e5e5e7] mb-3 tracking-tight">
78
+ AI Model
79
+ </label>
80
+ <select
81
+ value={selectedModel}
82
+ onChange={(e) => onModelChange(e.target.value)}
83
+ disabled={isGenerating}
84
+ className="w-full px-4 py-3 bg-[#3a3a3c] text-[#e5e5e7] text-sm border border-[#48484a] rounded-xl focus:outline-none focus:ring-2 focus:ring-[#007aff] focus:border-transparent disabled:opacity-50 font-medium shadow-sm"
85
+ >
86
+ {models.map((model) => (
87
+ <option key={model.id} value={model.id} className="bg-[#3a3a3c]">
88
+ {model.name}
89
+ </option>
90
+ ))}
91
+ </select>
92
+ {models.find(m => m.id === selectedModel) && (
93
+ <p className="text-xs text-[#86868b] mt-3 leading-relaxed">
94
+ {models.find(m => m.id === selectedModel)?.description}
95
+ </p>
96
+ )}
97
+ </div>
98
+
99
+ {/* Action Buttons */}
100
+ <div className="flex flex-col space-y-3 pt-4">
101
+ <button
102
+ onClick={onDeploy}
103
+ disabled={isGenerating}
104
+ className="w-full px-4 py-3.5 bg-[#007aff] text-white text-sm rounded-xl hover:bg-[#0051d5] disabled:opacity-50 disabled:cursor-not-allowed transition-all font-semibold flex items-center justify-center space-x-2 shadow-md active:scale-95"
105
+ >
106
+ <span>πŸš€</span>
107
+ <span>Deploy</span>
108
+ </button>
109
+ <button
110
+ onClick={onClear}
111
+ disabled={isGenerating}
112
+ className="w-full px-4 py-3.5 bg-[#3a3a3c] text-[#e5e5e7] text-sm rounded-xl hover:bg-[#48484a] disabled:opacity-50 disabled:cursor-not-allowed transition-all font-semibold border border-[#48484a] flex items-center justify-center space-x-2 shadow-sm active:scale-95"
113
+ >
114
+ <span>πŸ—‘οΈ</span>
115
+ <span>Clear</span>
116
+ </button>
117
+ </div>
118
+
119
+ {/* Info Panel */}
120
+ <div className="mt-6 p-4 bg-[#2c2c2e] border border-[#48484a] rounded-xl shadow-sm">
121
+ <h4 className="text-sm font-semibold text-[#e5e5e7] mb-3 tracking-tight">πŸ’‘ Tips</h4>
122
+ <ul className="text-xs text-[#86868b] space-y-2 leading-relaxed">
123
+ <li>β€’ Be specific in your requirements</li>
124
+ <li>β€’ Try different AI models</li>
125
+ <li>β€’ Edit code in the editor</li>
126
+ <li>β€’ Deploy to HF Spaces</li>
127
+ </ul>
128
+ </div>
129
+ </div>
130
+ );
131
+ }
132
+
frontend/src/components/Header.tsx ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import {
5
+ initializeOAuth,
6
+ loginWithHuggingFace,
7
+ loginDevMode,
8
+ logout,
9
+ getStoredUserInfo,
10
+ isAuthenticated,
11
+ isDevelopmentMode
12
+ } from '@/lib/auth';
13
+ import { apiClient } from '@/lib/api';
14
+ import type { OAuthUserInfo } from '@/lib/auth';
15
+
16
+ export default function Header() {
17
+ const [userInfo, setUserInfo] = useState<OAuthUserInfo | null>(null);
18
+ const [isLoading, setIsLoading] = useState(true);
19
+ const [showDevLogin, setShowDevLogin] = useState(false);
20
+ const [devUsername, setDevUsername] = useState('');
21
+ const isDevMode = isDevelopmentMode();
22
+
23
+ useEffect(() => {
24
+ handleOAuthInit();
25
+ }, []);
26
+
27
+ const handleOAuthInit = async () => {
28
+ setIsLoading(true);
29
+ try {
30
+ const oauthResult = await initializeOAuth();
31
+
32
+ if (oauthResult) {
33
+ setUserInfo(oauthResult.userInfo);
34
+ // Set token in API client
35
+ apiClient.setToken(oauthResult.accessToken);
36
+ } else {
37
+ // Check if we have stored user info
38
+ const storedUserInfo = getStoredUserInfo();
39
+ if (storedUserInfo) {
40
+ setUserInfo(storedUserInfo);
41
+ }
42
+ }
43
+ } catch (error) {
44
+ console.error('OAuth initialization error:', error);
45
+ } finally {
46
+ setIsLoading(false);
47
+ }
48
+ };
49
+
50
+ const handleLogin = async () => {
51
+ try {
52
+ await loginWithHuggingFace();
53
+ } catch (error) {
54
+ console.error('Login failed:', error);
55
+ alert('Failed to start login process. Please try again.');
56
+ }
57
+ };
58
+
59
+ const handleLogout = () => {
60
+ logout();
61
+ apiClient.logout();
62
+ setUserInfo(null);
63
+ // Reload page to clear state
64
+ window.location.reload();
65
+ };
66
+
67
+ const handleDevLogin = () => {
68
+ if (!devUsername.trim()) {
69
+ alert('Please enter a username');
70
+ return;
71
+ }
72
+
73
+ try {
74
+ const result = loginDevMode(devUsername);
75
+ setUserInfo(result.userInfo);
76
+ apiClient.setToken(result.accessToken);
77
+ setShowDevLogin(false);
78
+ setDevUsername('');
79
+ } catch (error) {
80
+ console.error('Dev login failed:', error);
81
+ alert('Failed to login in dev mode');
82
+ }
83
+ };
84
+
85
+ return (
86
+ <header className="bg-[#28282a] text-white border-b border-[#48484a]">
87
+ <div className="flex items-center justify-between px-5 h-14">
88
+ <div className="flex items-center space-x-3">
89
+ <div className="text-2xl">πŸš€</div>
90
+ <h1 className="text-base font-semibold text-[#e5e5e7] tracking-tight">AnyCoder</h1>
91
+ </div>
92
+
93
+ <div className="flex items-center space-x-4">
94
+ {isLoading ? (
95
+ <div className="px-4 py-2">
96
+ <span className="text-xs text-[#86868b] font-medium">Loading...</span>
97
+ </div>
98
+ ) : userInfo ? (
99
+ <div className="flex items-center space-x-3">
100
+ {userInfo.avatarUrl && (
101
+ <img
102
+ src={userInfo.avatarUrl}
103
+ alt={userInfo.name}
104
+ className="w-7 h-7 rounded-full ring-2 ring-[#48484a]"
105
+ />
106
+ )}
107
+ <span className="text-sm text-[#e5e5e7] font-medium">
108
+ {userInfo.preferredUsername || userInfo.name}
109
+ </span>
110
+ <button
111
+ onClick={handleLogout}
112
+ className="px-4 py-2 bg-[#3a3a3c] text-[#e5e5e7] text-xs rounded-lg hover:bg-[#48484a] transition-all border border-[#48484a] font-semibold shadow-sm active:scale-95"
113
+ >
114
+ Logout
115
+ </button>
116
+ </div>
117
+ ) : (
118
+ <div className="flex items-center space-x-3">
119
+ {/* Dev Mode Login (only on localhost) */}
120
+ {isDevMode && (
121
+ <>
122
+ {showDevLogin ? (
123
+ <div className="flex items-center space-x-2 bg-[#3a3a3c] px-3 py-2 rounded-lg border border-[#ff9f0a] shadow-lg">
124
+ <span className="text-xs text-[#ff9f0a] font-semibold">DEV</span>
125
+ <input
126
+ type="text"
127
+ value={devUsername}
128
+ onChange={(e) => setDevUsername(e.target.value)}
129
+ onKeyPress={(e) => e.key === 'Enter' && handleDevLogin()}
130
+ placeholder="username"
131
+ className="px-3 py-1.5 rounded-lg text-xs bg-[#2c2c2e] text-[#e5e5e7] border border-[#48484a] focus:outline-none focus:ring-2 focus:ring-[#ff9f0a] focus:border-transparent w-28 font-medium"
132
+ autoFocus
133
+ />
134
+ <button
135
+ onClick={handleDevLogin}
136
+ className="px-3 py-1.5 bg-[#ff9f0a] text-white rounded-lg hover:bg-[#ff8800] text-xs font-semibold shadow-sm active:scale-95"
137
+ >
138
+ OK
139
+ </button>
140
+ <button
141
+ onClick={() => {
142
+ setShowDevLogin(false);
143
+ setDevUsername('');
144
+ }}
145
+ className="text-[#86868b] hover:text-[#e5e5e7] text-sm transition-colors"
146
+ >
147
+ βœ•
148
+ </button>
149
+ </div>
150
+ ) : (
151
+ <button
152
+ onClick={() => setShowDevLogin(true)}
153
+ className="px-4 py-2 bg-[#ff9f0a] text-white rounded-lg hover:bg-[#ff8800] transition-all text-xs flex items-center space-x-2 font-semibold shadow-sm active:scale-95"
154
+ title="Dev Mode (localhost)"
155
+ >
156
+ <span>πŸ”§</span>
157
+ <span>Dev Login</span>
158
+ </button>
159
+ )}
160
+ <span className="text-[#86868b] text-xs font-medium">or</span>
161
+ </>
162
+ )}
163
+
164
+ {/* OAuth Login */}
165
+ <button
166
+ onClick={handleLogin}
167
+ className="px-4 py-2 bg-[#007aff] text-white rounded-lg hover:bg-[#0051d5] transition-all text-xs flex items-center space-x-2 font-semibold shadow-md active:scale-95"
168
+ >
169
+ <span>πŸ€—</span>
170
+ <span>Sign in</span>
171
+ </button>
172
+ </div>
173
+ )}
174
+ </div>
175
+ </div>
176
+ </header>
177
+ );
178
+ }
179
+
frontend/src/types/index.ts ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Type definitions for AnyCoder frontend
2
+
3
+ export interface Model {
4
+ name: string;
5
+ id: string;
6
+ description: string;
7
+ }
8
+
9
+ export interface Message {
10
+ role: 'user' | 'assistant' | 'system';
11
+ content: string;
12
+ timestamp?: string;
13
+ }
14
+
15
+ export interface CodeGenerationRequest {
16
+ query: string;
17
+ language: string;
18
+ model_id: string;
19
+ provider: string;
20
+ history: string[][];
21
+ agent_mode: boolean;
22
+ }
23
+
24
+ export interface CodeGenerationResponse {
25
+ code: string;
26
+ history: string[][];
27
+ status: string;
28
+ }
29
+
30
+ export interface StreamChunk {
31
+ type: 'chunk' | 'complete' | 'error' | 'status';
32
+ content?: string;
33
+ code?: string;
34
+ message?: string;
35
+ progress?: number;
36
+ timestamp?: string;
37
+ }
38
+
39
+ export interface AuthStatus {
40
+ authenticated: boolean;
41
+ username?: string;
42
+ message: string;
43
+ }
44
+
45
+ export interface DeploymentRequest {
46
+ code: string;
47
+ space_name?: string;
48
+ language: string;
49
+ requirements?: string;
50
+ }
51
+
52
+ export interface DeploymentResponse {
53
+ success: boolean;
54
+ space_url?: string;
55
+ message: string;
56
+ dev_mode?: boolean;
57
+ }
58
+
59
+ export type Language = 'html' | 'gradio' | 'transformers.js' | 'streamlit' | 'comfyui' | 'react';
60
+
frontend/tailwind.config.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ content: [
4
+ './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
5
+ './src/components/**/*.{js,ts,jsx,tsx,mdx}',
6
+ './src/app/**/*.{js,ts,jsx,tsx,mdx}',
7
+ ],
8
+ theme: {
9
+ extend: {
10
+ colors: {
11
+ primary: {
12
+ 50: '#eff6ff',
13
+ 100: '#dbeafe',
14
+ 200: '#bfdbfe',
15
+ 300: '#93c5fd',
16
+ 400: '#60a5fa',
17
+ 500: '#3b82f6',
18
+ 600: '#2563eb',
19
+ 700: '#1d4ed8',
20
+ 800: '#1e40af',
21
+ 900: '#1e3a8a',
22
+ },
23
+ },
24
+ },
25
+ },
26
+ plugins: [],
27
+ darkMode: 'class',
28
+ }
29
+
frontend/tsconfig.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["dom", "dom.iterable", "esnext"],
4
+ "allowJs": true,
5
+ "skipLibCheck": true,
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "esModuleInterop": true,
9
+ "module": "esnext",
10
+ "moduleResolution": "bundler",
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "jsx": "preserve",
14
+ "incremental": true,
15
+ "plugins": [
16
+ {
17
+ "name": "next"
18
+ }
19
+ ],
20
+ "paths": {
21
+ "@/*": ["./src/*"]
22
+ }
23
+ },
24
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25
+ "exclude": ["node_modules"]
26
+ }
27
+
start_backend.sh ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Start the FastAPI backend
3
+
4
+ echo "Starting AnyCoder FastAPI Backend..."
5
+ echo "API will be available at: http://localhost:8000"
6
+ echo "API docs at: http://localhost:8000/docs"
7
+ echo ""
8
+
9
+ # Check if HF_TOKEN is set
10
+ if [ -z "$HF_TOKEN" ]; then
11
+ echo "⚠️ WARNING: HF_TOKEN environment variable is not set!"
12
+ echo "Please set it with: export HF_TOKEN=your_token_here"
13
+ echo ""
14
+ fi
15
+
16
+ # Activate virtual environment
17
+ source /Users/ahsenkhaliq/anycoder/.venv/bin/activate
18
+
19
+ # Start the backend
20
+ python backend_api.py
21
+
start_frontend.sh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Start the Next.js frontend
3
+
4
+ echo "Starting AnyCoder Frontend..."
5
+ echo "Frontend will be available at: http://localhost:3000"
6
+ echo ""
7
+
8
+ cd frontend
9
+
10
+ # Install dependencies if node_modules doesn't exist
11
+ if [ ! -d "node_modules" ]; then
12
+ echo "Installing dependencies..."
13
+ npm install
14
+ fi
15
+
16
+ # Start the development server
17
+ npm run dev
18
+
start_fullstack.sh ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Start both backend and frontend in separate terminal windows
3
+
4
+ echo "πŸš€ Starting AnyCoder Full-Stack Application..."
5
+ echo ""
6
+
7
+ # Function to check if a command exists
8
+ command_exists() {
9
+ command -v "$1" >/dev/null 2>&1
10
+ }
11
+
12
+ # Check for required tools
13
+ if ! command_exists python3; then
14
+ echo "❌ Python 3 is not installed"
15
+ exit 1
16
+ fi
17
+
18
+ if ! command_exists node; then
19
+ echo "❌ Node.js is not installed"
20
+ exit 1
21
+ fi
22
+
23
+ # Make scripts executable
24
+ chmod +x start_backend.sh
25
+ chmod +x start_frontend.sh
26
+
27
+ echo "πŸ“¦ Starting Backend..."
28
+ # Start backend in background with venv activated
29
+ (source /Users/ahsenkhaliq/anycoder/.venv/bin/activate && python backend_api.py) &
30
+ BACKEND_PID=$!
31
+
32
+ # Wait for backend to start
33
+ sleep 3
34
+
35
+ echo ""
36
+ echo "🎨 Starting Frontend..."
37
+ # Start frontend in background
38
+ ./start_frontend.sh &
39
+ FRONTEND_PID=$!
40
+
41
+ echo ""
42
+ echo "βœ… Full-stack application started!"
43
+ echo ""
44
+ echo "πŸ”— Backend API: http://localhost:8000"
45
+ echo "πŸ”— API Docs: http://localhost:8000/docs"
46
+ echo "πŸ”— Frontend: http://localhost:3000"
47
+ echo ""
48
+ echo "Press Ctrl+C to stop both services"
49
+
50
+ # Wait for Ctrl+C
51
+ trap "kill $BACKEND_PID $FRONTEND_PID; exit" INT
52
+ wait
53
+