Spaces:
Running
Running
| """ | |
| Utility functions and constants for AI-Inferoxy AI Hub. | |
| Contains configuration constants and helper functions. | |
| """ | |
| import os | |
| import re | |
| # Configuration constants | |
| DEFAULT_CHAT_MODEL = "openai/gpt-oss-20b" | |
| DEFAULT_IMAGE_MODEL = "Qwen/Qwen-Image" | |
| DEFAULT_IMAGE_TO_IMAGE_MODEL = "Qwen/Qwen-Image-Edit" | |
| DEFAULT_TTS_MODEL = "hexgrad/Kokoro-82M" | |
| DEFAULT_VIDEO_MODEL = "Wan-AI/Wan2.2-T2V-A14B" | |
| # Unified default provider used by all non-chat tasks | |
| DEFAULT_PROVIDER = "auto" | |
| # Chat configuration | |
| CHAT_CONFIG = { | |
| "max_tokens": 1024, | |
| "temperature": 0.7, | |
| "top_p": 0.95, | |
| "system_message": "You are a helpful and friendly AI assistant. Provide clear, accurate, and helpful responses." | |
| } | |
| # Image generation configuration | |
| IMAGE_CONFIG = { | |
| "width": 1024, | |
| "height": 1024, | |
| "num_inference_steps": 20, | |
| "guidance_scale": 7.5, | |
| "seed": -1, | |
| "negative_prompt": "blurry, low quality, distorted, deformed, ugly, bad anatomy" | |
| } | |
| # Supported providers (unified across tasks) | |
| PROVIDERS_UNIFIED = [ | |
| "auto", | |
| "cerebras", | |
| "cohere", | |
| "fal-ai", | |
| "featherless-ai", | |
| "fireworks-ai", | |
| "groq", | |
| "hf-inference", | |
| "hyperbolic", | |
| "nebius", | |
| "novita", | |
| "nscale", | |
| "replicate", | |
| "sambanova", | |
| "together", | |
| ] | |
| # Backwards compatibility exported lists | |
| CHAT_PROVIDERS = PROVIDERS_UNIFIED | |
| IMAGE_PROVIDERS = PROVIDERS_UNIFIED | |
| # Popular models for quick access | |
| POPULAR_CHAT_MODELS = [ | |
| "openai/gpt-oss-20b", | |
| "meta-llama/Llama-2-7b-chat-hf", | |
| "microsoft/DialoGPT-medium", | |
| "google/flan-t5-base" | |
| ] | |
| POPULAR_IMAGE_MODELS = [ | |
| "Qwen/Qwen-Image", | |
| "black-forest-labs/FLUX.1-dev", | |
| "stabilityai/stable-diffusion-xl-base-1.0", | |
| "runwayml/stable-diffusion-v1-5" | |
| ] | |
| # Suggested model lists (users can still input any model id) | |
| SUGGESTED_CHAT_MODELS = [ | |
| "openai/gpt-oss-20b", | |
| "openai/gpt-oss-120b", | |
| "deepseek-ai/DeepSeek-V3.1", | |
| "zai-org/GLM-4.5", | |
| "Qwen/Qwen3-8B", | |
| "meta-llama/Llama-3.1-8B-Instruct", | |
| "deepseek-ai/DeepSeek-R1", | |
| "moonshotai/Kimi-K2-Instruct", | |
| "Qwen/Qwen3-Coder-30B-A3B-Instruct", | |
| "CohereLabs/command-a-reasoning-08-2025", | |
| ] | |
| SUGGESTED_IMAGE_MODELS = [ | |
| "Qwen/Qwen-Image", | |
| "black-forest-labs/FLUX.1-dev", | |
| "black-forest-labs/FLUX.1-Krea-dev", | |
| "stabilityai/stable-diffusion-xl-base-1.0", | |
| "black-forest-labs/FLUX.1-schnell", | |
| "UmeAiRT/FLUX.1-dev-LoRA-Modern_Pixel_art", | |
| "xey/sldr_flux_nsfw_v2-studio", | |
| "HiDream-ai/HiDream-I1-Full", | |
| "Kwai-Kolors/Kolors", | |
| ] | |
| SUGGESTED_IMAGE_TO_IMAGE_MODELS = [ | |
| "Qwen/Qwen-Image-Edit", | |
| "Kontext-Style/Ghibli_lora", | |
| "black-forest-labs/FLUX.1-Kontext-dev", | |
| "fofr/kontext-make-person-real", | |
| "jerrrycans/watermark20000", | |
| "fal/Pencil-Drawing-Kontext-Dev-LoRA", | |
| ] | |
| SUGGESTED_VIDEO_MODELS = [ | |
| "Wan-AI/Wan2.2-T2V-A14B", | |
| "Wan-AI/Wan2.2-TI2V-5B", | |
| "tencent/HunyuanVideo", | |
| "Wan-AI/Wan2.2-T2V-A14B-Diffusers", | |
| "zai-org/CogVideoX-5b", | |
| "Wan-AI/Wan2.1-T2V-14B", | |
| "genmo/mochi-1-preview", | |
| "Wan-AI/Wan2.1-T2V-1.3B", | |
| "Lightricks/LTX-Video-0.9.7-dev", | |
| "Lightricks/LTX-Video-0.9.5", | |
| "Lightricks/LTX-Video-0.9.7-distilled", | |
| ] | |
| # Model-specific configurations for TTS | |
| TTS_MODEL_CONFIGS = { | |
| "hexgrad/Kokoro-82M": { | |
| "type": "kokoro", | |
| "supports_voice": True, | |
| "supports_speed": True, | |
| "extra_body_params": ["voice", "speed"] | |
| }, | |
| "ResembleAI/chatterbox": { | |
| "type": "chatterbox", | |
| "supports_voice": False, | |
| "supports_speed": False, | |
| "extra_body_params": ["audio_url", "exaggeration", "temperature", "cfg"] | |
| }, | |
| "nari-labs/Dia-1.6B": { | |
| "type": "dia", | |
| "supports_voice": False, | |
| "supports_speed": False, | |
| "extra_body_params": [] | |
| } | |
| } | |
| # ----------------------------- | |
| # Text-to-Video configuration | |
| # ----------------------------- | |
| # Example prompts for text-to-video generation | |
| VIDEO_EXAMPLE_PROMPTS = [ | |
| "A young man walking on the street", | |
| "A corgi puppy running through a field of flowers, cinematic", | |
| "A futuristic city skyline at sunset with flying cars, 4k", | |
| "A serene beach with gentle waves and palm trees swaying", | |
| ] | |
| # Voice options for Kokoro TTS (based on the reference app) | |
| TTS_VOICES = { | |
| 'πΊπΈ πΊ Heart β€οΈ': 'af_heart', | |
| 'πΊπΈ πΊ Bella π₯': 'af_bella', | |
| 'πΊπΈ πΊ Nicole π§': 'af_nicole', | |
| 'πΊπΈ πΊ Aoede': 'af_aoede', | |
| 'πΊπΈ πΊ Kore': 'af_kore', | |
| 'πΊπΈ πΊ Sarah': 'af_sarah', | |
| 'πΊπΈ πΊ Nova': 'af_nova', | |
| 'πΊπΈ πΊ Sky': 'af_sky', | |
| 'πΊπΈ πΊ Alloy': 'af_alloy', | |
| 'πΊπΈ πΊ Jessica': 'af_jessica', | |
| 'πΊπΈ πΊ River': 'af_river', | |
| 'πΊπΈ πΉ Michael': 'am_michael', | |
| 'πΊπΈ πΉ Fenrir': 'am_fenrir', | |
| 'πΊπΈ πΉ Puck': 'am_puck', | |
| 'πΊπΈ πΉ Echo': 'am_echo', | |
| 'πΊπΈ πΉ Eric': 'am_eric', | |
| 'πΊπΈ πΉ Liam': 'am_liam', | |
| 'πΊπΈ πΉ Onyx': 'am_onyx', | |
| 'πΊπΈ πΉ Santa': 'am_santa', | |
| 'πΊπΈ πΉ Adam': 'am_adam', | |
| 'π¬π§ πΊ Emma': 'bf_emma', | |
| 'π¬π§ πΊ Isabella': 'bf_isabella', | |
| 'π¬π§ πΊ Alice': 'bf_alice', | |
| 'π¬π§ πΊ Lily': 'bf_lily', | |
| 'π¬π§ πΉ George': 'bm_george', | |
| 'π¬π§ πΉ Fable': 'bm_fable', | |
| 'π¬π§ πΉ Lewis': 'bm_lewis', | |
| 'π¬π§ πΉ Daniel': 'bm_daniel', | |
| } | |
| # Example prompts for chat | |
| CHAT_EXAMPLE_PROMPTS = [ | |
| "What's a polite way to introduce myself at a networking event?", | |
| "Can you suggest a fun icebreaker question for a group chat?", | |
| "Explain the concept of entropy in simple terms suitable for a high school student.", | |
| "Summarize the main differences between classical and operant conditioning.", | |
| "Is it possible for artificial intelligence to possess consciousness? Discuss briefly.", | |
| "What does 'the map is not the territory' mean in philosophy?", | |
| "Write a Python function to reverse a linked list.", | |
| "How can I optimize a SQL query for faster performance?", | |
| "Suggest 3 imaginative prompts for generating images of futuristic cities.", | |
| "Give me 3 creative prompts for generating surreal animal portraits.", | |
| ] | |
| # Example prompts for image generation | |
| IMAGE_EXAMPLE_PROMPTS = [ | |
| "A majestic dragon flying over a medieval castle, epic fantasy art, detailed, 8k", | |
| "A serene Japanese garden with cherry blossoms, zen atmosphere, peaceful, high quality", | |
| "A futuristic cityscape with flying cars and neon lights, cyberpunk style, cinematic", | |
| "A cute robot cat playing with yarn, adorable, cartoon style, vibrant colors", | |
| "A magical forest with glowing mushrooms and fairy lights, fantasy, ethereal beauty", | |
| "Portrait of a wise old wizard with flowing robes, magical aura, fantasy character art", | |
| "A cozy coffee shop on a rainy day, warm lighting, peaceful atmosphere, detailed", | |
| "An astronaut floating in space with Earth in background, photorealistic, stunning" | |
| ] | |
| # Example prompts for image-to-image generation | |
| IMAGE_TO_IMAGE_EXAMPLE_PROMPTS = [ | |
| "Turn the cat into a tiger with stripes and fierce expression", | |
| "Turn this image into the Ghibli style.", | |
| "Make the background a magical forest with glowing mushrooms", | |
| "Change the style to vintage comic book with bold colors", | |
| "Add a superhero cape and mask to the person", | |
| "Transform the building into a futuristic skyscraper", | |
| "Make the flowers bloom and add butterflies around them", | |
| "Change the weather to a stormy night with lightning", | |
| "Add a magical portal in the background with sparkles" | |
| ] | |
| # Example texts for text-to-speech generation | |
| TTS_EXAMPLE_TEXTS = [ | |
| "Hello! Welcome to the amazing world of AI-powered text-to-speech technology.", | |
| "The quick brown fox jumps over the lazy dog. This pangram contains every letter of the alphabet.", | |
| "In a world where technology advances at lightning speed, artificial intelligence continues to reshape our future.", | |
| "Imagine a world where machines can understand and respond to human emotions with perfect clarity.", | |
| "The future belongs to those who believe in the beauty of their dreams and have the courage to pursue them.", | |
| "Science is not only compatible with spirituality; it is a profound source of spirituality.", | |
| "The only way to do great work is to love what you do. If you haven't found it yet, keep looking.", | |
| "Life is what happens when you're busy making other plans. Embrace every moment with gratitude.", | |
| "[S1] Dia is an open weights text to dialogue model. [S2] You get full control over scripts and voices. [S1] Wow. Amazing. (laughs) [S2] Try it now." | |
| ] | |
| # Example audio URLs for Chatterbox TTS | |
| TTS_EXAMPLE_AUDIO_URLS = [ | |
| "https://github.com/nazdridoy/kokoro-tts/raw/main/previews/demo.mp3", | |
| "https://storage.googleapis.com/chatterbox-demo-samples/prompts/male_rickmorty.mp3" | |
| ] | |
| def get_proxy_key(): | |
| """Get the proxy API key from environment variables.""" | |
| return os.getenv("PROXY_KEY") | |
| def validate_proxy_key(): | |
| """Validate that the proxy key is available.""" | |
| proxy_key = get_proxy_key() | |
| if not proxy_key: | |
| return False, "β Error: PROXY_KEY not found in environment variables. Please set it in your HuggingFace Space secrets." | |
| return True, "" | |
| def get_proxy_url(): | |
| """Get the proxy URL from environment variables.""" | |
| return os.getenv("PROXY_URL") | |
| def validate_proxy_url(): | |
| """Validate that the proxy URL is available.""" | |
| proxy_url = get_proxy_url() | |
| if not proxy_url: | |
| return False, "β Error: PROXY_URL not found in environment variables. Please set it in your HuggingFace Space secrets." | |
| return True, "" | |
| def format_error_message(error_type, error_message): | |
| """Format error messages consistently.""" | |
| return f"β {error_type}: {error_message}" | |
| def format_success_message(operation, details=""): | |
| """Format success messages consistently.""" | |
| base_message = f"β {operation} completed successfully" | |
| if details: | |
| return f"{base_message}: {details}" | |
| return f"{base_message}!" | |
| def get_gradio_theme(): | |
| """Get the default Gradio theme for the application.""" | |
| try: | |
| import gradio as gr | |
| return gr.themes.Soft() | |
| except ImportError: | |
| return None | |
| # ----------------------------- | |
| # Reasoning (<think>) utilities | |
| # ----------------------------- | |
| def render_with_reasoning_toggle(text: str, show_reasoning: bool) -> str: | |
| """Render assistant text while optionally revealing content inside <think>...</think>. | |
| Behavior: | |
| - When show_reasoning is True: | |
| * Replace the opening <think> tag with a collapsible HTML <details> block and an opening | |
| fenced code block. Stream reasoning tokens inside this block as they arrive. | |
| * Replace the closing </think> tag with the closing fence and </details> when it appears. | |
| - When show_reasoning is False: | |
| * Remove complete <think>...</think> blocks. | |
| * For partial streams (no closing tag yet), trim everything from the first <think> onward. | |
| Safe to call on every streamed chunk; conversions are idempotent. | |
| """ | |
| if not isinstance(text, str): | |
| return text | |
| # If we are NOT showing reasoning, remove it entirely. For partial streams, hide from <think> onwards. | |
| if not show_reasoning: | |
| if "<think>" not in text: | |
| return text | |
| if "</think>" not in text: | |
| return text.split("<think>", 1)[0] | |
| # Remove complete <think>...</think> blocks | |
| pattern_strip = re.compile(r"<think>[\s\S]*?</think>", re.IGNORECASE) | |
| return pattern_strip.sub("", text) | |
| # Show reasoning: stream it as it arrives by converting tags into a collapsible details block | |
| open_block_open = "<details open><summary>Reasoning</summary>\n\n```text\n" | |
| open_block_closed = "<details><summary>Reasoning</summary>\n\n```text\n" | |
| close_block = "\n```\n</details>\n" | |
| # If the closing tag is not present yet, keep the block expanded while streaming | |
| if "</think>" not in text: | |
| # Replace any raw <think> with an expanded details block | |
| text = re.sub(r"<think>", open_block_open, text, flags=re.IGNORECASE) | |
| # If for any reason a closed details opening exists, switch it to open (expanded) | |
| text = text.replace(open_block_closed, open_block_open) | |
| return text | |
| # If the closing tag is present, render a collapsed block by default | |
| # 1) Ensure opening is the closed variant | |
| text = re.sub(r"<think>", open_block_closed, text, flags=re.IGNORECASE) | |
| text = text.replace(open_block_open, open_block_closed) | |
| # 2) Close the block | |
| text = re.sub(r"</think>", close_block, text, flags=re.IGNORECASE) | |
| return text | |