EOL: Final release

This commit is contained in:
zin
2026-06-28 18:51:32 +00:00
parent 934a4cbff4
commit 14c2bc2da7
3 changed files with 34 additions and 24 deletions
+31 -21
View File
@@ -2,16 +2,16 @@ import os
import json import json
import re import re
import requests import requests
from typing import List, Dict
class LLMAcousticBridge: class LLMAcousticBridge:
def __init__(self, model_name="dolphin-llama3:8b"): def __init__(self, model_name: str = "dolphin-llama3:8b"):
self.model_name = model_name self.model_name = model_name
base_url = os.getenv("OLLAMA_API_URL", "http://emom_ollama:11434") base_url = os.getenv("OLLAMA_API_URL", "http://emom_ollama:11434")
self.api_url = f"{base_url}/api/generate" self.api_url = f"{base_url}/api/generate"
def get_acoustic_profile(self, valence, arousal, semantics): def get_acoustic_profile(self, valence: float, arousal: float, semantics: List[str]) -> Dict[str, float]:
context_str = ", ".join(semantics) if semantics else "abstract scene" context_str = ", ".join(semantics) if semantics else "abstract scene"
prompt = f""" prompt = f"""
Analyze the visual context and emotions to determine the ideal background music properties. Analyze the visual context and emotions to determine the ideal background music properties.
Emotions: Valence {valence:.1f}/9.0 (Positivity), Arousal {arousal:.1f}/9.0 (Energy). Emotions: Valence {valence:.1f}/9.0 (Positivity), Arousal {arousal:.1f}/9.0 (Energy).
@@ -34,32 +34,42 @@ class LLMAcousticBridge:
"model": self.model_name, "model": self.model_name,
"prompt": prompt, "prompt": prompt,
"stream": False, "stream": False,
"format": "json" # Принудительный JSON-режим Ollama "format": "json",
"options": {
"temperature": 0.7,
"top_p": 0.9
}
} }
print(f"Запрос акустического профиля к Ollama...") print(f"Запрос акустического профиля к Ollama...")
response = requests.post(self.api_url, json=payload, timeout=120) response = requests.post(self.api_url, json=payload, timeout=120)
response.raise_for_status()
if response.status_code == 200: data = response.json()
data = response.json() response_text = data.get("response", "")
response_text = data.get("response", "")
profile = {}
try: try:
# 1. Попытка прямой десериализации profile = json.loads(response_text)
profile = json.loads(response_text) except json.JSONDecodeError:
return profile match = re.search(r'\{.*\}', response_text, re.DOTALL)
except json.JSONDecodeError: if match:
# 2. Аварийное извлечение JSON из текста с помощью регулярного выражения profile = json.loads(match.group(0))
match = re.search(r'\{.*\}', response_text, re.DOTALL) else:
if match: print(f"[ERROR] Ошибка парсинга LLM ответа: {response_text}")
return json.loads(match.group(0))
print(f"Ошибка парсинга LLM ответа: {response_text}")
return {} return {}
# 3. Жесткая валидация ключей (чтобы matcher.py не упал на демо)
required_keys = ['energy', 'flux', 'centroid', 'pitch', 'hnr', 'zcr']
if profile and all(k in profile for k in required_keys):
return profile
else: else:
print(f"Ollama вернула ошибку HTTP: {response.status_code}") print(f"[WARN] LLM вернула неполный JSON, активирован fallback: {profile}")
return {} return {}
except requests.exceptions.RequestException as e:
print(f"[ERROR] Ошибка соединения с Ollama: {str(e)}")
return {}
except Exception as e: except Exception as e:
print(f"Ошибка соединения с Ollama: {str(e)}") print(f"[ERROR] Внутренняя ошибка семантического моста: {str(e)}")
return {} return {}
+1 -1
View File
@@ -78,6 +78,6 @@ class MusicMatcher:
self.norm_db['acoustic_distance'] = acoustic_penalty / len(self.acoustic_features) self.norm_db['acoustic_distance'] = acoustic_penalty / len(self.acoustic_features)
# Вычисление интегральной метрики соответствия (мультимодальный скоринг) # Вычисление интегральной метрики соответствия (мультимодальный скоринг)
self.norm_db['final_score'] = self.norm_db['emo_distance'] + (self.norm_db['acoustic_distance'] * 4.0) self.norm_db['final_score'] = self.norm_db['emo_distance'] + (self.norm_db['acoustic_distance'] * 2.0)
return self.norm_db.sort_values(by='final_score').head(top_k) return self.norm_db.sort_values(by='final_score').head(top_k)
+2 -2
View File
@@ -264,9 +264,9 @@
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "Python (thesis)", "display_name": "Python (my-python-project)",
"language": "python", "language": "python",
"name": "thesis" "name": "my-python-project"
}, },
"language_info": { "language_info": {
"codemirror_mode": { "codemirror_mode": {