From 14c2bc2da7eb835a5839b56b014e211ce8979748 Mon Sep 17 00:00:00 2001 From: zin Date: Sun, 28 Jun 2026 18:51:32 +0000 Subject: [PATCH] EOL: Final release --- src/music_engine/llm_bridge.py | 52 +++++++++++++++---------- src/music_engine/matcher.py | 2 +- src/scripts/22_extract_embeddings.ipynb | 4 +- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/music_engine/llm_bridge.py b/src/music_engine/llm_bridge.py index 4e17ff5..5662d64 100644 --- a/src/music_engine/llm_bridge.py +++ b/src/music_engine/llm_bridge.py @@ -2,16 +2,16 @@ import os import json import re import requests +from typing import List, Dict class LLMAcousticBridge: - def __init__(self, model_name="dolphin-llama3:8b"): + def __init__(self, model_name: str = "dolphin-llama3:8b"): self.model_name = model_name base_url = os.getenv("OLLAMA_API_URL", "http://emom_ollama:11434") 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" - prompt = f""" 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). @@ -34,32 +34,42 @@ class LLMAcousticBridge: "model": self.model_name, "prompt": prompt, "stream": False, - "format": "json" # Принудительный JSON-режим Ollama + "format": "json", + "options": { + "temperature": 0.7, + "top_p": 0.9 + } } print(f"Запрос акустического профиля к Ollama...") response = requests.post(self.api_url, json=payload, timeout=120) + response.raise_for_status() - if response.status_code == 200: - data = response.json() - response_text = data.get("response", "") - - try: - # 1. Попытка прямой десериализации - profile = json.loads(response_text) - return profile - except json.JSONDecodeError: - # 2. Аварийное извлечение JSON из текста с помощью регулярного выражения - match = re.search(r'\{.*\}', response_text, re.DOTALL) - if match: - return json.loads(match.group(0)) - - print(f"Ошибка парсинга LLM ответа: {response_text}") + data = response.json() + response_text = data.get("response", "") + + profile = {} + try: + profile = json.loads(response_text) + except json.JSONDecodeError: + match = re.search(r'\{.*\}', response_text, re.DOTALL) + if match: + profile = json.loads(match.group(0)) + else: + print(f"[ERROR] Ошибка парсинга LLM ответа: {response_text}") 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: - print(f"Ollama вернула ошибку HTTP: {response.status_code}") + print(f"[WARN] LLM вернула неполный JSON, активирован fallback: {profile}") return {} + except requests.exceptions.RequestException as e: + print(f"[ERROR] Ошибка соединения с Ollama: {str(e)}") + return {} except Exception as e: - print(f"Ошибка соединения с Ollama: {str(e)}") + print(f"[ERROR] Внутренняя ошибка семантического моста: {str(e)}") return {} \ No newline at end of file diff --git a/src/music_engine/matcher.py b/src/music_engine/matcher.py index 22cf06b..727eaa8 100644 --- a/src/music_engine/matcher.py +++ b/src/music_engine/matcher.py @@ -78,6 +78,6 @@ class MusicMatcher: 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) \ No newline at end of file diff --git a/src/scripts/22_extract_embeddings.ipynb b/src/scripts/22_extract_embeddings.ipynb index 78498e7..5e05efa 100644 --- a/src/scripts/22_extract_embeddings.ipynb +++ b/src/scripts/22_extract_embeddings.ipynb @@ -264,9 +264,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (thesis)", + "display_name": "Python (my-python-project)", "language": "python", - "name": "thesis" + "name": "my-python-project" }, "language_info": { "codemirror_mode": {