waddie commited on
Commit
59520d4
ยท
1 Parent(s): 708792d

refactor rate limiting logic to simplify API key handling and remove OpenWebUI specific checks

Browse files
Files changed (1) hide show
  1. src/main.py +12 -36
src/main.py CHANGED
@@ -414,29 +414,20 @@ async def rate_limit_api_key(key: str = Depends(API_KEY_HEADER)):
414
  api_key_str = key[7:].strip()
415
  config = get_config()
416
 
417
- # Check if API key ends with -openwebui suffix
418
- # If so, strip it for authentication but preserve it in the returned key_data
419
- base_api_key = api_key_str
420
- is_openwebui_mode = api_key_str.endswith("-openwebui")
421
- if is_openwebui_mode:
422
- base_api_key = api_key_str[:-11] # Remove "-openwebui" suffix (11 characters)
423
- debug_print(f"๐Ÿ”‘ OpenWebUI mode detected - stripped suffix from key")
424
-
425
- # Look up the key without the suffix
426
- key_data = next((k for k in config["api_keys"] if k["key"] == base_api_key), None)
427
  if not key_data:
428
  raise HTTPException(status_code=401, detail="Invalid API Key.")
429
 
430
- # Rate Limiting (use base key for rate limiting)
431
  rate_limit = key_data.get("rpm", 60)
432
  current_time = time.time()
433
 
434
  # Clean up old timestamps (older than 60 seconds)
435
- api_key_usage[base_api_key] = [t for t in api_key_usage[base_api_key] if current_time - t < 60]
436
 
437
- if len(api_key_usage[base_api_key]) >= rate_limit:
438
  # Calculate seconds until oldest request expires (60 seconds window)
439
- oldest_timestamp = min(api_key_usage[base_api_key])
440
  retry_after = int(60 - (current_time - oldest_timestamp))
441
  retry_after = max(1, retry_after) # At least 1 second
442
 
@@ -446,11 +437,9 @@ async def rate_limit_api_key(key: str = Depends(API_KEY_HEADER)):
446
  headers={"Retry-After": str(retry_after)}
447
  )
448
 
449
- api_key_usage[base_api_key].append(current_time)
450
 
451
- # Return key_data with the original key string (including -openwebui suffix if present)
452
- # This allows downstream code to check for OpenWebUI mode
453
- return {**key_data, "key": api_key_str}
454
 
455
  # --- Core Logic ---
456
 
@@ -1394,26 +1383,14 @@ async def health_check():
1394
  async def list_models(api_key: dict = Depends(rate_limit_api_key)):
1395
  models = get_models()
1396
 
1397
- # Check if API key ends with -openwebui
1398
- api_key_str = api_key.get("key", "")
1399
- is_openwebui = api_key_str.endswith("-openwebui")
1400
-
1401
- debug_print(f"๐Ÿ”‘ API key check: ends with -openwebui = {is_openwebui}")
1402
-
1403
  # Filter for models with text OR search OR image output capability and an organization (exclude stealth models)
1404
- # Include chat, search, web dev, and image generation models (if openwebui key)
1405
  valid_models = [m for m in models
1406
  if (m.get('capabilities', {}).get('outputCapabilities', {}).get('text')
1407
  or m.get('capabilities', {}).get('outputCapabilities', {}).get('search')
1408
- or (is_openwebui and m.get('capabilities', {}).get('outputCapabilities', {}).get('image')))
1409
  and m.get('organization')]
1410
 
1411
- # Log image models when using openwebui key
1412
- if is_openwebui:
1413
- image_models = [m.get("publicName") for m in valid_models
1414
- if m.get('capabilities', {}).get('outputCapabilities', {}).get('image')]
1415
- debug_print(f"๐Ÿ–ผ๏ธ Image models available for OpenWebUI key: {image_models}")
1416
-
1417
  return {
1418
  "object": "list",
1419
  "data": [
@@ -2132,11 +2109,10 @@ async def api_chat_completions(request: Request, api_key: dict = Depends(rate_li
2132
  unique_citations.append(citation)
2133
  message_obj["citations"] = unique_citations
2134
 
2135
- # For OpenWebUI keys with image models, convert image URL to base64 data URL
2136
- is_openwebui = api_key_str.endswith("-openwebui")
2137
  is_image_model = modality == "image"
2138
 
2139
- if is_openwebui and is_image_model and response_text.startswith("http"):
2140
  debug_print(f"๐Ÿ–ผ๏ธ Converting image URL to base64 for OpenWebUI compatibility")
2141
  try:
2142
  # Download the image
@@ -2153,7 +2129,7 @@ async def api_chat_completions(request: Request, api_key: dict = Depends(rate_li
2153
  # Create data URL
2154
  data_url = f"data:{content_type};base64,{img_base64}"
2155
 
2156
- # Format as markdown for OpenWebUI
2157
  message_obj["content"] = f"![Generated Image]({data_url})"
2158
 
2159
  debug_print(f"โœ… Image converted to base64 data URL ({len(img_base64)} chars)")
 
414
  api_key_str = key[7:].strip()
415
  config = get_config()
416
 
417
+ key_data = next((k for k in config["api_keys"] if k["key"] == api_key_str), None)
 
 
 
 
 
 
 
 
 
418
  if not key_data:
419
  raise HTTPException(status_code=401, detail="Invalid API Key.")
420
 
421
+ # Rate Limiting
422
  rate_limit = key_data.get("rpm", 60)
423
  current_time = time.time()
424
 
425
  # Clean up old timestamps (older than 60 seconds)
426
+ api_key_usage[api_key_str] = [t for t in api_key_usage[api_key_str] if current_time - t < 60]
427
 
428
+ if len(api_key_usage[api_key_str]) >= rate_limit:
429
  # Calculate seconds until oldest request expires (60 seconds window)
430
+ oldest_timestamp = min(api_key_usage[api_key_str])
431
  retry_after = int(60 - (current_time - oldest_timestamp))
432
  retry_after = max(1, retry_after) # At least 1 second
433
 
 
437
  headers={"Retry-After": str(retry_after)}
438
  )
439
 
440
+ api_key_usage[api_key_str].append(current_time)
441
 
442
+ return key_data
 
 
443
 
444
  # --- Core Logic ---
445
 
 
1383
  async def list_models(api_key: dict = Depends(rate_limit_api_key)):
1384
  models = get_models()
1385
 
 
 
 
 
 
 
1386
  # Filter for models with text OR search OR image output capability and an organization (exclude stealth models)
1387
+ # Always include image models - no special key needed
1388
  valid_models = [m for m in models
1389
  if (m.get('capabilities', {}).get('outputCapabilities', {}).get('text')
1390
  or m.get('capabilities', {}).get('outputCapabilities', {}).get('search')
1391
+ or m.get('capabilities', {}).get('outputCapabilities', {}).get('image'))
1392
  and m.get('organization')]
1393
 
 
 
 
 
 
 
1394
  return {
1395
  "object": "list",
1396
  "data": [
 
2109
  unique_citations.append(citation)
2110
  message_obj["citations"] = unique_citations
2111
 
2112
+ # For image models used in chat endpoint, convert URL to markdown with base64
 
2113
  is_image_model = modality == "image"
2114
 
2115
+ if is_image_model and response_text.startswith("http"):
2116
  debug_print(f"๐Ÿ–ผ๏ธ Converting image URL to base64 for OpenWebUI compatibility")
2117
  try:
2118
  # Download the image
 
2129
  # Create data URL
2130
  data_url = f"data:{content_type};base64,{img_base64}"
2131
 
2132
+ # Format as markdown
2133
  message_obj["content"] = f"![Generated Image]({data_url})"
2134
 
2135
  debug_print(f"โœ… Image converted to base64 data URL ({len(img_base64)} chars)")