velokey commited on
Commit
f026b1b
·
verified ·
1 Parent(s): 89f82e8

Upload 4 files

Browse files
openai-compatible-api-playground/.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .env
4
+ .venv/
5
+ venv/
6
+
openai-compatible-api-playground/README.md ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: VeloKey OpenAI-Compatible API Playground
3
+ emoji: 🔑
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 4.44.1
8
+ app_file: app.py
9
+ pinned: true
10
+ license: mit
11
+ short_description: Test VeloKey's OpenAI-compatible AI model API from Hugging Face
12
+ tags:
13
+ - openai-compatible
14
+ - ai-api
15
+ - llm
16
+ - gradio
17
+ - api-playground
18
+ ---
19
+
20
+ # VeloKey OpenAI-Compatible API Playground
21
+
22
+ Test VeloKey's OpenAI-compatible AI model API directly from a Hugging Face Space.
23
+
24
+ This demo lets you:
25
+
26
+ - Send a chat completion request to `https://api.velokey.ai/v1/chat/completions`
27
+ - Use your own VeloKey API key without storing it in the Space
28
+ - Choose or enter a model ID available to your account
29
+ - Inspect the raw JSON response for debugging
30
+ - List models available through `GET /v1/models`
31
+
32
+ ## How to use
33
+
34
+ 1. Get a VeloKey API key from [velokey.ai/console/keys](https://velokey.ai/console/keys?ref=huggingface-space).
35
+ 2. Paste the key into the API key field.
36
+ 3. Click **List available models** if you are not sure which model ID to use.
37
+ 4. Enter a prompt and click **Run chat completion**.
38
+
39
+ Your API key is only used for the request you send from this app. Do not paste production secrets into third-party apps unless you understand the risk.
40
+
41
+ ## Resources
42
+
43
+ - [VeloKey website](https://velokey.ai?ref=huggingface-space)
44
+ - [API documentation](https://docs.velokey.ai/api/introduction)
45
+ - [Model catalog](https://velokey.ai/model?ref=huggingface-space)
46
+ - [Pricing](https://velokey.ai/pricing?ref=huggingface-space)
47
+ - [Get API key](https://velokey.ai/console/keys?ref=huggingface-space)
openai-compatible-api-playground/app.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import time
5
+ from typing import Any
6
+
7
+ import gradio as gr
8
+ import requests
9
+
10
+
11
+ BASE_URL = "https://api.velokey.ai/v1"
12
+ CHAT_COMPLETIONS_URL = f"{BASE_URL}/chat/completions"
13
+ MODELS_URL = f"{BASE_URL}/models"
14
+
15
+ MODEL_EXAMPLES = [
16
+ "gpt-5.5",
17
+ "claude-sonnet-4-6",
18
+ "gemini-3-pro-preview",
19
+ "deepseek-v4-pro",
20
+ "qwen3.7-max",
21
+ ]
22
+
23
+ DEFAULT_SYSTEM_PROMPT = "You are a concise assistant for developers."
24
+ DEFAULT_USER_PROMPT = "Explain what an OpenAI-compatible API gateway is in two sentences."
25
+
26
+
27
+ def _headers(api_key: str) -> dict[str, str]:
28
+ return {
29
+ "Authorization": f"Bearer {api_key.strip()}",
30
+ "Content-Type": "application/json",
31
+ "User-Agent": "velokey-huggingface-playground/1.0",
32
+ }
33
+
34
+
35
+ def _format_json(data: Any) -> str:
36
+ return json.dumps(data, ensure_ascii=False, indent=2)
37
+
38
+
39
+ def _request_json(method: str, url: str, api_key: str, **kwargs: Any) -> tuple[int, Any, float]:
40
+ start = time.perf_counter()
41
+ response = requests.request(
42
+ method,
43
+ url,
44
+ headers=_headers(api_key),
45
+ timeout=60,
46
+ **kwargs,
47
+ )
48
+ elapsed_ms = (time.perf_counter() - start) * 1000
49
+
50
+ try:
51
+ body: Any = response.json()
52
+ except ValueError:
53
+ body = response.text
54
+
55
+ return response.status_code, body, elapsed_ms
56
+
57
+
58
+ def list_models(api_key: str) -> tuple[str, str]:
59
+ if not api_key.strip():
60
+ return "Paste a VeloKey API key first.", ""
61
+
62
+ try:
63
+ status, body, elapsed_ms = _request_json("GET", MODELS_URL, api_key)
64
+ except requests.RequestException as exc:
65
+ return f"Request failed: {exc}", ""
66
+
67
+ if status >= 400:
68
+ return f"Model list request returned HTTP {status}.", _format_json(body)
69
+
70
+ model_ids: list[str] = []
71
+ if isinstance(body, dict) and isinstance(body.get("data"), list):
72
+ for item in body["data"]:
73
+ if isinstance(item, dict) and item.get("id"):
74
+ model_ids.append(str(item["id"]))
75
+ elif isinstance(body, list):
76
+ for item in body:
77
+ if isinstance(item, dict) and item.get("id"):
78
+ model_ids.append(str(item["id"]))
79
+
80
+ if model_ids:
81
+ preview = "\n".join(model_ids[:30])
82
+ if len(model_ids) > 30:
83
+ preview += f"\n...and {len(model_ids) - 30} more"
84
+ summary = f"Found {len(model_ids)} model IDs in {elapsed_ms:.0f} ms."
85
+ return summary, preview
86
+
87
+ return f"Request succeeded in {elapsed_ms:.0f} ms, but no model IDs were recognized.", _format_json(body)
88
+
89
+
90
+ def run_chat_completion(
91
+ api_key: str,
92
+ model: str,
93
+ system_prompt: str,
94
+ user_prompt: str,
95
+ temperature: float,
96
+ max_tokens: int,
97
+ ) -> tuple[str, str, str]:
98
+ if not api_key.strip():
99
+ return "Paste a VeloKey API key first.", "", ""
100
+ if not model.strip():
101
+ return "Enter a model ID available to your VeloKey account.", "", ""
102
+ if not user_prompt.strip():
103
+ return "Enter a user prompt.", "", ""
104
+
105
+ messages: list[dict[str, str]] = []
106
+ if system_prompt.strip():
107
+ messages.append({"role": "system", "content": system_prompt.strip()})
108
+ messages.append({"role": "user", "content": user_prompt.strip()})
109
+
110
+ payload = {
111
+ "model": model.strip(),
112
+ "messages": messages,
113
+ "temperature": temperature,
114
+ "max_tokens": max_tokens,
115
+ }
116
+
117
+ try:
118
+ status, body, elapsed_ms = _request_json("POST", CHAT_COMPLETIONS_URL, api_key, json=payload)
119
+ except requests.RequestException as exc:
120
+ return f"Request failed: {exc}", "", _format_json(payload)
121
+
122
+ if status >= 400:
123
+ return f"Chat completion returned HTTP {status}.", _format_json(body), _format_json(payload)
124
+
125
+ answer = ""
126
+ if isinstance(body, dict):
127
+ choices = body.get("choices")
128
+ if isinstance(choices, list) and choices:
129
+ first = choices[0]
130
+ if isinstance(first, dict):
131
+ message = first.get("message")
132
+ if isinstance(message, dict):
133
+ content = message.get("content")
134
+ if isinstance(content, str):
135
+ answer = content
136
+ if not answer and isinstance(first.get("text"), str):
137
+ answer = str(first["text"])
138
+
139
+ if not answer:
140
+ answer = "Request succeeded, but the response format did not include choices[0].message.content."
141
+
142
+ status_line = f"HTTP {status} in {elapsed_ms:.0f} ms"
143
+ return status_line, answer, _format_json(body)
144
+
145
+
146
+ with gr.Blocks(
147
+ title="VeloKey OpenAI-Compatible API Playground",
148
+ theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"),
149
+ css="""
150
+ .resource-links a { margin-right: 0.75rem; }
151
+ .hint { color: #4b5563; font-size: 0.95rem; }
152
+ """,
153
+ ) as demo:
154
+ gr.Markdown(
155
+ """
156
+ # VeloKey OpenAI-Compatible API Playground
157
+
158
+ Test a VeloKey chat completion request from Hugging Face using your own API key.
159
+
160
+ <p class="resource-links">
161
+ <a href="https://velokey.ai?ref=huggingface-space" target="_blank">Website</a>
162
+ <a href="https://docs.velokey.ai/api/introduction" target="_blank">API docs</a>
163
+ <a href="https://velokey.ai/model?ref=huggingface-space" target="_blank">Models</a>
164
+ <a href="https://velokey.ai/pricing?ref=huggingface-space" target="_blank">Pricing</a>
165
+ <a href="https://velokey.ai/console/keys?ref=huggingface-space" target="_blank">Get API key</a>
166
+ </p>
167
+ """
168
+ )
169
+
170
+ with gr.Row():
171
+ api_key_input = gr.Textbox(
172
+ label="VeloKey API key",
173
+ type="password",
174
+ placeholder="vk-...",
175
+ scale=2,
176
+ )
177
+ model_input = gr.Dropdown(
178
+ label="Model ID",
179
+ choices=MODEL_EXAMPLES,
180
+ value=MODEL_EXAMPLES[0],
181
+ allow_custom_value=True,
182
+ scale=2,
183
+ )
184
+
185
+ with gr.Row():
186
+ list_models_button = gr.Button("List available models", variant="secondary")
187
+ model_status = gr.Textbox(label="Model list status", interactive=False)
188
+
189
+ available_models = gr.Textbox(
190
+ label="Available model IDs",
191
+ lines=8,
192
+ interactive=False,
193
+ placeholder="Click List available models to query GET /v1/models.",
194
+ )
195
+
196
+ with gr.Accordion("Prompt settings", open=True):
197
+ system_prompt_input = gr.Textbox(
198
+ label="System prompt",
199
+ value=DEFAULT_SYSTEM_PROMPT,
200
+ lines=2,
201
+ )
202
+ user_prompt_input = gr.Textbox(
203
+ label="User prompt",
204
+ value=DEFAULT_USER_PROMPT,
205
+ lines=5,
206
+ )
207
+ with gr.Row():
208
+ temperature_input = gr.Slider(
209
+ label="Temperature",
210
+ minimum=0,
211
+ maximum=2,
212
+ step=0.1,
213
+ value=0.7,
214
+ )
215
+ max_tokens_input = gr.Slider(
216
+ label="Max tokens",
217
+ minimum=16,
218
+ maximum=2048,
219
+ step=16,
220
+ value=512,
221
+ )
222
+
223
+ run_button = gr.Button("Run chat completion", variant="primary")
224
+
225
+ with gr.Row():
226
+ status_output = gr.Textbox(label="Status", interactive=False)
227
+ answer_output = gr.Textbox(label="Assistant response", lines=10, interactive=False)
228
+
229
+ raw_json_output = gr.Code(label="Raw JSON response", language="json", lines=18)
230
+
231
+ gr.Markdown(
232
+ """
233
+ <p class="hint">
234
+ API keys are submitted with each request and are not saved by this app. For production apps,
235
+ keep your VeloKey API key on your own backend, not in browser-side code.
236
+ </p>
237
+ """
238
+ )
239
+
240
+ list_models_button.click(
241
+ fn=list_models,
242
+ inputs=[api_key_input],
243
+ outputs=[model_status, available_models],
244
+ )
245
+
246
+ run_button.click(
247
+ fn=run_chat_completion,
248
+ inputs=[
249
+ api_key_input,
250
+ model_input,
251
+ system_prompt_input,
252
+ user_prompt_input,
253
+ temperature_input,
254
+ max_tokens_input,
255
+ ],
256
+ outputs=[status_output, answer_output, raw_json_output],
257
+ )
258
+
259
+
260
+ if __name__ == "__main__":
261
+ demo.launch()
openai-compatible-api-playground/requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio==4.44.1
2
+ huggingface_hub==0.25.2
3
+ requests==2.32.5