Files
wiki/tasks/karaoke/nlp.py
2026-04-30 00:30:01 +03:00

124 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
nlp.py — GigaChat NLP-анализ текста песни → {mood, scenes}
"""
import json
import os
import requests
from dotenv import load_dotenv
load_dotenv(os.path.expanduser("~/.openclaw/.env"))
def get_gigachat_token() -> str:
"""Получить access_token GigaChat через GigaChat API."""
base_url = os.environ.get("GIGACHAT_BASE_URL", "https://gigachat.devices.sberbank.ru")
# По ТЗ: через прокси 185.130.212.192:8443
creds = os.environ.get("GIGACHAT_CREDS", "")
token_url = os.environ.get("GIGACHAT_TOKEN_URL", f"{base_url}/api/v2/oauth")
headers = {
"Authorization": f"Basic {creds}",
"RqUID": "00000000-0000-0000-0000-000000000000",
"Content-Type": "application/x-www-form-urlencoded",
}
resp = requests.post(token_url, headers=headers, data={"scope": "GIGACHAT_API_PERS"},
verify=False, timeout=15)
resp.raise_for_status()
return resp.json()["access_token"]
def analyze(text: str) -> dict:
"""
Отправить текст в GigaChat, получить {mood, scenes}.
При ошибке возвращает fallback.
"""
try:
base_url = os.environ.get("GIGACHAT_BASE_URL", "https://gigachat.devices.sberbank.ru")
token = get_gigachat_token()
except Exception as e:
print(f"[nlp] GigaChat недоступен: {e}. Используем fallback.")
return _fallback(text)
prompt = (
"Определи настроение и 3-5 ключевых визуальных сцен для этой песни. "
"Ответь ТОЛЬКО JSON без обёрток:\n"
'{"mood": "строка", "scenes": ["сцена1", "сцена2", ...]}'
"\n\nТекст песни:\n" + text[:3000]
)
url = f"{base_url}/api/v1/chat/completions"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
body = {
"model": "GigaChat",
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.3,
}
try:
resp = requests.post(url, headers=headers, json=body,
verify=False, timeout=30)
resp.raise_for_status()
data = resp.json()
content = data["choices"][0]["message"]["content"].strip()
# Парсим JSON из ответа — иногда модель возвращает markdown-обёртку
content = content.strip().strip("```json").strip("```").strip()
result = json.loads(content)
print(f"[nlp] GigaChat ответ: mood={result.get('mood')}, scenes={result.get('scenes')}")
return result
except Exception as e:
print(f"[nlp] Ошибка GigaChat API: {e}. Используем fallback.")
return _fallback(text)
def _fallback(text: str) -> dict:
"""Простой fallback без API."""
text_lower = text.lower()
mood_map = {
"love": "romantic", "любов": "romantic", "heart": "romantic",
"сердц": "romantic", "kiss": "romantic", "night": "moody",
"ноч": "moody", "dark": "moody", "темн": "moody",
"rain": "moody", "дожд": "moody", "sun": "happy",
"солнц": "happy", "свет": "happy", "light": "happy",
"party": "energetic", "танц": "energetic", "dance": "energetic",
"drive": "energetic", "драйв": "energetic",
"sad": "sad", "груст": "sad", "cry": "sad", "плач": "sad",
}
mood = "neutral"
for key, val in mood_map.items():
if key in text_lower:
mood = val
break
scene_map = {
"love": "romantic couple", "любов": "romantic sunset",
"night": "city night lights", "ноч": "starry sky",
"sun": "golden hour landscape", "солнц": "sunrise nature",
"rain": "rain window", "дожд": "rainy city",
"party": "party lights", "танц": "dance floor",
"sad": "solitary person", "груст": "lonely road",
"sea": "ocean waves", "мор": "ocean sunset",
"mountain": "mountain peaks", "гор": "mountain landscape",
"fire": "campfire", "огон": "firelight",
"snow": "snowy landscape", "снег": "winter forest",
"лес": "forest path", "forest": "forest path",
"road": "highway drive", "дорог": "open road",
}
scenes = ["abstract gradient"]
for key, val in scene_map.items():
if key in text_lower:
scenes.append(val)
scenes = scenes[:5]
if len(scenes) < 1:
scenes = ["abstract gradient"]
return {"mood": mood, "scenes": scenes}