| import os |
| import gradio as gr |
| from openai import OpenAI |
| from collections import defaultdict |
| import time |
|
|
| |
| |
| try: |
| from dotenv import load_dotenv |
| load_dotenv() |
| except ImportError: |
| pass |
|
|
| |
| API_KEYS = { |
| "groq": os.environ.get("GROQ_API_KEY"), |
| "gemini": os.environ.get("GEMINI_API_KEY"), |
| "mistral": os.environ.get("MISTRAL_API_KEY"), |
| "cohere": os.environ.get("COHERE_API_KEY"), |
| "huggingface": os.environ.get("HF_API_KEY"), |
| } |
|
|
| |
| ALL_PROVIDERS = [ |
| { |
| "name": "groq", |
| "base_url": "https://api.groq.com/openai/v1", |
| "model": "llama-3.1-8b-instant", |
| "daily_limit": 14400, |
| "priority": 1, |
| }, |
| { |
| "name": "gemini", |
| "base_url": "https://generativelanguage.googleapis.com/v1beta/openai/", |
| "model": "gemini-2.5-flash", |
| "daily_limit": 1500, |
| "priority": 2, |
| }, |
| { |
| "name": "mistral", |
| "base_url": "https://api.mistral.ai/v1", |
| "model": "mistral-small-latest", |
| "daily_limit": 1400, |
| "priority": 3, |
| }, |
| { |
| "name": "cohere", |
| "base_url": "https://api.cohere.com/compatibility/v1", |
| "model": "command-r-plus", |
| "daily_limit": 1000, |
| "priority": 4, |
| }, |
| { |
| "name": "huggingface", |
| "base_url": "https://api-inference.huggingface.co/v1/", |
| "model": "Qwen/Qwen2.5-Coder-1.5B-Instruct", |
| "daily_limit": 1000, |
| "priority": 5, |
| }, |
| ] |
|
|
| |
| ACTIVE_PROVIDERS = [ |
| p for p in ALL_PROVIDERS |
| if API_KEYS.get(p["name"]) not in (None, "") |
| ] |
|
|
| |
| usage_count = defaultdict(int) |
| bad_keys = set() |
| last_reset = time.time() |
|
|
| def pick_provider(exclude=None): |
| global last_reset |
| if exclude is None: |
| exclude = set() |
|
|
| if time.time() - last_reset > 86400: |
| usage_count.clear() |
| bad_keys.clear() |
| last_reset = time.time() |
|
|
| available = [ |
| p for p in ACTIVE_PROVIDERS |
| if p["name"] not in exclude and p["name"] not in bad_keys |
| ] |
| if not available: |
| return None |
|
|
| return min( |
| available, |
| key=lambda p: ( |
| usage_count[p["name"]] / p["daily_limit"], |
| p["priority"] |
| ) |
| ) |
|
|
| SYSTEM_PROMPT = "You are a Minecraft coding assistant. Be brief and direct." |
|
|
| def respond(message, history): |
| if not ACTIVE_PROVIDERS: |
| yield "β No API keys provided! Add them in your Space's Settings β Variables and Secrets." |
| return |
|
|
| |
| messages = [{"role": "system", "content": SYSTEM_PROMPT}] |
| for exchange in history[-3:]: |
| user_msg = exchange[0] if isinstance(exchange, (list, tuple)) else "" |
| asst_msg = exchange[1] if isinstance(exchange, (list, tuple)) else "" |
| if user_msg: |
| messages.append({"role": "user", "content": user_msg}) |
| if asst_msg: |
| messages.append({"role": "assistant", "content": asst_msg}) |
| messages.append({"role": "user", "content": message}) |
|
|
| tried = set() |
|
|
| while True: |
| provider = pick_provider(exclude=tried) |
|
|
| if provider is None: |
| yield "β All providers failed or hit limits. Try again later." |
| return |
|
|
| print(f"Trying: {provider['name']} | uses today: {usage_count[provider['name']]}") |
|
|
| client = OpenAI( |
| api_key=API_KEYS[provider["name"]], |
| base_url=provider["base_url"], |
| ) |
|
|
| try: |
| stream = client.chat.completions.create( |
| model=provider["model"], |
| messages=messages, |
| max_tokens=1024, |
| temperature=0.7, |
| stream=True, |
| ) |
| usage_count[provider["name"]] += 1 |
|
|
| response_text = "" |
| for chunk in stream: |
| token = chunk.choices[0].delta.content or "" |
| response_text += token |
| yield response_text |
| return |
|
|
| except Exception as e: |
| err = str(e).lower() |
| tried.add(provider["name"]) |
|
|
| if "401" in err or "unauthorized" in err or "invalid api key" in err: |
| bad_keys.add(provider["name"]) |
| print(f"β {provider['name']} bad key β skipping for session") |
| elif "429" in err or "rate limit" in err or "quota" in err or "exceeded" in err: |
| print(f"β οΈ {provider['name']} rate limited β trying next provider") |
| else: |
| print(f"β οΈ {provider['name']} error: {e} β trying next provider") |
|
|
| |
| print("\n=== Provider Status ===") |
| for p in ALL_PROVIDERS: |
| key = API_KEYS.get(p["name"]) |
| status = "β
Active" if key not in (None, "") else "β No key" |
| print(f" {p['name']:<14} {status}") |
| print(f"\nActive providers: {len(ACTIVE_PROVIDERS)}/{len(ALL_PROVIDERS)}") |
| if not ACTIVE_PROVIDERS: |
| print("β οΈ WARNING: No API keys found in environment!") |
| print("=" * 23 + "\n") |
|
|
| |
| demo = gr.ChatInterface( |
| fn=respond, |
| title="βοΈ Minecraft Coding Assistant", |
| description=f"Multi-provider Β· {len(ACTIVE_PROVIDERS)} active Β· ~{sum(p['daily_limit'] for p in ACTIVE_PROVIDERS):,} req/day", |
| examples=[ |
| "How do I create a custom recipe in a datapack?", |
| "Write a Spigot plugin that teleports a player on command", |
| "What's the syntax for a /execute command with conditions?", |
| ], |
| cache_examples=False, |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|