Change timeout, Support local dev
Browse files- .env +1 -0
- app.py +36 -36
- pyproject.toml +5 -0
- requirements.txt +1 -0
- uv.lock +11 -0
.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
API_KEY=sk-xoRiNMss7qR8ywNi1c6DYg
|
app.py
CHANGED
|
@@ -5,6 +5,10 @@ import base64
|
|
| 5 |
import os
|
| 6 |
from typing import List, Optional, Tuple, Any
|
| 7 |
import mimetypes
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
class OmniAPIClient:
|
| 10 |
"""Client for interacting with the Omni API"""
|
|
@@ -74,9 +78,9 @@ class OmniAPIClient:
|
|
| 74 |
# Fixed set of models as requested
|
| 75 |
fixed_models = [
|
| 76 |
"typhoon-ocr-preview",
|
|
|
|
| 77 |
"openai/gpt-5",
|
| 78 |
"meta-llama/llama-4-maverick",
|
| 79 |
-
"qwen/qwen3-235b-a22b-instruct-2507",
|
| 80 |
"gemini/gemini-2.5-pro",
|
| 81 |
"gemini/gemini-2.5-flash"
|
| 82 |
]
|
|
@@ -118,7 +122,7 @@ class OmniAPIClient:
|
|
| 118 |
self.chat_endpoint,
|
| 119 |
json=payload,
|
| 120 |
headers=headers,
|
| 121 |
-
timeout=
|
| 122 |
)
|
| 123 |
|
| 124 |
# Check response
|
|
@@ -146,34 +150,42 @@ class OmniAPIClient:
|
|
| 146 |
def create_ui():
|
| 147 |
"""Create the Gradio UI"""
|
| 148 |
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
fixed_models = [
|
| 153 |
"typhoon-ocr-preview",
|
|
|
|
| 154 |
"openai/gpt-5",
|
| 155 |
"meta-llama/llama-4-maverick",
|
| 156 |
-
"qwen/qwen3-235b-a22b-instruct-2507",
|
| 157 |
"gemini/gemini-2.5-pro",
|
| 158 |
"gemini/gemini-2.5-flash"
|
|
|
|
|
|
|
|
|
|
| 159 |
]
|
| 160 |
-
|
| 161 |
|
| 162 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
"""Handle request submission"""
|
| 164 |
try:
|
| 165 |
# Validate inputs
|
| 166 |
-
if not
|
| 167 |
-
return "❌
|
| 168 |
|
| 169 |
if not text.strip() and not files:
|
| 170 |
return "❌ Please provide either text or upload files", ""
|
| 171 |
|
| 172 |
-
#
|
| 173 |
-
api_key_to_use =
|
| 174 |
|
| 175 |
# Create client
|
| 176 |
-
client = OmniAPIClient(
|
| 177 |
|
| 178 |
# Filter out None/empty files - handle various file input states
|
| 179 |
valid_files = []
|
|
@@ -264,29 +276,17 @@ def create_ui():
|
|
| 264 |
with gr.Group(elem_classes=["config-panel"]):
|
| 265 |
gr.Markdown("## ⚙️ Configuration")
|
| 266 |
with gr.Row():
|
| 267 |
-
|
| 268 |
-
label="API
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
)
|
| 272 |
-
api_key = gr.Textbox(
|
| 273 |
-
label="API Key (Optional)",
|
| 274 |
-
type="password",
|
| 275 |
-
placeholder="Enter your API key if required"
|
| 276 |
)
|
| 277 |
|
| 278 |
with gr.Row():
|
| 279 |
with gr.Column(scale=3):
|
| 280 |
model = gr.Dropdown(
|
| 281 |
label="Model",
|
| 282 |
-
choices=[
|
| 283 |
-
"typhoon-ocr-preview",
|
| 284 |
-
"openai/gpt-5",
|
| 285 |
-
"meta-llama/llama-4-maverick",
|
| 286 |
-
"qwen/qwen3-235b-a22b-instruct-2507",
|
| 287 |
-
"gemini/gemini-2.5-pro",
|
| 288 |
-
"gemini/gemini-2.5-flash"
|
| 289 |
-
],
|
| 290 |
value="qwen/qwen3-235b-a22b-instruct-2507",
|
| 291 |
interactive=True
|
| 292 |
)
|
|
@@ -375,7 +375,7 @@ def create_ui():
|
|
| 375 |
# Event handlers
|
| 376 |
send_btn.click(
|
| 377 |
fn=send_request,
|
| 378 |
-
inputs=[
|
| 379 |
outputs=[status_output, response_output]
|
| 380 |
)
|
| 381 |
|
|
@@ -388,14 +388,14 @@ def create_ui():
|
|
| 388 |
# Allow Enter key to submit (when text input is focused)
|
| 389 |
text_input.submit(
|
| 390 |
fn=send_request,
|
| 391 |
-
inputs=[
|
| 392 |
outputs=[status_output, response_output]
|
| 393 |
)
|
| 394 |
|
| 395 |
-
#
|
| 396 |
-
|
| 397 |
fn=fetch_models,
|
| 398 |
-
inputs=[
|
| 399 |
outputs=[model]
|
| 400 |
)
|
| 401 |
|
|
|
|
| 5 |
import os
|
| 6 |
from typing import List, Optional, Tuple, Any
|
| 7 |
import mimetypes
|
| 8 |
+
from dotenv import load_dotenv
|
| 9 |
+
|
| 10 |
+
# Load environment variables from .env file
|
| 11 |
+
load_dotenv()
|
| 12 |
|
| 13 |
class OmniAPIClient:
|
| 14 |
"""Client for interacting with the Omni API"""
|
|
|
|
| 78 |
# Fixed set of models as requested
|
| 79 |
fixed_models = [
|
| 80 |
"typhoon-ocr-preview",
|
| 81 |
+
"qwen/qwen3-235b-a22b-instruct-2507",
|
| 82 |
"openai/gpt-5",
|
| 83 |
"meta-llama/llama-4-maverick",
|
|
|
|
| 84 |
"gemini/gemini-2.5-pro",
|
| 85 |
"gemini/gemini-2.5-flash"
|
| 86 |
]
|
|
|
|
| 122 |
self.chat_endpoint,
|
| 123 |
json=payload,
|
| 124 |
headers=headers,
|
| 125 |
+
timeout=600
|
| 126 |
)
|
| 127 |
|
| 128 |
# Check response
|
|
|
|
| 150 |
def create_ui():
|
| 151 |
"""Create the Gradio UI"""
|
| 152 |
|
| 153 |
+
# Define available API endpoints and their corresponding models
|
| 154 |
+
API_ENDPOINTS = {
|
| 155 |
+
"https://api.modelharbor.com": [
|
|
|
|
| 156 |
"typhoon-ocr-preview",
|
| 157 |
+
"qwen/qwen3-235b-a22b-instruct-2507",
|
| 158 |
"openai/gpt-5",
|
| 159 |
"meta-llama/llama-4-maverick",
|
|
|
|
| 160 |
"gemini/gemini-2.5-pro",
|
| 161 |
"gemini/gemini-2.5-flash"
|
| 162 |
+
],
|
| 163 |
+
"https://api-omni.modelharbor.com": [
|
| 164 |
+
"qwen/qwen3-235b-a22b-instruct-2507-omni"
|
| 165 |
]
|
| 166 |
+
}
|
| 167 |
|
| 168 |
+
def fetch_models(api_endpoint):
|
| 169 |
+
"""Return models based on selected API endpoint"""
|
| 170 |
+
models = API_ENDPOINTS.get(api_endpoint, [])
|
| 171 |
+
default_model = models[0] if models else ""
|
| 172 |
+
return gr.Dropdown(choices=models, value=default_model)
|
| 173 |
+
|
| 174 |
+
def send_request(api_endpoint, model, max_tokens, text, files):
|
| 175 |
"""Handle request submission"""
|
| 176 |
try:
|
| 177 |
# Validate inputs
|
| 178 |
+
if not api_endpoint:
|
| 179 |
+
return "❌ API endpoint is required", ""
|
| 180 |
|
| 181 |
if not text.strip() and not files:
|
| 182 |
return "❌ Please provide either text or upload files", ""
|
| 183 |
|
| 184 |
+
# Always use API key from environment variable/secrets
|
| 185 |
+
api_key_to_use = os.getenv("API_KEY", "")
|
| 186 |
|
| 187 |
# Create client
|
| 188 |
+
client = OmniAPIClient(api_endpoint)
|
| 189 |
|
| 190 |
# Filter out None/empty files - handle various file input states
|
| 191 |
valid_files = []
|
|
|
|
| 276 |
with gr.Group(elem_classes=["config-panel"]):
|
| 277 |
gr.Markdown("## ⚙️ Configuration")
|
| 278 |
with gr.Row():
|
| 279 |
+
api_endpoint = gr.Dropdown(
|
| 280 |
+
label="API Endpoint",
|
| 281 |
+
choices=list(API_ENDPOINTS.keys()),
|
| 282 |
+
value="https://api.modelharbor.com"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
)
|
| 284 |
|
| 285 |
with gr.Row():
|
| 286 |
with gr.Column(scale=3):
|
| 287 |
model = gr.Dropdown(
|
| 288 |
label="Model",
|
| 289 |
+
choices=API_ENDPOINTS["https://api.modelharbor.com"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
value="qwen/qwen3-235b-a22b-instruct-2507",
|
| 291 |
interactive=True
|
| 292 |
)
|
|
|
|
| 375 |
# Event handlers
|
| 376 |
send_btn.click(
|
| 377 |
fn=send_request,
|
| 378 |
+
inputs=[api_endpoint, model, max_tokens, text_input, file_upload],
|
| 379 |
outputs=[status_output, response_output]
|
| 380 |
)
|
| 381 |
|
|
|
|
| 388 |
# Allow Enter key to submit (when text input is focused)
|
| 389 |
text_input.submit(
|
| 390 |
fn=send_request,
|
| 391 |
+
inputs=[api_endpoint, model, max_tokens, text_input, file_upload],
|
| 392 |
outputs=[status_output, response_output]
|
| 393 |
)
|
| 394 |
|
| 395 |
+
# Update model list when API endpoint changes
|
| 396 |
+
api_endpoint.change(
|
| 397 |
fn=fetch_models,
|
| 398 |
+
inputs=[api_endpoint],
|
| 399 |
outputs=[model]
|
| 400 |
)
|
| 401 |
|
pyproject.toml
CHANGED
|
@@ -11,6 +11,7 @@ dependencies = [
|
|
| 11 |
"aiofiles>=24.1.0",
|
| 12 |
"gradio-client>=1.13.1",
|
| 13 |
"websockets==14.2",
|
|
|
|
| 14 |
]
|
| 15 |
|
| 16 |
[build-system]
|
|
@@ -25,3 +26,7 @@ dev-dependencies = [
|
|
| 25 |
"pytest>=7.0.0",
|
| 26 |
"watchdog>=2.1.0",
|
| 27 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
"aiofiles>=24.1.0",
|
| 12 |
"gradio-client>=1.13.1",
|
| 13 |
"websockets==14.2",
|
| 14 |
+
"python-dotenv>=1.1.1",
|
| 15 |
]
|
| 16 |
|
| 17 |
[build-system]
|
|
|
|
| 26 |
"pytest>=7.0.0",
|
| 27 |
"watchdog>=2.1.0",
|
| 28 |
]
|
| 29 |
+
|
| 30 |
+
[tool.flake8]
|
| 31 |
+
ignore = ["E111"]
|
| 32 |
+
max-line-length = 120
|
requirements.txt
CHANGED
|
@@ -56,3 +56,4 @@ urllib3==2.2.3
|
|
| 56 |
uvicorn==0.33.0
|
| 57 |
watchdog==4.0.2
|
| 58 |
websockets==14.2
|
|
|
|
|
|
| 56 |
uvicorn==0.33.0
|
| 57 |
watchdog==4.0.2
|
| 58 |
websockets==14.2
|
| 59 |
+
python-dotenv==1.0.1
|
uv.lock
CHANGED
|
@@ -772,6 +772,7 @@ dependencies = [
|
|
| 772 |
{ name = "aiofiles" },
|
| 773 |
{ name = "gradio" },
|
| 774 |
{ name = "gradio-client" },
|
|
|
|
| 775 |
{ name = "python-multipart" },
|
| 776 |
{ name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" },
|
| 777 |
{ name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
|
|
@@ -789,6 +790,7 @@ requires-dist = [
|
|
| 789 |
{ name = "aiofiles", specifier = ">=24.1.0" },
|
| 790 |
{ name = "gradio", specifier = ">=5.46.1" },
|
| 791 |
{ name = "gradio-client", specifier = ">=1.13.1" },
|
|
|
|
| 792 |
{ name = "python-multipart", specifier = ">=0.0.20" },
|
| 793 |
{ name = "requests", specifier = ">=2.31.0" },
|
| 794 |
{ name = "websockets", specifier = "==14.2" },
|
|
@@ -1353,6 +1355,15 @@ wheels = [
|
|
| 1353 |
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
| 1354 |
]
|
| 1355 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1356 |
[[package]]
|
| 1357 |
name = "python-multipart"
|
| 1358 |
version = "0.0.20"
|
|
|
|
| 772 |
{ name = "aiofiles" },
|
| 773 |
{ name = "gradio" },
|
| 774 |
{ name = "gradio-client" },
|
| 775 |
+
{ name = "python-dotenv" },
|
| 776 |
{ name = "python-multipart" },
|
| 777 |
{ name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" },
|
| 778 |
{ name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
|
|
|
|
| 790 |
{ name = "aiofiles", specifier = ">=24.1.0" },
|
| 791 |
{ name = "gradio", specifier = ">=5.46.1" },
|
| 792 |
{ name = "gradio-client", specifier = ">=1.13.1" },
|
| 793 |
+
{ name = "python-dotenv", specifier = ">=1.1.1" },
|
| 794 |
{ name = "python-multipart", specifier = ">=0.0.20" },
|
| 795 |
{ name = "requests", specifier = ">=2.31.0" },
|
| 796 |
{ name = "websockets", specifier = "==14.2" },
|
|
|
|
| 1355 |
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
| 1356 |
]
|
| 1357 |
|
| 1358 |
+
[[package]]
|
| 1359 |
+
name = "python-dotenv"
|
| 1360 |
+
version = "1.1.1"
|
| 1361 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1362 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978 }
|
| 1363 |
+
wheels = [
|
| 1364 |
+
{ url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556 },
|
| 1365 |
+
]
|
| 1366 |
+
|
| 1367 |
[[package]]
|
| 1368 |
name = "python-multipart"
|
| 1369 |
version = "0.0.20"
|