freellmapikey 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +528 -0
- package/bin/cli.mjs +68 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tashfeen Ahmed
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# FreeLLMAPIKey
|
|
4
|
+
|
|
5
|
+
**One OpenAI-compatible endpoint. 18 integrated providers. ~1B+ tokens per month.**
|
|
6
|
+
|
|
7
|
+
> **Fork notice:** This repo is **FreeLLMAPIKey** (`freellmapikey`), a renamed fork of [FreeLLMAPI](https://github.com/tashfeenahmed/freellmapi) by [Tashfeen Ahmed](https://github.com/tashfeenahmed). See [CREDITS.md](./CREDITS.md).
|
|
8
|
+
|
|
9
|
+
Aggregate the free tiers from Google, Groq, Cerebras, SambaNova, NVIDIA, Mistral, OpenRouter, GitHub Models, Cohere, Cloudflare, Hugging Face, Together AI, Z.ai (Zhipu), and AWS Bedrock behind a single `/v1/chat/completions` endpoint. Keys are stored encrypted. A router picks the best available model for each request, falls over to the next provider when one is rate-limited, and tracks per-key usage so you stay under every free-tier cap.
|
|
10
|
+
|
|
11
|
+
[](https://github.com/nalepy/freellmapikey/actions/workflows/ci.yml)
|
|
12
|
+
[](./LICENSE)
|
|
13
|
+
[](#contributing)
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Credits
|
|
22
|
+
|
|
23
|
+
FreeLLMAPIKey is based on [**FreeLLMAPI**](https://github.com/tashfeenahmed/freellmapi) by [**Tashfeen Ahmed**](https://github.com/tashfeenahmed). This fork uses the name **freellmapikey** so it is not confused with the upstream repository. Full attribution: [CREDITS.md](./CREDITS.md).
|
|
24
|
+
|
|
25
|
+
## Contents
|
|
26
|
+
|
|
27
|
+
- [Credits](#credits)
|
|
28
|
+
- [Why this exists](#why-this-exists)
|
|
29
|
+
- [Supported providers](#supported-providers)
|
|
30
|
+
- [Features](#features)
|
|
31
|
+
- [Not yet supported](#not-yet-supported)
|
|
32
|
+
- [Quick start](#quick-start)
|
|
33
|
+
- [Using the API](#using-the-api)
|
|
34
|
+
- [Chat completions](#chat-completions)
|
|
35
|
+
- [Embeddings](#embeddings)
|
|
36
|
+
- [Screenshots](#screenshots)
|
|
37
|
+
- [How it works](#how-it-works)
|
|
38
|
+
- [Limitations](#limitations)
|
|
39
|
+
- [Contributing](#contributing)
|
|
40
|
+
- [Terms of Service review](#terms-of-service-review)
|
|
41
|
+
- [Disclaimer](#disclaimer)
|
|
42
|
+
|
|
43
|
+
## Why this exists
|
|
44
|
+
|
|
45
|
+
Every serious AI lab now offers a free tier — a few million tokens a month, a few thousand requests a day. On its own each tier is a toy. Stacked together, they add up to roughly **1.3 billion tokens per month** of working inference capacity, across dozens of models from small-and-fast to reasonably capable.
|
|
46
|
+
|
|
47
|
+
The problem is that stacking them by hand is painful: many different SDKs, rate limits, and failure modes per vendor. FreeLLMAPIKey collapses that into one OpenAI-compatible endpoint. Point any OpenAI client library at your local server, and it routes transparently across whichever providers you've added keys for.
|
|
48
|
+
|
|
49
|
+
## Supported providers
|
|
50
|
+
|
|
51
|
+
<table>
|
|
52
|
+
<tr>
|
|
53
|
+
<td align="center" width="180"><a href="https://ai.google.dev"><b>Google</b><br/>Gemini 2.5 Flash · 3.x previews</a></td>
|
|
54
|
+
<td align="center" width="180"><a href="https://groq.com"><b>Groq</b><br/>Llama 3.3, Llama 4, GPT-OSS, Qwen3</a></td>
|
|
55
|
+
<td align="center" width="180"><a href="https://cerebras.ai"><b>Cerebras</b><br/>Qwen3 235B</a></td>
|
|
56
|
+
<td align="center" width="180"><a href="https://cloud.sambanova.ai"><b>SambaNova</b><br/>DeepSeek V3.x · Llama 4 · Gemma 3</a></td>
|
|
57
|
+
</tr>
|
|
58
|
+
<tr>
|
|
59
|
+
<td align="center"><a href="https://mistral.ai"><b>Mistral</b><br/>Large 3 · Medium 3.5 · Codestral · Devstral</a></td>
|
|
60
|
+
<td align="center"><a href="https://openrouter.ai"><b>OpenRouter</b><br/>19 free-tier models</a></td>
|
|
61
|
+
<td align="center"><a href="https://github.com/marketplace/models"><b>GitHub Models</b><br/>GPT-4.1 · GPT-4o</a></td>
|
|
62
|
+
<td align="center"><a href="https://developers.cloudflare.com/workers-ai"><b>Cloudflare</b><br/>Kimi K2 · GLM-4.7 · GPT-OSS · Granite 4</a></td>
|
|
63
|
+
</tr>
|
|
64
|
+
<tr>
|
|
65
|
+
<td align="center"><a href="https://cohere.com"><b>Cohere</b><br/>Command R+ · Command-A (trial)</a></td>
|
|
66
|
+
<td align="center"><a href="https://huggingface.co/docs/inference-providers"><b>Hugging Face</b><br/>GPT-OSS · Llama 3.1/3.3 (router)</a></td>
|
|
67
|
+
<td align="center"><a href="https://docs.together.ai"><b>Together AI</b><br/>GPT-OSS 20B · Llama 3.1/3.3 Turbo</a></td>
|
|
68
|
+
<td align="center"><a href="https://docs.z.ai"><b>Z.ai (Zhipu)</b><br/>GLM-4.5 · GLM-4.7 Flash</a></td>
|
|
69
|
+
</tr>
|
|
70
|
+
<tr>
|
|
71
|
+
<td align="center"><a href="https://build.nvidia.com"><b>NVIDIA</b><br/>NIM (disabled by default)</a></td>
|
|
72
|
+
<td align="center"><a href="https://docs.aws.amazon.com/bedrock/latest/userguide/inference-chat-completions-mantle.html"><b>AWS Bedrock</b><br/>Claude · GPT-OSS (IAM or API key)</a></td>
|
|
73
|
+
<td colspan="2" align="center"><i>Adding another? See <a href="#contributing">Contributing</a>.</i></td>
|
|
74
|
+
</tr>
|
|
75
|
+
</table>
|
|
76
|
+
|
|
77
|
+
## Features
|
|
78
|
+
|
|
79
|
+
- **OpenAI-compatible** — `POST /v1/chat/completions` and `GET /v1/models` work with the official OpenAI SDKs and any OpenAI-compatible client (LangChain, LlamaIndex, Continue, Hermes, etc.). Just change `base_url`.
|
|
80
|
+
- **Embeddings** — `POST /v1/embeddings` routes through Google (`text-embedding-004`, 768 dims, 1500 RPM free) and Mistral (`mistral-embed`, 1024 dims) with the same auto-fallback logic as chat. Works with `model: "auto"` or a specific model name. OpenAI-compatible response shape.
|
|
81
|
+
- **Responses API (Codex)** — `POST /v1/responses` with streaming SSE; **Guides** walk through local Codex `config.toml` and factory rollback.
|
|
82
|
+
- **Anthropic-compatible** — `POST /v1/messages` and `POST /v1/messages/count_tokens` for Claude Code CLI; **Guides** include local `ANTHROPIC_BASE_URL` setup and factory restore.
|
|
83
|
+
- **Streaming and non-streaming** — Server-Sent Events for `stream: true`, JSON response otherwise. Every provider adapter implements both.
|
|
84
|
+
- **Tool calling** — OpenAI-style `tools` / `tool_choice` requests are passed through, and assistant `tool_calls` + `tool` role follow-up messages round-trip across providers.
|
|
85
|
+
- **Vision (Codex & chat)** — Pasted images in Codex (`input_image` on `/v1/responses`) and multimodal user messages on `/v1/chat/completions` are routed to vision-capable models (Gemini, Llama 4, etc.); text-only backends are skipped when images are present.
|
|
86
|
+
- **Automatic fallover** — If the chosen provider returns a 429, 5xx, or times out, the router skips it, puts the key on a short cooldown, and retries on the next model in your fallback chain (up to 20 attempts).
|
|
87
|
+
- **Per-key rate tracking** — RPM, RPD, TPM, and TPD counters per `(platform, model, key)` so the router always picks a key that's under its caps.
|
|
88
|
+
- **Sticky sessions** — Multi-turn conversations keep talking to the same model for 30 minutes to avoid the hallucination spike that comes from mid-conversation model switches.
|
|
89
|
+
- **Encrypted key storage** — API keys are encrypted with AES-256-GCM before hitting SQLite; decryption happens in-memory just before a request.
|
|
90
|
+
- **Unified API key** — Clients authenticate to your proxy with a single `freellmapikey-…` bearer token. You never expose upstream provider keys to your apps.
|
|
91
|
+
- **Health checks** — Periodic probes mark keys as `healthy`, `rate_limited`, `invalid`, or `error` so the router skips dead ones automatically.
|
|
92
|
+
- **Admin dashboard** — React + Vite UI to manage keys, reorder the fallback chain, inspect analytics, and run prompts in a playground. Dark mode included.
|
|
93
|
+
- **Analytics** — Per-request logging with latency, token counts, success rate, per-provider breakdowns, a **usage log** (timestamped successful routes), and a persistent **error log** for failures.
|
|
94
|
+
- **Deploys to a Raspberry Pi** — Runs happily on a Pi 4 under PM2 behind nginx. ~40 MB RSS at idle.
|
|
95
|
+
|
|
96
|
+
## Not yet supported
|
|
97
|
+
|
|
98
|
+
The scope is deliberately narrow. If a feature isn't on this list and isn't below, assume it isn't there yet.
|
|
99
|
+
|
|
100
|
+
- **Image generation** (`/v1/images/*`)
|
|
101
|
+
- **Audio / speech** (`/v1/audio/*`)
|
|
102
|
+
- **Legacy completions** (`/v1/completions`) — only the chat endpoint is implemented
|
|
103
|
+
- **Moderation** (`/v1/moderations`)
|
|
104
|
+
- **`n > 1`** (multiple completions per request)
|
|
105
|
+
- **Per-user billing / multi-tenant auth** — single-user by design
|
|
106
|
+
|
|
107
|
+
PRs that add any of these are very welcome. See [Contributing](#contributing).
|
|
108
|
+
|
|
109
|
+
## Quick start
|
|
110
|
+
|
|
111
|
+
**Option A — zero-config npx (no git clone needed)**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npx freellmapikey
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The CLI clones the repo into `~/.freellmapikey`, runs `npm install && npm run build`, and starts the server on `:3001`. On subsequent runs it skips setup and goes straight to start. Subcommands: `setup`, `start`, `update`.
|
|
118
|
+
|
|
119
|
+
**Option B — clone and run**
|
|
120
|
+
|
|
121
|
+
**Prerequisites:** Node.js 20+, npm.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
git clone https://github.com/nalepy/freellmapikey.git
|
|
125
|
+
cd freellmapikey
|
|
126
|
+
npm install
|
|
127
|
+
|
|
128
|
+
# Generate an encryption key for at-rest key storage
|
|
129
|
+
cp .env.example .env
|
|
130
|
+
echo "ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")" >> .env
|
|
131
|
+
|
|
132
|
+
# Start server + dashboard together
|
|
133
|
+
npm run dev
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Open http://localhost:5173 (the Vite dev UI), add your provider keys on the **Keys** page, reorder the **Fallback Chain** to taste, and grab your unified API key from **Keys** or **Guides**. Use **Guides** for VS Code (Continue, Cline), Claude Code CLI, Codex, and OpenAI-compatible clients — each integration has **configure local proxy** and **restore factory** sections where relevant.
|
|
137
|
+
|
|
138
|
+
**Hugging Face, Together AI & AWS Bedrock**
|
|
139
|
+
|
|
140
|
+
| Provider | Where to get a key | Notes |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| Hugging Face | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) | Create a token with **Inference Providers** permission (`hf_…`). Routed via `https://router.huggingface.co/v1`. |
|
|
143
|
+
| Together AI | [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) | Prepaid credits (often a $5 minimum top-up). OpenAI-compatible serverless models. |
|
|
144
|
+
| AWS Bedrock | [Bedrock console → API keys](https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html) or IAM | On the **Keys** page: **Region** + **Access Key ID** + **Secret Access Key** (same as Cursor), *or* Region + a **Bedrock API key** (`ABSK…`) with Access Key ID left empty. IAM uses SigV4 on `bedrock-runtime`; API keys use Bearer on `bedrock-mantle`. Enable model access in your region; billed via AWS (credits / on-demand), not a standing free tier. |
|
|
145
|
+
|
|
146
|
+
For a production build:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm run build
|
|
150
|
+
node server/dist/index.js # server + dashboard both served on :3001
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Using the API
|
|
154
|
+
|
|
155
|
+
Any OpenAI-compatible client works. Examples:
|
|
156
|
+
|
|
157
|
+
### Chat completions
|
|
158
|
+
|
|
159
|
+
**Python**
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from openai import OpenAI
|
|
163
|
+
|
|
164
|
+
client = OpenAI(
|
|
165
|
+
base_url="http://localhost:3001/v1",
|
|
166
|
+
api_key="freellmapikey-your-unified-key",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
resp = client.chat.completions.create(
|
|
170
|
+
model="auto", # let the router pick; or specify e.g. "gemini-2.5-flash"
|
|
171
|
+
messages=[{"role": "user", "content": "Summarise the fall of Rome in one sentence."}],
|
|
172
|
+
)
|
|
173
|
+
print(resp.choices[0].message.content)
|
|
174
|
+
print("Routed via:", resp.headers.get("x-routed-via"))
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**curl**
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
curl http://localhost:3001/v1/chat/completions \
|
|
181
|
+
-H "Authorization: Bearer freellmapikey-your-unified-key" \
|
|
182
|
+
-H "Content-Type: application/json" \
|
|
183
|
+
-d '{
|
|
184
|
+
"model": "auto",
|
|
185
|
+
"messages": [{"role": "user", "content": "hi"}]
|
|
186
|
+
}'
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Streaming**
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
stream = client.chat.completions.create(
|
|
193
|
+
model="auto",
|
|
194
|
+
messages=[{"role": "user", "content": "Stream me a haiku about SQLite."}],
|
|
195
|
+
stream=True,
|
|
196
|
+
)
|
|
197
|
+
for chunk in stream:
|
|
198
|
+
print(chunk.choices[0].delta.content or "", end="", flush=True)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Tool calling**
|
|
202
|
+
|
|
203
|
+
Pass OpenAI-style `tools` and `tool_choice`; the assistant response round-trips back through the proxy exactly like the OpenAI API. Multi-step flows (assistant `tool_calls` → `tool` role follow-up → final answer) work across every provider the router can reach.
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
tools = [{
|
|
207
|
+
"type": "function",
|
|
208
|
+
"function": {
|
|
209
|
+
"name": "get_weather",
|
|
210
|
+
"description": "Get current weather for a city.",
|
|
211
|
+
"parameters": {
|
|
212
|
+
"type": "object",
|
|
213
|
+
"properties": {"city": {"type": "string"}},
|
|
214
|
+
"required": ["city"],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
}]
|
|
218
|
+
|
|
219
|
+
# 1. Model asks for a tool call
|
|
220
|
+
first = client.chat.completions.create(
|
|
221
|
+
model="auto",
|
|
222
|
+
messages=[{"role": "user", "content": "What's the weather in Karachi?"}],
|
|
223
|
+
tools=tools,
|
|
224
|
+
tool_choice="required",
|
|
225
|
+
)
|
|
226
|
+
call = first.choices[0].message.tool_calls[0]
|
|
227
|
+
|
|
228
|
+
# 2. You execute the tool, feed the result back
|
|
229
|
+
final = client.chat.completions.create(
|
|
230
|
+
model="auto",
|
|
231
|
+
messages=[
|
|
232
|
+
{"role": "user", "content": "What's the weather in Karachi?"},
|
|
233
|
+
first.choices[0].message,
|
|
234
|
+
{"role": "tool", "tool_call_id": call.id, "content": '{"temp_c": 32, "cond": "sunny"}'},
|
|
235
|
+
],
|
|
236
|
+
tools=tools,
|
|
237
|
+
)
|
|
238
|
+
print(final.choices[0].message.content)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Works with `stream=True` as well — you'll get `delta.tool_calls` chunks followed by a `finish_reason: "tool_calls"` close. Under the hood, OpenAI-compatible providers (Groq, Cerebras, SambaNova, Mistral, OpenRouter, GitHub Models, Hugging Face, Together AI, Cloudflare, AWS Bedrock, Cohere compat) get the request passed through; Gemini requests get translated into Google's `functionDeclarations` / `functionResponse` shape and the response is translated back.
|
|
242
|
+
|
|
243
|
+
Every response carries an `X-Routed-Via: <platform>/<model>` header so you can see which provider actually served each call. If a request fell over between providers, you'll also see `X-Fallback-Attempts: N`.
|
|
244
|
+
|
|
245
|
+
### Embeddings
|
|
246
|
+
|
|
247
|
+
`POST /v1/embeddings` — OpenAI-compatible. Routes through Google (`text-embedding-004`, 768 dims) and Mistral (`mistral-embed`, 1024 dims). Add a Google AI Studio key and/or a Mistral key on the **Keys** page to enable it.
|
|
248
|
+
|
|
249
|
+
| Model | Platform | Dims | Free limit |
|
|
250
|
+
|---|---|---|---|
|
|
251
|
+
| `text-embedding-004` | Google | 768 | 1500 RPM, ~1M chars/day |
|
|
252
|
+
| `text-multilingual-embedding-002` | Google | 768 | 1500 RPM, ~1M chars/day |
|
|
253
|
+
| `mistral-embed` | Mistral | 1024 | 2 RPM, 500k TPM (experiment tier) |
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
from openai import OpenAI
|
|
257
|
+
|
|
258
|
+
client = OpenAI(
|
|
259
|
+
base_url="http://localhost:3001/v1",
|
|
260
|
+
api_key="freellmapikey-your-unified-key",
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Single string — routed to Google text-embedding-004 by default
|
|
264
|
+
resp = client.embeddings.create(model="auto", input="Hello, world")
|
|
265
|
+
print(len(resp.data[0].embedding)) # 768
|
|
266
|
+
|
|
267
|
+
# Batch
|
|
268
|
+
resp = client.embeddings.create(
|
|
269
|
+
model="text-embedding-004",
|
|
270
|
+
input=["first doc", "second doc"],
|
|
271
|
+
)
|
|
272
|
+
for item in resp.data:
|
|
273
|
+
print(item.index, len(item.embedding))
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
curl http://localhost:3001/v1/embeddings \
|
|
278
|
+
-H "Authorization: Bearer freellmapikey-your-unified-key" \
|
|
279
|
+
-H "Content-Type: application/json" \
|
|
280
|
+
-d '{"model": "auto", "input": "Hello, world"}'
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Routing priority: `model="auto"` (or omitted) tries Google first, then Mistral. A specific Google model name (`text-embedding-*`, `text-multilingual-*`) goes straight to Google; `mistral-embed` goes straight to Mistral. If the first provider has no healthy key or is on cooldown after a 429, the route falls through to the next one automatically.
|
|
284
|
+
|
|
285
|
+
**Claude Code (CLI — local proxy or factory)**
|
|
286
|
+
|
|
287
|
+
The **Guides** tab documents both setups. **CLI only** — Claude Desktop cannot override `ANTHROPIC_BASE_URL`.
|
|
288
|
+
|
|
289
|
+
*Configure local proxy* (terminal `claude` command):
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
export ANTHROPIC_BASE_URL="http://localhost:3001"
|
|
293
|
+
export ANTHROPIC_API_KEY="freellmapikey-your-unified-key-from-dashboard"
|
|
294
|
+
claude
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
```powershell
|
|
298
|
+
$env:ANTHROPIC_BASE_URL = "http://localhost:3001"
|
|
299
|
+
$env:ANTHROPIC_API_KEY = "freellmapikey-your-unified-key-from-dashboard"
|
|
300
|
+
claude
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Optional `~/.claude/settings.json` (or `%USERPROFILE%\.claude\settings.json` on Windows) with the same `env` keys. If you see a claude.ai token conflict, run `/logout` in the CLI first. Test with `Reply with exactly: freellmapikey-OK` and confirm **Analytics → Usage log**.
|
|
304
|
+
|
|
305
|
+
*Restore factory* Anthropic routing: unset `ANTHROPIC_BASE_URL` and remove the FreeLLMAPIKey value from `ANTHROPIC_API_KEY` / `settings.json` `env`, then use Anthropic or claude.ai sign-in as usual. Usage log should stay empty for Claude when traffic is off the proxy.
|
|
306
|
+
|
|
307
|
+
**Continue (VS Code)**
|
|
308
|
+
|
|
309
|
+
The [Continue](https://marketplace.visualstudio.com/items?itemName=Continue.continue) extension uses OpenAI Chat Completions. Point it at FreeLLMAPIKey with `provider: openai` and `apiBase` set to your local `/v1` URL (this repo recommends the extension in `.vscode/extensions.json`).
|
|
310
|
+
|
|
311
|
+
1. Start FreeLLMAPIKey and add provider keys on the **Keys** page.
|
|
312
|
+
2. Copy your unified key (`freellmapikey-…`).
|
|
313
|
+
3. Edit Continue config: VS Code → Continue chat → configs dropdown (top right) → cog beside **Local Config**, or open the file directly:
|
|
314
|
+
- Windows: `%USERPROFILE%\.continue\config.yaml`
|
|
315
|
+
- macOS / Linux: `~/.continue/config.yaml`
|
|
316
|
+
4. Add FreeLLMAPIKey to `config.yaml` (see below), save, and reload the VS Code window if the model does not appear (`Developer: Reload Window`). Select **FreeLLMAPIKey** in Continue’s model/config dropdown before chatting.
|
|
317
|
+
|
|
318
|
+
**Already have a Continue config?** Do **not** replace the whole file. Keep your existing top-level `name`, `version`, `schema`, `context`, `rules`, and other `models` entries. Append **one new list item** under `models:` (there must be only one `models:` key in the file). Replace the entire file only if you want FreeLLMAPIKey as your sole model.
|
|
319
|
+
|
|
320
|
+
*Existing config — append under `models:`:*
|
|
321
|
+
|
|
322
|
+
```yaml
|
|
323
|
+
- name: FreeLLMAPIKey
|
|
324
|
+
provider: openai
|
|
325
|
+
model: auto
|
|
326
|
+
apiBase: http://localhost:3001/v1
|
|
327
|
+
apiKey: freellmapikey-your-unified-key-from-dashboard
|
|
328
|
+
roles:
|
|
329
|
+
- chat
|
|
330
|
+
- edit
|
|
331
|
+
- apply
|
|
332
|
+
capabilities:
|
|
333
|
+
- tool_use
|
|
334
|
+
defaultCompletionOptions:
|
|
335
|
+
temperature: 0.7
|
|
336
|
+
maxTokens: 4096
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
*New install — full `config.yaml`:*
|
|
340
|
+
|
|
341
|
+
```yaml
|
|
342
|
+
name: FreeLLMAPIKey (local)
|
|
343
|
+
version: 1.0.0
|
|
344
|
+
schema: v1
|
|
345
|
+
models:
|
|
346
|
+
- name: FreeLLMAPIKey
|
|
347
|
+
provider: openai
|
|
348
|
+
model: auto
|
|
349
|
+
apiBase: http://localhost:3001/v1
|
|
350
|
+
apiKey: freellmapikey-your-unified-key-from-dashboard
|
|
351
|
+
roles:
|
|
352
|
+
- chat
|
|
353
|
+
- edit
|
|
354
|
+
- apply
|
|
355
|
+
capabilities:
|
|
356
|
+
- tool_use
|
|
357
|
+
defaultCompletionOptions:
|
|
358
|
+
temperature: 0.7
|
|
359
|
+
maxTokens: 4096
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Use `model: auto` to follow your dashboard fallback chain, or a slug from `GET http://localhost:3001/v1/models` (e.g. `gemini-2.5-flash`). `tool_use` enables Continue Agent mode when the routed backend supports tools. Verify with a short chat message, then check **Analytics → Usage log** for a new row (`x-routed-via` on HTTP responses shows the actual provider). Continue does not use Codex’s `/v1/responses` or Claude’s `/v1/messages`. See the [config.yaml reference](https://docs.continue.dev/reference/) and the copy-paste blocks on the dashboard **Guides** tab.
|
|
363
|
+
|
|
364
|
+
**Cline (VS Code)**
|
|
365
|
+
|
|
366
|
+
The [Cline](https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev) extension (also in `.vscode/extensions.json`) uses an **OpenAI Compatible** provider and `POST /v1/chat/completions` with tool calling for its agent loop.
|
|
367
|
+
|
|
368
|
+
1. Start FreeLLMAPIKey and add provider keys on the **Keys** page.
|
|
369
|
+
2. Copy your unified key (`freellmapikey-…`).
|
|
370
|
+
3. Open the Cline panel → **Settings** (gear) → set **API Provider** to **OpenAI Compatible**.
|
|
371
|
+
4. Set **Base URL** to `http://localhost:3001/v1`, **API Key** to your unified key, and **Model ID** to `auto` (or a slug from `GET http://localhost:3001/v1/models`).
|
|
372
|
+
5. Use **Verify** if offered, send a test message, then check **Analytics → Usage log**.
|
|
373
|
+
|
|
374
|
+
If Plan and Act modes show separate model fields, set both to `auto` or the same slug. Docs: [OpenAI Compatible provider](https://docs.cline.bot/provider-config/openai-compatible). Full steps are on the dashboard **Guides** tab.
|
|
375
|
+
|
|
376
|
+
**OpenAI Codex (local proxy or factory)**
|
|
377
|
+
|
|
378
|
+
*Configure local proxy:* set `CUSTOM_API_KEY` to your unified key, then edit `~/.codex/config.toml` (Codex → Settings → Open config.toml):
|
|
379
|
+
|
|
380
|
+
```toml
|
|
381
|
+
model_provider = "freellmapikey"
|
|
382
|
+
model = "auto"
|
|
383
|
+
|
|
384
|
+
[model_providers.freellmapikey]
|
|
385
|
+
name = "FreeLLMAPIKey (local)"
|
|
386
|
+
base_url = "http://localhost:3001/v1"
|
|
387
|
+
env_key = "CUSTOM_API_KEY"
|
|
388
|
+
wire_api = "responses"
|
|
389
|
+
requires_openai_auth = false
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Optional: sync `~/.codex/freellmapikey-models.json` from the dashboard **Guides** tab or `npm run codex:model-catalog`. Restart Codex after saving.
|
|
393
|
+
|
|
394
|
+
*Restore factory* OpenAI routing: remove `[model_providers.freellmapikey]`, set `model_provider = "openai"`, unset `CUSTOM_API_KEY`, sign in with OpenAI in Codex, quit and reopen. See [Codex configuration](https://developers.openai.com/codex/config) and the **Guides** tab for full snippets.
|
|
395
|
+
|
|
396
|
+
## Screenshots
|
|
397
|
+
|
|
398
|
+
### Keys
|
|
399
|
+
|
|
400
|
+
Manage provider credentials and grab the unified API key your apps connect with. Each key shows a status dot and when it was last health-checked.
|
|
401
|
+
|
|
402
|
+

|
|
403
|
+
|
|
404
|
+
### Playground
|
|
405
|
+
|
|
406
|
+
Send a chat completion through the router and see which provider served it, with the model ID and latency printed right on the message.
|
|
407
|
+
|
|
408
|
+

|
|
409
|
+
|
|
410
|
+
### Analytics
|
|
411
|
+
|
|
412
|
+
Request volume, success rate, tokens in and out, average latency, and per-provider breakdowns over 24h / 7d / 30d windows.
|
|
413
|
+
|
|
414
|
+
- **Usage log** — Scrollable table of each **successful** routed request (newest first): local timestamp, provider, model, vision flag, input/output tokens, and latency. Use it to confirm Continue, Cline, Playground, or other OpenAI-compatible clients are hitting the proxy. Cleared when you **Reset analytics**.
|
|
415
|
+
- **Error log (debug)** — Detailed failure rows (endpoint, retry, vision flags, full message) plus `server/data/error.log`. Kept when you reset analytics so you can still debug.
|
|
416
|
+
|
|
417
|
+
API: `GET /api/analytics/usage-log?range=7d&limit=100` (same `range` as other analytics endpoints: `24h`, `7d`, `30d`).
|
|
418
|
+
|
|
419
|
+

|
|
420
|
+
|
|
421
|
+
## How it works
|
|
422
|
+
|
|
423
|
+
```
|
|
424
|
+
┌──────────────────┐ Bearer freellmapikey-… ┌─────────────────────────┐
|
|
425
|
+
│ OpenAI SDK / │ ──────────────────────▶ │ Express proxy (:3001) │
|
|
426
|
+
│ curl / any │ ◀────────────────────── │ /v1/chat/completions │
|
|
427
|
+
│ OpenAI client │ streamed tokens └────────────┬────────────┘
|
|
428
|
+
└──────────────────┘ │
|
|
429
|
+
▼
|
|
430
|
+
┌────────────────────────────────────────────────┐
|
|
431
|
+
│ Router │
|
|
432
|
+
│ 1. Pick highest-priority model that │
|
|
433
|
+
│ (a) has a healthy key and │
|
|
434
|
+
│ (b) is under all its rate limits. │
|
|
435
|
+
│ 2. Decrypt key, call provider SDK. │
|
|
436
|
+
│ 3. On 429/5xx → cooldown + retry next model. │
|
|
437
|
+
└────────────────────────────────────────────────┘
|
|
438
|
+
│
|
|
439
|
+
┌──────────────┬────────────┬──────────┴─────────┬─────────────┬──────────┐
|
|
440
|
+
▼ ▼ ▼ ▼ ▼ ▼
|
|
441
|
+
Google Groq Cerebras OpenRouter Hugging Face Together AI Bedrock …more
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
- **Router** (`server/src/services/router.ts`) — picks a model per request.
|
|
445
|
+
- **Rate-limit ledger** (`server/src/services/ratelimit.ts`) — in-memory RPM/RPD/TPM/TPD counters backed by SQLite, with cooldowns on 429s.
|
|
446
|
+
- **Provider adapters** (`server/src/providers/*.ts`) — one file per provider, implementing the `BaseProvider` class: `chatCompletion()`, `streamChatCompletion()`, and optionally `embeddings()`.
|
|
447
|
+
- **Health service** (`server/src/services/health.ts`) — periodic probe keeps key status fresh.
|
|
448
|
+
- **Dashboard** (`client/`) — React + Vite + shadcn/ui admin surface.
|
|
449
|
+
- **Storage** — SQLite (`better-sqlite3`) with AES-256-GCM envelope encryption for keys.
|
|
450
|
+
|
|
451
|
+
## Limitations
|
|
452
|
+
|
|
453
|
+
Stacking free tiers has real trade-offs. Be honest with yourself about them:
|
|
454
|
+
|
|
455
|
+
- **No frontier models.** The free-tier catalog tops out around Llama 3.3 70B, GLM-4.5, Qwen 3 Coder, and Gemini 2.5 Pro. You will not get GPT-5 or Claude Opus class reasoning through this. For hard problems, pay for a real API.
|
|
456
|
+
- **Intelligence degrades as the day progresses.** Your top-ranked models (usually Gemini 2.5 Pro, GPT-4o via GitHub Models) have the lowest daily caps. Once they hit their limits, the router falls down your priority chain to smaller/weaker models. Expect the effective intelligence of the endpoint to drop in the late hours of each day — then reset at UTC midnight.
|
|
457
|
+
- **Latency is highly variable.** Cerebras and Groq are extremely fast; others are not. You get whichever one is available.
|
|
458
|
+
- **Free tiers can change without notice.** Providers regularly tighten, loosen, or remove free tiers. When that happens you'll see 429s or auth errors until you update the catalog. Re-seed scripts live in `server/src/scripts/`.
|
|
459
|
+
- **Credit-based providers.** Hugging Face Inference Providers and Together AI use small prepaid credit pools (not unlimited monthly free RPM like Groq). AWS Bedrock bills through your AWS account (new-account credits or on-demand). Budget rows in the dashboard reflect that.
|
|
460
|
+
- **No SLA, by definition.** If you need reliability, use a paid provider with a contract.
|
|
461
|
+
- **Local-first.** There's no multi-tenant auth. Run this for yourself; don't expose it to the internet.
|
|
462
|
+
|
|
463
|
+
## Contributing
|
|
464
|
+
|
|
465
|
+
Contributors very welcome! Good first PRs:
|
|
466
|
+
|
|
467
|
+
- **Add a provider** — copy `server/src/providers/openai-compat.ts` as a template, wire it into `server/src/providers/index.ts`, seed its models in `server/src/db/index.ts`, add a test in `server/src/__tests__/providers/`.
|
|
468
|
+
- **Add an endpoint** — images, audio, moderations. The provider base class already has `embeddings()` as a model; follow the same pattern for new endpoint types.
|
|
469
|
+
- **Improve the router** — cost-aware routing (cheapest-healthy-fastest tradeoffs), better latency-weighted priority, regional pinning.
|
|
470
|
+
- **Dashboard polish** — charts on the Analytics page, key rotation UX, batch import of keys from `.env`.
|
|
471
|
+
- **Docs** — more examples, client library snippets for Go/Rust/etc., a deployment recipe for Docker or Fly.
|
|
472
|
+
|
|
473
|
+
**Development loop:**
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
npm install
|
|
477
|
+
npm run dev # server on :3001, dashboard on :5173, both with HMR
|
|
478
|
+
npm test # vitest — 75 tests across providers, routes, router, ratelimit
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
PRs should include a test, keep the existing test suite green, and match the `.editorconfig` / tsconfig defaults already in the repo. Issues and discussions are open.
|
|
482
|
+
|
|
483
|
+
### Contributors
|
|
484
|
+
|
|
485
|
+
Thanks to everyone who's helped improve FreeLLMAPIKey:
|
|
486
|
+
|
|
487
|
+
- [@moaaz12-web](https://github.com/moaaz12-web) — tool-calling support across providers (#3)
|
|
488
|
+
- [@lukasulc](https://github.com/lukasulc) — better-sqlite3 bump to fix npm install on Node 24+ (#12)
|
|
489
|
+
- [@VinhPhamAI](https://github.com/VinhPhamAI) — root `.env` PORT now propagates to server + Vite dev proxy + UI base URL (#27)
|
|
490
|
+
- [@deadc](https://github.com/deadc) — preserve Gemini `thoughtSignature` so multi-turn function calling stops 400-ing (#32); router model-first key-exhaustion tests + per-model `limits` hoist (#42)
|
|
491
|
+
- [@zhangyu1324](https://github.com/zhangyu1324) — requested Ollama Cloud integration, now V10 catalog (#14 / #41)
|
|
492
|
+
- [@jtbrennan-git](https://github.com/jtbrennan-git) — security review (#35) and Phase 1 hardening: parameterized analytics queries, sort-preset whitelist, timing-safe API key compare, mid-stream error sanitization
|
|
493
|
+
- [@praveenkumarpranjal](https://github.com/praveenkumarpranjal) — guard Gemini SSE `JSON.parse` so a malformed frame no longer aborts the whole stream, plus first streaming tests for the Google provider (#47)
|
|
494
|
+
|
|
495
|
+
## Terms of Service review
|
|
496
|
+
|
|
497
|
+
A self-hosted, single-user, personal-use setup was re-reviewed against each provider's ToS (May 2026). Summary:
|
|
498
|
+
|
|
499
|
+
| Provider | Verdict | Notes |
|
|
500
|
+
|---|---|---|
|
|
501
|
+
| Google Gemini | ⚠️ Caution | March 2026 ToS narrows scope to *"professional or business purposes, not for consumer use"* — a self-hosted developer proxy is still defensible, but the clause is new. |
|
|
502
|
+
| Groq | ✅ Likely OK | GroqCloud Services Agreement permits Customer Application integration. |
|
|
503
|
+
| Cerebras | ✅ Likely OK | Permitted; explicitly forbids selling/transferring API keys. |
|
|
504
|
+
| Mistral | ✅ Likely OK | APIs allowed for personal/internal business use. |
|
|
505
|
+
| OpenRouter | ✅ Likely OK | April 2026 ToS sharpens the no-resale / no-competing-service clause; private single-user proxy still fine. |
|
|
506
|
+
| SambaNova | ⚠️ Ambiguous | EULA §1.5(c) blocks resale and "service bureau" use; single-user with no third-party access is fine. |
|
|
507
|
+
| Cloudflare Workers AI | ⚠️ Ambiguous | No anti-proxy clause; covered by general Self-Serve Subscription Agreement. |
|
|
508
|
+
| NVIDIA NIM | ⚠️ Caution | Trial ToS §1.2 / §1.4: *"evaluation only, not production."* Disabled in default catalog. |
|
|
509
|
+
| GitHub Models | ⚠️ Caution | Free tier explicitly scoped to *"experimentation"* and *"prototyping."* |
|
|
510
|
+
| Cohere | ❌ Avoid | Terms §14 still forbids *"personal, family or household purposes."* |
|
|
511
|
+
| Zhipu (open.bigmodel.cn) | ✅ Likely OK | Personal/non-commercial research carve-out still in the platform docs. |
|
|
512
|
+
| Z.ai (api.z.ai) | ⚠️ Caution | New row — Singapore entity (distinct from Zhipu CN). §III.3(l) anti-traffic-redirect clause could plausibly be read against a proxy; no explicit personal-use carve-out. |
|
|
513
|
+
| Ollama Cloud | ✅ Likely OK | Free plan permits cloud-model access (1 concurrent, 5-hour session caps). No anti-proxy / anti-resale clauses found. |
|
|
514
|
+
| Hugging Face | ⚠️ Caution | Inference Providers credits (~$0.10/mo free tier); routed via `router.huggingface.co` OpenAI API. Legacy Fireworks-route model removed in V4 (broken tool calls). |
|
|
515
|
+
| Together AI | ⚠️ Caution | Prepaid credits only ($5 minimum purchase since July 2025); signup promos may apply. Serverless API permits customer-application integration. |
|
|
516
|
+
| AWS Bedrock | ⚠️ Caution | Not a recurring free tier — AWS account billing. OpenAI-compatible Chat Completions via [Bedrock Mantle / Runtime](https://docs.aws.amazon.com/bedrock/latest/userguide/inference-chat-completions-mantle.html). Personal proxy use is fine if you comply with AWS Service Terms and enable only models you have rights to invoke. |
|
|
517
|
+
|
|
518
|
+
Rules of thumb that keep most providers happy: **one account per provider**, **no reselling**, **no sharing your endpoint with other humans**, **don't hammer a free tier as a paid production backend**. This is informational, not legal advice — read each provider's ToS and make your own call.
|
|
519
|
+
|
|
520
|
+
Removed from the catalog (April 2026 review): Moonshot and MiniMax direct integrations (Moonshot — paid-only; MiniMax — use OpenRouter `minimax/minimax-m2.5:free`). Hugging Face was re-added in V13 via the Inference Providers router with new model ids (the old Fireworks-route Llama row failed structured tool calls).
|
|
521
|
+
|
|
522
|
+
## Disclaimer
|
|
523
|
+
|
|
524
|
+
**This project is for personal experimentation and learning, not production.** Free tiers exist so developers can prototype against them; they aren't a stable, supported inference substrate and shouldn't be treated as one. If you build something real on top of FreeLLMAPIKey, swap in a paid API before you ship. Your relationship with each upstream provider is governed by the terms you accepted when you created your account — those terms still apply when the traffic is proxied through this project, and you're responsible for complying with them.
|
|
525
|
+
|
|
526
|
+
## License
|
|
527
|
+
|
|
528
|
+
[MIT](./LICENSE)
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FreeLLMAPIKey CLI
|
|
4
|
+
* Usage:
|
|
5
|
+
* npx freellmapikey → setup (if needed) + start
|
|
6
|
+
* npx freellmapikey setup → clone + install + build
|
|
7
|
+
* npx freellmapikey start → start server (must be set up first)
|
|
8
|
+
* npx freellmapikey update → git pull + rebuild
|
|
9
|
+
*/
|
|
10
|
+
import { execSync, spawn } from 'child_process';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { homedir } from 'os';
|
|
14
|
+
|
|
15
|
+
const INSTALL_DIR = join(homedir(), '.freellmapikey');
|
|
16
|
+
const REPO_URL = 'https://github.com/nalepy/freellmapikey.git';
|
|
17
|
+
const SERVER_DIST = join(INSTALL_DIR, 'server', 'dist', 'index.js');
|
|
18
|
+
|
|
19
|
+
const cmd = process.argv[2] ?? 'auto';
|
|
20
|
+
|
|
21
|
+
function run(command, opts = {}) {
|
|
22
|
+
execSync(command, { stdio: 'inherit', ...opts });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isSetUp() {
|
|
26
|
+
return existsSync(SERVER_DIST);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function setup() {
|
|
30
|
+
console.log('\n🔧 FreeLLMAPIKey — setting up in', INSTALL_DIR);
|
|
31
|
+
if (!existsSync(INSTALL_DIR)) {
|
|
32
|
+
run(`git clone ${REPO_URL} "${INSTALL_DIR}"`);
|
|
33
|
+
}
|
|
34
|
+
run('npm install', { cwd: INSTALL_DIR });
|
|
35
|
+
run('npm run build', { cwd: INSTALL_DIR });
|
|
36
|
+
console.log('\n✅ Setup complete!\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function start() {
|
|
40
|
+
if (!isSetUp()) {
|
|
41
|
+
console.error('Not set up. Run: npx freellmapikey setup');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
console.log('\n🚀 FreeLLMAPIKey starting on http://localhost:3001\n');
|
|
45
|
+
const child = spawn(process.execPath, [SERVER_DIST], {
|
|
46
|
+
cwd: INSTALL_DIR,
|
|
47
|
+
stdio: 'inherit',
|
|
48
|
+
env: { ...process.env },
|
|
49
|
+
});
|
|
50
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
51
|
+
process.on('SIGINT', () => child.kill('SIGINT'));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (cmd === 'setup') {
|
|
55
|
+
setup();
|
|
56
|
+
} else if (cmd === 'start') {
|
|
57
|
+
start();
|
|
58
|
+
} else if (cmd === 'update') {
|
|
59
|
+
run(`git -C "${INSTALL_DIR}" pull`);
|
|
60
|
+
run('npm install', { cwd: INSTALL_DIR });
|
|
61
|
+
run('npm run build', { cwd: INSTALL_DIR });
|
|
62
|
+
console.log('\n✅ Updated!\n');
|
|
63
|
+
start();
|
|
64
|
+
} else {
|
|
65
|
+
// auto: setup if needed, then start
|
|
66
|
+
if (!isSetUp()) setup();
|
|
67
|
+
start();
|
|
68
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "freellmapikey",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "One OpenAI-compatible endpoint. 18 free-tier providers. ~1.3B tokens/month.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"bin": {
|
|
7
|
+
"freellmapikey": "./bin/cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"llm", "openai", "proxy", "free", "gemini", "claude", "codex", "embeddings"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/nalepy/freellmapikey",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/nalepy/freellmapikey.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20"
|
|
25
|
+
},
|
|
26
|
+
"workspaces": ["shared", "server", "client"],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "concurrently \"npm run dev -w server\" \"npm run dev -w client\"",
|
|
29
|
+
"test": "npm run test -w server",
|
|
30
|
+
"build": "npm run build -w server && npm run build -w client",
|
|
31
|
+
"build:server": "npm run build -w server",
|
|
32
|
+
"codex:model-catalog": "node scripts/generate-codex-model-catalog.mjs"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"concurrently": "^9.1.2"
|
|
36
|
+
}
|
|
37
|
+
}
|