119 lines
7.3 KiB
Python
119 lines
7.3 KiB
Python
"""
|
||
Сервис генерации гипнотических названий для картин галереи.
|
||
|
||
Включает:
|
||
- Локальный генератор псевдослучайных гипно-заголовков (в стиле Гипножабы, психоделики и мемов).
|
||
- Закладку (интерфейс и спецификацию) для будущей интеграции с OpenRouter API (мультимодальные VLM).
|
||
"""
|
||
|
||
import random
|
||
from typing import Optional
|
||
|
||
|
||
# Словари для локального генератора гипно-тайтлов
|
||
HYPNO_ADJECTIVES = [
|
||
"мерцающий", "астральный", "гипнотический", "вульгарный", "сюрреалистический", "абсурдный", "психоделический",
|
||
"пульсирующий", "неоновый", "трансцендентный", "мозговой", "ментальный", "бессознательный", "космический",
|
||
"галлюциногенный", "фрактальный", " отрешённый", "синестетический", "параллельный", "иллюзорный", "эфемерный",
|
||
"гипножабий", "проводящий", "тошнотворный", "завораживающий", "магнетический", "беспечный", "сновидческий",
|
||
"психотропный", "мистический", "потусторонний", "беспечный", "сновидческий", "психотропный", "мистический",
|
||
"потусторонний", "спиральный", "зыбкий", "пахучий", "скользкий", "туманный", "онейрический", "эфирный",
|
||
"трансовый", "квантовый", "сочный", "гипно-абсурдный", "психоактивный", "сюрреалистичный", "магический",
|
||
"синтетический", "хроматический", "перцептивный", "психоделичный", "галлюцинаторный", "трансцендентальный",
|
||
"перфорированный",
|
||
]
|
||
|
||
HYPNO_NOUNS = [
|
||
"транс", "пульсар", "взгляд", "слизень", "вихрь", "портал", "путь", "фрактал", "сигнал", "спектр",
|
||
"резонанс", "морок", "оазис", "омут", "лабиринт", "импульс", "монолит", "оракул", "вектор",
|
||
"сгусток", "каскад", "горизонт", "мухомор", "паттерн", "контур", "фантом", "всплеск", "мираж", "транквилизатор",
|
||
"взмах", "взгляд", "морок", "туман", "свет", "кристалл", "поток", "сингулятор", "снег", "пульс", "глюк",
|
||
"качан", "сигнал", "поток", "свет", "синтез", "рык", "трепет", "плюх", "Му", "бip-бip", "карачун", "фронтир",
|
||
"сторож", "привратник", "шёпот", "шлепок по жопе", "гриб", "плевок", "червяк", "пузырь", "психо-паук",
|
||
]
|
||
|
||
HYPNO_GENITIVES = [
|
||
"сознания", "Гипножабы", "бессознательного", "пустоты", "матрицы", "психо-паутины", "слизня", "ноосферы",
|
||
"нео-модерна", "транса", "глубины", "эфира", "плесени", "измерения", "пуантилизма", "субстанции",
|
||
"неопределенности", "континуума", "кислоты", "сына подруги твоей мамы"
|
||
]
|
||
|
||
HYPNO_POSTFIXES = [
|
||
"#42", "v3.14", "(Ultra)", "(Фаза 7)", "(Альфа)", "(Омега)", "(Протокол 09)", "(Ревизия 14)", "(Экстракт)",
|
||
"(Слой 9)", "(Палата №6)", "(Ангар 18)", "(Неоконченное произведение)", "(Секретный проект)",
|
||
]
|
||
|
||
|
||
def generate_hypno_title(seed: Optional[int] = None) -> str:
|
||
"""
|
||
Генерирует сочное гипнотическое название для картины на основе словарей.
|
||
Примеры:
|
||
- «Мерцающий Транс сознания #42»
|
||
- «Гипножабий Пульсар психо-паутины»
|
||
- «Астральный Взгляд v3.14»
|
||
"""
|
||
rng = random.Random(seed)
|
||
adj = rng.choice(HYPNO_ADJECTIVES)
|
||
noun = rng.choice(HYPNO_NOUNS)
|
||
|
||
pattern_type = rng.randint(1, 3)
|
||
if pattern_type == 1:
|
||
genitive = rng.choice(HYPNO_GENITIVES)
|
||
postfix = rng.choice(HYPNO_POSTFIXES)
|
||
return f"{adj} {noun} {genitive} {postfix}"
|
||
elif pattern_type == 2:
|
||
genitive = rng.choice(HYPNO_GENITIVES)
|
||
return f"{adj} {noun} {genitive}"
|
||
else:
|
||
postfix = rng.choice(HYPNO_POSTFIXES)
|
||
return f"{adj} {noun} {postfix}"
|
||
|
||
|
||
# =====================================================================
|
||
# ЗАКЛАДКА: 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 = (
|
||
"Ты — глашатай всемогущей Гипножабы. Придумай короткое (2-4 слова), "
|
||
"яркое, иронично-абсурдное и гипнотическое название на русском языке "
|
||
"для полутоновой SVG-картины, изображенной на миниатюре. "
|
||
"Отвечай ТОЛЬКО названием, без кавычек и вводных слов."
|
||
),
|
||
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": "Дай гипнотическое название для этой картины:"},
|
||
{"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
|