Skip to content

Commit 0d84f14

Browse files
committed
first commit
0 parents  commit 0d84f14

28 files changed

+3355
-0
lines changed

.dockerignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules
2+
.env
3+
.env.*
4+
!.env.example
5+
*.log
6+
.git
7+
.github
8+
test-*.py
9+
test-*.ps1
10+
README.md
11+
LICENSE

.env

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Server Configuration
2+
PORT=3000
3+
4+
# API Key for authentication (optional)
5+
# If set, clients must include: Authorization: Bearer <your-key>
6+
PROXY_API_KEY=test-api-key
7+
8+
# Qoder Configuration
9+
QODER_API_KEY=pt-6MCYc3Byvf6kHhowqb1z2WxO_019d4e83-a465-77a3-bd91-459b57dc1b5d
10+
QODER_PERSONAL_ACCESS_TOKEN=pt-6MCYc3Byvf6kHhowqb1z2WxO_019d4e83-a465-77a3-bd91-459b57dc1b5d
11+
12+
# Dashboard
13+
DASHBOARD_ENABLED=true
14+
DASHBOARD_PASSWORD=admin
15+
DASHBOARD_SECRET=local-dev-secret-change-in-production
16+

.env.example

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# ─── Server ─────────────────────────────────────────────────────────────────
2+
PORT=3000
3+
4+
# ─── Proxy auth ──────────────────────────────────────────────────────────────
5+
# Required: clients must send Authorization: Bearer <PROXY_API_KEY>
6+
# If not set, the proxy accepts all requests without auth (NOT recommended).
7+
PROXY_API_KEY=your-secret-proxy-key
8+
9+
# ─── Qoder credentials ───────────────────────────────────────────────────────
10+
# Personal Access Token — generate at https://qoder.com/account/integrations
11+
QODER_PERSONAL_ACCESS_TOKEN=your-qoder-pat-here
12+
# QODER_API_KEY= ← legacy alias, still accepted
13+
14+
# ─── Dashboard ───────────────────────────────────────────────────────────────
15+
DASHBOARD_ENABLED=true
16+
# Password to log in to /dashboard/ (required if DASHBOARD_ENABLED=true)
17+
DASHBOARD_PASSWORD=your-dashboard-password
18+
# HMAC secret for signing session cookies. Auto-generated if not set,
19+
# but set it explicitly so sessions survive container restarts.
20+
DASHBOARD_SECRET=change-this-to-a-random-secret
21+
22+
# ─── Public URL ───────────────────────────────────────────────────────────────
23+
# Set this to your deployed URL so the Endpoints page shows the correct base URL.
24+
# If not set, falls back to the incoming request's Host header.
25+
# PUBLIC_BASE_URL=https://your-domain.com
26+
27+
# ─── CORS ─────────────────────────────────────────────────────────────────────
28+
CORS_ORIGIN=*
29+
30+
# ─── Туning ───────────────────────────────────────────────────────────────────
31+
# Max ms before killing a hung qodercli process and returning 504
32+
QODER_TIMEOUT_MS=120000
33+
# Max in-memory log entries (request log + system log each)
34+
LOG_MAX_ENTRIES=500
35+
# Max bytes to capture per request/response payload
36+
LOG_BODY_MAX_BYTES=8192
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Build & Push to GHCR
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE: ghcr.io/foxy1402/qoder-proxy
11+
12+
jobs:
13+
build-push:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Set up QEMU (multi-arch)
24+
uses: docker/setup-qemu-action@v3
25+
26+
- name: Set up Docker Buildx
27+
uses: docker/setup-buildx-action@v3
28+
29+
- name: Login to GHCR
30+
uses: docker/login-action@v3
31+
with:
32+
registry: ${{ env.REGISTRY }}
33+
username: ${{ github.actor }}
34+
password: ${{ secrets.GITHUB_TOKEN }}
35+
36+
- name: Build & push
37+
uses: docker/build-push-action@v5
38+
with:
39+
context: .
40+
platforms: linux/amd64,linux/arm64
41+
push: true
42+
tags: |
43+
${{ env.IMAGE }}:latest
44+
${{ env.IMAGE }}:${{ github.sha }}
45+
cache-from: type=gha
46+
cache-to: type=gha,mode=max

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Node.js
2+
node_modules/
3+
npm-debug.log
4+
yarn-error.log
5+
6+
# System
7+
.DS_Store
8+
Thumbs.db

Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM node:20-alpine
2+
3+
# Install qodercli globally — uses QODER_PERSONAL_ACCESS_TOKEN env var at runtime for auth
4+
RUN npm install -g @qoder-ai/qodercli
5+
6+
WORKDIR /app
7+
8+
# Install production deps first (layer caching)
9+
COPY package*.json ./
10+
RUN npm ci --omit=dev
11+
12+
# Copy source
13+
COPY src/ ./src/
14+
15+
EXPOSE 3000
16+
17+
ENV NODE_ENV=production
18+
19+
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
20+
CMD wget -qO- http://localhost:3000/health || exit 1
21+
22+
CMD ["node", "src/server.js"]

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Qoder AI
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

README.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Qoder OpenAI Proxy
2+
3+
An OpenAI-compatible API wrapper for `qodercli` with built-in dashboard, metrics, and Docker support.
4+
Use Qoder through any tool or library designed for OpenAI's API.
5+
6+
## Features
7+
8+
- **🔌 OpenAI-Compatible**: Drop-in API replacement for apps like Cursor, Cline, LangChain, and Open WebUI
9+
- **💬 Full Chat Support**: Support for `/v1/chat/completions` (system messages, multi-turn history)
10+
- **⚡ Streaming**: Real-time SSE streaming responses without lag
11+
- **🔄 Intelligent Tier Mapping**: Seamless translation between OpenAI aliases (gpt-4, claude-3.5) and Qoder tiers (auto, ultimate, lite)
12+
- **📊 Admin Dashboard**: Built-in dark-themed web dashboard for testing, viewing live logs, and monitoring proxy health
13+
- **🐳 Docker Native**: Zero-persistence RAM-only architecture designed for easy deployment to cloud services via our public GHCR image
14+
15+
---
16+
17+
## 🚀 Quick Start (Docker / Cloud Deployment)
18+
19+
The proxy is containerized and available on the GitHub Container Registry. It runs completely statelessly—no volumes or persistent storage needed. All configuration is done via environment variables.
20+
21+
### Deploying via Docker Run
22+
23+
We expose port `3000` via TCP. Configure your personal tokens securely using environment variables:
24+
25+
```bash
26+
docker run -d \
27+
--name qoder-proxy \
28+
-p 3000:3000 \
29+
-e QODER_PERSONAL_ACCESS_TOKEN="your-qoder-pat" \
30+
-e PROXY_API_KEY="your-secret-custom-key" \
31+
-e DASHBOARD_PASSWORD="secure-dashboard-password" \
32+
ghcr.io/foxy1402/qoder-proxy:latest
33+
```
34+
35+
### Environment Variables
36+
37+
| Variable | Description | Required | Profile/Type |
38+
|---|---|---|---|
39+
| `QODER_PERSONAL_ACCESS_TOKEN` | Your Personal Access Token from [Qoder Integrations](https://qoder.com/account/integrations) | **Yes** | Secret |
40+
| `PROXY_API_KEY` | The secret key *you* choose to protect the `/v1` API from outside internet requests | **Yes*** | Secret (Bearer Token) |
41+
| `DASHBOARD_PASSWORD` | Password to access the web UI at `/dashboard/` | **Yes*** | Secret |
42+
| `PORT` | Container internal TCP port | No | Defaults to `3000` |
43+
| `DASHBOARD_ENABLED`| Set to `false` to disable the web UI | No | Defaults to `true` |
44+
| `CORS_ORIGIN` | Allowed domains for web clients calling the API | No | Defaults to `*` |
45+
| `QODER_TIMEOUT_MS`| Maximum request timeout | No | Defaults to `120000` (2 min) |
46+
47+
*\* Highly recommended when running on the public internet.*
48+
49+
---
50+
51+
## 🌐 The Admin Dashboard
52+
53+
The built-in web dashboard provides full observability into what your proxy is doing. Access it at `http://your-server-ip:3000/dashboard/`.
54+
55+
1. **Endpoints**: Get quick copy-paste snippets for integrating tools.
56+
2. **Playground**: Test the API live in your browser and swap between available models.
57+
3. **Request Logs**: Inspect live incoming requests, view request payloads, duration, HTTP status, and assembled response text.
58+
4. **System Logs**: View background system errors from `qodercli`.
59+
60+
*Note: All logs are stored securely in RAM and are completely erased whenever the Docker container restarts.*
61+
62+
---
63+
64+
## 🤖 Model Intelligence & Mapping
65+
66+
The proxy dynamically understands standard OpenAI names and routes them intelligently to your permitted Qoder tiers.
67+
68+
| OpenAI / Anthropic Alias | Routes To Qoder Tier |
69+
|---|---|
70+
| `gpt-4`, `gpt-4o`, `claude-3.5-sonnet` | `auto` |
71+
| `o1`, `claude-3-opus` | `ultimate` |
72+
| `o1-mini`, `o3-mini`, `claude-3-sonnet`| `performance` |
73+
| `claude-3.5-haiku`, `gemini-flash` | `efficient` |
74+
| `gpt-3.5-turbo`, `gpt-4o-mini`, `claude-3-haiku` | `lite` |
75+
| *(New frontier models)* `qwen`, `kimi`, `glm`| Respective custom identifier (`qmodel`, `kmodel`, etc.) |
76+
77+
---
78+
79+
## 🛠 Usage Examples
80+
81+
Once deployed, copy your host URL (e.g. `http://localhost:3000/v1` or `https://my-proxy.com/v1`) into any app that takes OpenAI-style endpoints, and set the API Key to whatever you defined as `PROXY_API_KEY`.
82+
83+
### Python (OpenAI SDK)
84+
85+
```python
86+
from openai import OpenAI
87+
88+
client = OpenAI(
89+
base_url="http://localhost:3000/v1",
90+
api_key="your-secret-custom-key"
91+
)
92+
93+
stream = client.chat.completions.create(
94+
model="gpt-4o", # The proxy will map this to the 'auto' tier
95+
messages=[{"role": "user", "content": "Hello!"}],
96+
stream=True
97+
)
98+
99+
for chunk in stream:
100+
if chunk.choices[0].delta.content:
101+
print(chunk.choices[0].delta.content, end="", flush=True)
102+
```
103+
104+
### Direct HTTP (cURL)
105+
106+
```bash
107+
curl http://localhost:3000/v1/chat/completions \
108+
-H "Content-Type: application/json" \
109+
-H "Authorization: Bearer your-secret-custom-key" \
110+
-d '{
111+
"model": "claude-3.5-sonnet",
112+
"messages": [
113+
{"role": "system", "content": "You are a helpful assistant."},
114+
{"role": "user", "content": "Hello!"}
115+
],
116+
"stream": false
117+
}'
118+
```
119+
120+
## ⚠️ Limitations
121+
- **Embeddings**: Qoder does not support embeddings. Calling `/v1/embeddings` securely returns a `501 Not Implemented`.
122+
- **Token usage limits**: Request token tracking / `usage` payload properties return `null`.
123+
- **Function calling**: Not implemented by the Qoder CLI wrapper yet.
124+
125+
## License
126+
MIT

0 commit comments

Comments
 (0)