""" Сервис генерации гипнотических названий для картин галереи. Включает: - Локальный генератор псевдослучайных гипно-заголовков (в стиле Гипножабы, психоделики и мемов). - Закладку (интерфейс и спецификацию) для будущей интеграции с OpenRouter API (мультимодальные VLM). """ import random from typing import Optional # Словари для локального генератора гипно-тайтлов на английском языке HYPNO_ADJECTIVES = [ "Shimmering", "Astral", "Hypnotic", "Vulgar", "Surreal", "Absurd", "Psyche­delic", "Pulsating", "Neon", "Trans­cendent", "Cerebral", "Mental", "Subcon­scious", "Cosmic", "Halluci­nogenic", "Fractal", "Detached", "Synes­thetic", "Parallel", "Illusory", "Ephemeral", "Hypnot­oadian", "Conductive", "Mesme­rizing", "Magnetic", "Carefree", "Oneiric", "Psychot­ropic", "Mystical", "Other­worldly", "Spiral", "Quivering", "Slippery", "Misty", "Ethereal", "Trance", "Quantum", "Juicy", "Hypno-Absurd", "Psychoactive", "Magical", "Synthetic", "Chromatic", "Perceptive", "Perforated", "Vibra­tional", "Neural", "Subliminal", "Glitched", "Radioactive", "Brain-Melting", "Galactic", "Phospho­rescent", "Chaotic", "Hypnagogic", "Interdim­ensional", "Cybernetic", "Uncanny", ] HYPNO_NOUNS = [ "Trance", "Pulsar", "Gaze", "Brain Slug", "Vortex", "Portal", "Path", "Fractal", "Signal", "Spectrum", "Resonance", "Mirage", "Oasis", "Abyss", "Labyrinth", "Impulse", "Monolith", "Oracle", "Vector", "Clot", "Cascade", "Horizon", "Toadstool", "Pattern", "Contour", "Phantom", "Splash", "Tranqui­lizer", "Mist", "Crystal", "Stream", "Singulator", "Pulse", "Glitch", "Synthesis", "Roar", "Tremor", "Frontier", "Sentinel", "Gatekeeper", "Whisper", "Spore", "Worm", "Bubble", "Psycho-Spider", "Receptor", "Mind-Warp", "Hypnotoad", "Neuron", "Oscil­lation", "Echo", "Hologram", "Matrix", "Mind-drill", "Neurotoxin", "Dreamscape", "Substance", ] HYPNO_GENITIVES = [ "of Consciousness", "of the Hypnotoad", "of the Subcon­scious", "of the Void", "of the Matrix", "of the Psycho-Web", "of the Brain Slug", "of the Noosphere", "of the Neo-Modern", "of the Deep Trance", "of the Ether", "of the 4th Dimension", "of Pointillism", "of the Substance", "of Uncer­tainty", "of the Continuum", "of Acid", "of Pure Perception", "of Lucid Dreams", "of Halluci­nations", "of Psyche­delia", "of Trans­cendence", "of the Nether­world", "of DOOP Regul­ations", "of Galactic Frequencies", "of Grade 24 Bureaucracy", ] HYPNO_POSTFIXES = [ "#42", "v3.14", "(Ultra)", "(Phase 7)", "(Alpha)", "(Omega)", "(Protocol 09)", "(Revision 14)", "(Extract)", "(Layer 9)", "(Ward 106)", "(Hangar 18)", "(Unfinished Opus)", "(Secret Project)", "[Classified]", "(DOOP-66)", "(Sub-Level 4)", "(MK-Ultra)", "C90" ] def generate_hypno_title(seed: Optional[int] = None) -> str: """ Генерирует сочное гипнотическое название для картины на основе словарей. Примеры: - «Hypnotic Pulsar of the Hypnotoad #42» - «Astral Gaze» - «Brain Slug of the Void» - «Transcendent (Ultra)» - «Hypnotic» - «Vortex» """ rng = random.Random(seed) adj = rng.choice(HYPNO_ADJECTIVES) noun = rng.choice(HYPNO_NOUNS) genitive = rng.choice(HYPNO_GENITIVES) postfix = rng.choice(HYPNO_POSTFIXES) patterns = [ # Однословные варианты lambda: noun, lambda: adj, # Двухсловные комбинации lambda: f"{adj} {noun}", lambda: f"{noun} {genitive}", lambda: f"{noun} {postfix}", lambda: f"{adj} {postfix}", # Трех- и четырехсловные гипно-конструкции lambda: f"{adj} {noun} {genitive}", lambda: f"{adj} {noun} {postfix}", lambda: f"{adj} {noun} {genitive} {postfix}", ] chosen_pattern = rng.choice(patterns) return chosen_pattern() # ===================================================================== # ЗАКЛАДКА: OpenRouter VLM API Integration (Post-MVP / AI Title) # ===================================================================== def generate_title_openrouter( image_bytes: bytes, *, api_key: Optional[str] = None, model: str = "google/gemini-2.5-flash", system_prompt: str = ( "You are the herald of the almighty Hypnotoad. Create a short (2-4 words), " "punchy, ironically absurd, and hypnotic English title " "for a halftone SVG artwork shown in the thumbnail. " "Reply ONLY with the title, without quotes or introductory words." ), timeout: int = 5, ) -> Optional[str]: """ [ЗАКЛАДКА ПОД OPENROUTER API] Спецификация интеграции: 1. Исходное растровое изображение сжимается до thumbnail 256x256 WebP/JPEG. 2. Кодируется в Base64 (data:image/jpeg;base64,...). 3. Отправляется POST-запрос на https://openrouter.ai/api/v1/chat/completions: Payload: { "model": model, "messages": [ {"role": "system", "content": system_prompt}, { "role": "user", "content": [ {"type": "text", "text": "Give a hypnotic title for this artwork:"}, {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64_data}"}} ] } ], "max_tokens": 50, "temperature": 0.9 } 4. При ошибке таймаута, отсутствии OPENROUTER_API_KEY в .env или сбое сети функция возвращает None, вызывая локальный fallback (generate_hypno_title). """ # TODO: Интегрировать requests / httpx при добавлении OPENROUTER_API_KEY в settings.py if not api_key: return None # Заглушка: при отсутствии реального сетевого коннектора возвращаем None для fallback return None