query-oracle 0.3.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Heman Phadvas
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.
@@ -0,0 +1,299 @@
1
+ Metadata-Version: 2.4
2
+ Name: query-oracle
3
+ Version: 0.3.0
4
+ Summary: Automatic LLM model and effort-level routing based on query classification.
5
+ Author-email: Heman Phadvas <tailung.hp@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/hemanpadvas2002/query-oracle
8
+ Project-URL: Repository, https://github.com/hemanpadvas2002/query-oracle
9
+ Project-URL: Issues, https://github.com/hemanpadvas2002/query-oracle/issues
10
+ Project-URL: Live API, https://query-oracle-production.up.railway.app
11
+ Keywords: llm,routing,anthropic,openai,gemini,claude,mcp,model-selection,cost-optimization
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Operating System :: OS Independent
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: anthropic>=0.40.0
26
+ Requires-Dist: python-dotenv>=1.0.0
27
+ Provides-Extra: server
28
+ Requires-Dist: fastapi>=0.110.0; extra == "server"
29
+ Requires-Dist: uvicorn[standard]>=0.27.0; extra == "server"
30
+ Provides-Extra: mcp
31
+ Requires-Dist: mcp<2.0.0,>=1.0.0; extra == "mcp"
32
+ Provides-Extra: openai
33
+ Requires-Dist: openai>=1.30.0; extra == "openai"
34
+ Provides-Extra: gemini
35
+ Requires-Dist: google-generativeai>=0.7.0; extra == "gemini"
36
+ Provides-Extra: train
37
+ Requires-Dist: transformers>=4.40.0; extra == "train"
38
+ Requires-Dist: datasets>=2.19.0; extra == "train"
39
+ Requires-Dist: torch>=2.2.0; extra == "train"
40
+ Requires-Dist: scikit-learn>=1.4.0; extra == "train"
41
+ Requires-Dist: optimum>=1.19.0; extra == "train"
42
+ Requires-Dist: onnxruntime>=1.17.0; extra == "train"
43
+ Provides-Extra: all
44
+ Requires-Dist: query-oracle[gemini,mcp,openai,server]; extra == "all"
45
+ Dynamic: license-file
46
+
47
+ # query-oracle
48
+
49
+ > Automatic LLM routing — the right model, the right effort, zero manual selection.
50
+
51
+ [![CI](https://github.com/hemanpadvas2002/query-oracle/actions/workflows/ci.yml/badge.svg)](https://github.com/hemanpadvas2002/query-oracle/actions/workflows/ci.yml)
52
+ [![Live](https://img.shields.io/badge/API-live%20on%20Railway-brightgreen)](https://query-oracle-production.up.railway.app/health)
53
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
54
+
55
+ ---
56
+
57
+ ## Live demo
58
+
59
+ > **Illustrative** — actual output will vary by provider, model, and query.
60
+
61
+ ```python
62
+ from llm_router import QueryRouter
63
+
64
+ r = QueryRouter().route("Design a fault-tolerant event streaming architecture.")
65
+ print(f"tier={r.tier.value} model={r.model_used} thinking={r.extended_thinking_used}")
66
+ print(f"cost=${r.cost_usd:.5f} total=${r.total_cost_usd:.5f} latency={r.latency_ms:.0f}ms")
67
+ print(r.classification.reasoning)
68
+ ```
69
+
70
+ ---
71
+
72
+ ## What it does
73
+
74
+ query-oracle sits in front of your LLM calls and automatically decides which model deserves the query. Factual lookups go to Haiku or GPT-4o-mini in under a second; open-ended design problems get routed to Opus with extended thinking or o1 with high reasoning effort. The classification itself costs a fraction of a cent and the routing decision is logged so you can fine-tune a local DistilBERT classifier later — eventually dropping the classification API cost to zero.
75
+
76
+ It ships as a Python library, a live REST API, a Claude Code MCP plugin, a VS Code / Cursor extension, an OpenAI Custom GPT Action, and a reusable GitHub Actions workflow. Pick whichever integration fits your stack.
77
+
78
+ ---
79
+
80
+ ## Quick install — pick your platform
81
+
82
+ ### Python library
83
+
84
+ ```bash
85
+ pip install "query-oracle"
86
+ ```
87
+
88
+ With optional extras:
89
+
90
+ ```bash
91
+ pip install "query-oracle[server]" # FastAPI REST server
92
+ pip install "query-oracle[mcp]" # Claude Code / Desktop MCP plugin
93
+ pip install "query-oracle[openai]" # OpenAI provider
94
+ pip install "query-oracle[gemini]" # Gemini provider
95
+ pip install "query-oracle[all]" # everything
96
+ ```
97
+
98
+ ### Claude Code / Claude Desktop (MCP)
99
+
100
+ ```bash
101
+ pip install "query-oracle[mcp]"
102
+ claude mcp add query-oracle -- query-oracle-mcp
103
+ ```
104
+
105
+ Then in any Claude conversation:
106
+
107
+ ```
108
+ route "Design a real-time fraud detection pipeline."
109
+ classify "What is the capital of France?"
110
+ ```
111
+
112
+ Or add to `~/.claude/claude_desktop_config.json` manually:
113
+
114
+ ```json
115
+ {
116
+ "mcpServers": {
117
+ "query-oracle": {
118
+ "command": "query-oracle-mcp",
119
+ "env": { "ANTHROPIC_API_KEY": "sk-ant-..." }
120
+ }
121
+ }
122
+ }
123
+ ```
124
+
125
+ ---
126
+
127
+ ### ChatGPT — Custom GPT Action
128
+
129
+ Paste this URL into **GPT builder → Configure → Actions → Import from URL**:
130
+
131
+ ```
132
+ https://query-oracle-production.up.railway.app/openapi.json
133
+ ```
134
+
135
+ The server is live — no setup required. See [`openai-plugin/README.md`](openai-plugin/README.md) for how to self-host and add authentication.
136
+
137
+ ---
138
+
139
+ ### Cursor / VS Code Extension
140
+
141
+ The extension starts the REST server automatically — no manual uvicorn command.
142
+
143
+ ```bash
144
+ cd vscode-extension
145
+ npm install
146
+ npm run package # → query-oracle-1.0.0.vsix
147
+ code --install-extension query-oracle-1.0.0.vsix
148
+ ```
149
+
150
+ Press `Cmd/Ctrl+Shift+L` to open the query input. Responses appear in the **LLM Query Router** output panel with tier, model, latency, and cost.
151
+
152
+ ---
153
+
154
+ ### GitHub Copilot / Codex
155
+
156
+ Copy `.github/copilot-instructions.md` into your own repo's `.github/` folder. Copilot will read it automatically in VS Code and JetBrains and stop suggesting hard-coded model names.
157
+
158
+ For GitHub Actions / Copilot Workspace tasks:
159
+
160
+ ```yaml
161
+ jobs:
162
+ design:
163
+ uses: hemanpadvas2002/query-oracle/.github/workflows/copilot-router.yml@main
164
+ with:
165
+ query: "Design a zero-downtime database migration strategy."
166
+ secrets:
167
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
168
+ # outputs: response, tier, model_used, cost_usd
169
+ ```
170
+
171
+ ---
172
+
173
+ ## How routing works
174
+
175
+ | Tier | When | Anthropic | OpenAI | Gemini |
176
+ |---|---|---|---|---|
177
+ | `fast` | Factual lookups, maths, news, nutrition | claude-haiku-4-5 | gpt-4o-mini | gemini-1.5-flash |
178
+ | `balanced` | Analysis, explanations, moderate reasoning | claude-sonnet-4-5 | gpt-4o | gemini-1.5-pro |
179
+ | `deep` | Strategy, design, ethics, complex ideation | claude-opus-4-5 + thinking | o1 (high) | gemini-2.0-flash-thinking |
180
+
181
+ The classifier sends the query to a small model (Haiku by default) with a structured prompt that returns `tier`, `effort`, `facts_ratio`, `judgment_ratio`, `confidence`, and a one-sentence `reasoning`. Every result is logged to `logs/classifications.jsonl` — this passively builds the labelled dataset for local DistilBERT fine-tuning.
182
+
183
+ ---
184
+
185
+ ## Response fields
186
+
187
+ ```python
188
+ RouterResponse(
189
+ content = "...",
190
+ tier = QueryTier.DEEP,
191
+ effort = EffortLevel.HIGH,
192
+ provider = ProviderType.ANTHROPIC,
193
+ model_used = "claude-opus-4-5",
194
+ extended_thinking_used = True,
195
+ input_tokens = 312,
196
+ output_tokens = 891,
197
+ latency_ms = 3241.4,
198
+ cost_usd = 0.02184, # completion cost only
199
+ total_cost_usd = 0.02188, # completion + classifier cost
200
+ classification = ClassificationResult(
201
+ tier = QueryTier.DEEP,
202
+ effort = EffortLevel.HIGH,
203
+ facts_ratio = 0.12,
204
+ judgment_ratio = 0.88,
205
+ confidence = 0.94,
206
+ reasoning = "Complex distributed systems design — strategy tier warranted",
207
+ classifier_input_tokens = 85,
208
+ classifier_output_tokens = 47,
209
+ classifier_cost_usd = 0.0000456,
210
+ ),
211
+ )
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Live REST API
217
+
218
+ **Base URL:** `https://query-oracle-production.up.railway.app`
219
+
220
+ ```bash
221
+ # Health check (no auth required)
222
+ curl https://query-oracle-production.up.railway.app/health
223
+ # {"status":"ok"}
224
+
225
+ # Classify only (auth required when QUERY_ORACLE_API_KEY is set)
226
+ curl -s -X POST https://query-oracle-production.up.railway.app/classify \
227
+ -H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
228
+ -H "Content-Type: application/json" \
229
+ -d '{"query": "How many calories in a banana?"}' | jq .
230
+
231
+ # Route and get a full response
232
+ curl -s -X POST https://query-oracle-production.up.railway.app/route \
233
+ -H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
234
+ -H "Content-Type: application/json" \
235
+ -d '{"query": "Explain backpressure in reactive systems.", "provider": "anthropic"}' \
236
+ | jq '{tier, model_used, cost_usd, total_cost_usd, latency_ms}'
237
+ ```
238
+
239
+ Interactive docs: [`/docs`](https://query-oracle-production.up.railway.app/docs)
240
+
241
+ ---
242
+
243
+ ## Securing your deployment
244
+
245
+ By default the server runs in open mode (dev-only). Before exposing it publicly:
246
+
247
+ **1. Set an API key**
248
+
249
+ ```bash
250
+ export QUERY_ORACLE_API_KEY="your-secret-key"
251
+ ```
252
+
253
+ All requests to `/route` and `/classify` then require:
254
+
255
+ ```
256
+ Authorization: Bearer your-secret-key
257
+ ```
258
+
259
+ The `/health` endpoint stays open. The server logs a warning at startup if no key is set.
260
+
261
+ **2. Restrict CORS origins**
262
+
263
+ ```bash
264
+ export CORS_ORIGINS="https://yourdomain.com,https://app.yourdomain.com"
265
+ ```
266
+
267
+ When unset, CORS defaults to `*` (any origin). Set it to your specific domains in production.
268
+
269
+ **3. Rate limiting**
270
+
271
+ The `/route` endpoint enforces 30 requests per minute per client IP in-process. For heavier traffic, put an API gateway (e.g. Nginx, Cloudflare, Railway gateway) in front.
272
+
273
+ **Railway environment variables:**
274
+
275
+ ```
276
+ QUERY_ORACLE_API_KEY → your secret key
277
+ ANTHROPIC_API_KEY → sk-ant-...
278
+ OPENAI_API_KEY → sk-... (optional)
279
+ GEMINI_API_KEY → AIza... (optional)
280
+ CORS_ORIGINS → https://yourdomain.com
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Train your own classifier (coming soon)
286
+
287
+ Once `logs/classifications.jsonl` accumulates ~500 entries, run `python training/train.py --data training/data/queries.csv` to fine-tune a local DistilBERT model. Swap it in with `QueryRouter(classifier=DistilBERTClassifier("training/query-classifier-final"))` and classification drops to ~10 ms with zero API cost.
288
+
289
+ ---
290
+
291
+ ## Contributing
292
+
293
+ Open an issue or PR — the codebase is intentionally small. Adding a new provider means subclassing `BaseProvider` and implementing one method; the routing logic, classifier, and all integrations stay unchanged.
294
+
295
+ ---
296
+
297
+ ## Licence
298
+
299
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,253 @@
1
+ # query-oracle
2
+
3
+ > Automatic LLM routing — the right model, the right effort, zero manual selection.
4
+
5
+ [![CI](https://github.com/hemanpadvas2002/query-oracle/actions/workflows/ci.yml/badge.svg)](https://github.com/hemanpadvas2002/query-oracle/actions/workflows/ci.yml)
6
+ [![Live](https://img.shields.io/badge/API-live%20on%20Railway-brightgreen)](https://query-oracle-production.up.railway.app/health)
7
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
8
+
9
+ ---
10
+
11
+ ## Live demo
12
+
13
+ > **Illustrative** — actual output will vary by provider, model, and query.
14
+
15
+ ```python
16
+ from llm_router import QueryRouter
17
+
18
+ r = QueryRouter().route("Design a fault-tolerant event streaming architecture.")
19
+ print(f"tier={r.tier.value} model={r.model_used} thinking={r.extended_thinking_used}")
20
+ print(f"cost=${r.cost_usd:.5f} total=${r.total_cost_usd:.5f} latency={r.latency_ms:.0f}ms")
21
+ print(r.classification.reasoning)
22
+ ```
23
+
24
+ ---
25
+
26
+ ## What it does
27
+
28
+ query-oracle sits in front of your LLM calls and automatically decides which model deserves the query. Factual lookups go to Haiku or GPT-4o-mini in under a second; open-ended design problems get routed to Opus with extended thinking or o1 with high reasoning effort. The classification itself costs a fraction of a cent and the routing decision is logged so you can fine-tune a local DistilBERT classifier later — eventually dropping the classification API cost to zero.
29
+
30
+ It ships as a Python library, a live REST API, a Claude Code MCP plugin, a VS Code / Cursor extension, an OpenAI Custom GPT Action, and a reusable GitHub Actions workflow. Pick whichever integration fits your stack.
31
+
32
+ ---
33
+
34
+ ## Quick install — pick your platform
35
+
36
+ ### Python library
37
+
38
+ ```bash
39
+ pip install "query-oracle"
40
+ ```
41
+
42
+ With optional extras:
43
+
44
+ ```bash
45
+ pip install "query-oracle[server]" # FastAPI REST server
46
+ pip install "query-oracle[mcp]" # Claude Code / Desktop MCP plugin
47
+ pip install "query-oracle[openai]" # OpenAI provider
48
+ pip install "query-oracle[gemini]" # Gemini provider
49
+ pip install "query-oracle[all]" # everything
50
+ ```
51
+
52
+ ### Claude Code / Claude Desktop (MCP)
53
+
54
+ ```bash
55
+ pip install "query-oracle[mcp]"
56
+ claude mcp add query-oracle -- query-oracle-mcp
57
+ ```
58
+
59
+ Then in any Claude conversation:
60
+
61
+ ```
62
+ route "Design a real-time fraud detection pipeline."
63
+ classify "What is the capital of France?"
64
+ ```
65
+
66
+ Or add to `~/.claude/claude_desktop_config.json` manually:
67
+
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "query-oracle": {
72
+ "command": "query-oracle-mcp",
73
+ "env": { "ANTHROPIC_API_KEY": "sk-ant-..." }
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ---
80
+
81
+ ### ChatGPT — Custom GPT Action
82
+
83
+ Paste this URL into **GPT builder → Configure → Actions → Import from URL**:
84
+
85
+ ```
86
+ https://query-oracle-production.up.railway.app/openapi.json
87
+ ```
88
+
89
+ The server is live — no setup required. See [`openai-plugin/README.md`](openai-plugin/README.md) for how to self-host and add authentication.
90
+
91
+ ---
92
+
93
+ ### Cursor / VS Code Extension
94
+
95
+ The extension starts the REST server automatically — no manual uvicorn command.
96
+
97
+ ```bash
98
+ cd vscode-extension
99
+ npm install
100
+ npm run package # → query-oracle-1.0.0.vsix
101
+ code --install-extension query-oracle-1.0.0.vsix
102
+ ```
103
+
104
+ Press `Cmd/Ctrl+Shift+L` to open the query input. Responses appear in the **LLM Query Router** output panel with tier, model, latency, and cost.
105
+
106
+ ---
107
+
108
+ ### GitHub Copilot / Codex
109
+
110
+ Copy `.github/copilot-instructions.md` into your own repo's `.github/` folder. Copilot will read it automatically in VS Code and JetBrains and stop suggesting hard-coded model names.
111
+
112
+ For GitHub Actions / Copilot Workspace tasks:
113
+
114
+ ```yaml
115
+ jobs:
116
+ design:
117
+ uses: hemanpadvas2002/query-oracle/.github/workflows/copilot-router.yml@main
118
+ with:
119
+ query: "Design a zero-downtime database migration strategy."
120
+ secrets:
121
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
122
+ # outputs: response, tier, model_used, cost_usd
123
+ ```
124
+
125
+ ---
126
+
127
+ ## How routing works
128
+
129
+ | Tier | When | Anthropic | OpenAI | Gemini |
130
+ |---|---|---|---|---|
131
+ | `fast` | Factual lookups, maths, news, nutrition | claude-haiku-4-5 | gpt-4o-mini | gemini-1.5-flash |
132
+ | `balanced` | Analysis, explanations, moderate reasoning | claude-sonnet-4-5 | gpt-4o | gemini-1.5-pro |
133
+ | `deep` | Strategy, design, ethics, complex ideation | claude-opus-4-5 + thinking | o1 (high) | gemini-2.0-flash-thinking |
134
+
135
+ The classifier sends the query to a small model (Haiku by default) with a structured prompt that returns `tier`, `effort`, `facts_ratio`, `judgment_ratio`, `confidence`, and a one-sentence `reasoning`. Every result is logged to `logs/classifications.jsonl` — this passively builds the labelled dataset for local DistilBERT fine-tuning.
136
+
137
+ ---
138
+
139
+ ## Response fields
140
+
141
+ ```python
142
+ RouterResponse(
143
+ content = "...",
144
+ tier = QueryTier.DEEP,
145
+ effort = EffortLevel.HIGH,
146
+ provider = ProviderType.ANTHROPIC,
147
+ model_used = "claude-opus-4-5",
148
+ extended_thinking_used = True,
149
+ input_tokens = 312,
150
+ output_tokens = 891,
151
+ latency_ms = 3241.4,
152
+ cost_usd = 0.02184, # completion cost only
153
+ total_cost_usd = 0.02188, # completion + classifier cost
154
+ classification = ClassificationResult(
155
+ tier = QueryTier.DEEP,
156
+ effort = EffortLevel.HIGH,
157
+ facts_ratio = 0.12,
158
+ judgment_ratio = 0.88,
159
+ confidence = 0.94,
160
+ reasoning = "Complex distributed systems design — strategy tier warranted",
161
+ classifier_input_tokens = 85,
162
+ classifier_output_tokens = 47,
163
+ classifier_cost_usd = 0.0000456,
164
+ ),
165
+ )
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Live REST API
171
+
172
+ **Base URL:** `https://query-oracle-production.up.railway.app`
173
+
174
+ ```bash
175
+ # Health check (no auth required)
176
+ curl https://query-oracle-production.up.railway.app/health
177
+ # {"status":"ok"}
178
+
179
+ # Classify only (auth required when QUERY_ORACLE_API_KEY is set)
180
+ curl -s -X POST https://query-oracle-production.up.railway.app/classify \
181
+ -H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
182
+ -H "Content-Type: application/json" \
183
+ -d '{"query": "How many calories in a banana?"}' | jq .
184
+
185
+ # Route and get a full response
186
+ curl -s -X POST https://query-oracle-production.up.railway.app/route \
187
+ -H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
188
+ -H "Content-Type: application/json" \
189
+ -d '{"query": "Explain backpressure in reactive systems.", "provider": "anthropic"}' \
190
+ | jq '{tier, model_used, cost_usd, total_cost_usd, latency_ms}'
191
+ ```
192
+
193
+ Interactive docs: [`/docs`](https://query-oracle-production.up.railway.app/docs)
194
+
195
+ ---
196
+
197
+ ## Securing your deployment
198
+
199
+ By default the server runs in open mode (dev-only). Before exposing it publicly:
200
+
201
+ **1. Set an API key**
202
+
203
+ ```bash
204
+ export QUERY_ORACLE_API_KEY="your-secret-key"
205
+ ```
206
+
207
+ All requests to `/route` and `/classify` then require:
208
+
209
+ ```
210
+ Authorization: Bearer your-secret-key
211
+ ```
212
+
213
+ The `/health` endpoint stays open. The server logs a warning at startup if no key is set.
214
+
215
+ **2. Restrict CORS origins**
216
+
217
+ ```bash
218
+ export CORS_ORIGINS="https://yourdomain.com,https://app.yourdomain.com"
219
+ ```
220
+
221
+ When unset, CORS defaults to `*` (any origin). Set it to your specific domains in production.
222
+
223
+ **3. Rate limiting**
224
+
225
+ The `/route` endpoint enforces 30 requests per minute per client IP in-process. For heavier traffic, put an API gateway (e.g. Nginx, Cloudflare, Railway gateway) in front.
226
+
227
+ **Railway environment variables:**
228
+
229
+ ```
230
+ QUERY_ORACLE_API_KEY → your secret key
231
+ ANTHROPIC_API_KEY → sk-ant-...
232
+ OPENAI_API_KEY → sk-... (optional)
233
+ GEMINI_API_KEY → AIza... (optional)
234
+ CORS_ORIGINS → https://yourdomain.com
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Train your own classifier (coming soon)
240
+
241
+ Once `logs/classifications.jsonl` accumulates ~500 entries, run `python training/train.py --data training/data/queries.csv` to fine-tune a local DistilBERT model. Swap it in with `QueryRouter(classifier=DistilBERTClassifier("training/query-classifier-final"))` and classification drops to ~10 ms with zero API cost.
242
+
243
+ ---
244
+
245
+ ## Contributing
246
+
247
+ Open an issue or PR — the codebase is intentionally small. Adding a new provider means subclassing `BaseProvider` and implementing one method; the routing logic, classifier, and all integrations stay unchanged.
248
+
249
+ ---
250
+
251
+ ## Licence
252
+
253
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["setuptools>=45", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "query-oracle"
7
+ version = "0.3.0"
8
+ description = "Automatic LLM model and effort-level routing based on query classification."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Heman Phadvas", email = "tailung.hp@gmail.com" },
14
+ ]
15
+ keywords = [
16
+ "llm", "routing", "anthropic", "openai", "gemini", "claude",
17
+ "mcp", "model-selection", "cost-optimization",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Intended Audience :: Developers",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
28
+ "Topic :: Software Development :: Libraries :: Python Modules",
29
+ "Operating System :: OS Independent",
30
+ ]
31
+ dependencies = [
32
+ "anthropic>=0.40.0",
33
+ "python-dotenv>=1.0.0",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/hemanpadvas2002/query-oracle"
38
+ Repository = "https://github.com/hemanpadvas2002/query-oracle"
39
+ Issues = "https://github.com/hemanpadvas2002/query-oracle/issues"
40
+ "Live API" = "https://query-oracle-production.up.railway.app"
41
+
42
+ [project.optional-dependencies]
43
+ server = ["fastapi>=0.110.0", "uvicorn[standard]>=0.27.0"]
44
+ mcp = ["mcp>=1.0.0,<2.0.0"]
45
+ openai = ["openai>=1.30.0"]
46
+ gemini = ["google-generativeai>=0.7.0"]
47
+ train = ["transformers>=4.40.0", "datasets>=2.19.0", "torch>=2.2.0",
48
+ "scikit-learn>=1.4.0", "optimum>=1.19.0", "onnxruntime>=1.17.0"]
49
+ all = ["query-oracle[server,mcp,openai,gemini]"]
50
+
51
+ [project.scripts]
52
+ query-oracle-mcp = "llm_router.mcp_server:main"
53
+
54
+ [tool.setuptools.packages.find]
55
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,14 @@
1
+ from .models import (
2
+ ClassificationResult, EffortLevel, ProviderType,
3
+ QueryTier, RouterConfig, RouterResponse,
4
+ MODEL_PRICING, estimate_cost,
5
+ )
6
+ from .router import QueryRouter
7
+ from .classifier import PromptClassifier, DistilBERTClassifier
8
+
9
+ __all__ = [
10
+ "QueryRouter", "RouterConfig", "RouterResponse",
11
+ "ClassificationResult", "QueryTier", "EffortLevel", "ProviderType",
12
+ "PromptClassifier", "DistilBERTClassifier",
13
+ "MODEL_PRICING", "estimate_cost",
14
+ ]