import requests import json import re class LLMAcousticBridge: def __init__(self, model_name="dolphin-llama3:8b"): self.model_name = model_name self.api_url = "http://localhost:11434/api/generate" def _clean_json(self, text): """Вытаскивает чистый JSON из ответа нейросети.""" try: match = re.search(r'\{.*\}', text, re.DOTALL) if match: return json.loads(match.group(0)) return json.loads(text) except: return None def get_acoustic_profile(self, valence, arousal, scene_descriptions): """Просит LLM сгенерировать идеальный звук под описание.""" # Объединяем описания, если загружено несколько фото context_str = " | ".join(scene_descriptions) if scene_descriptions else "abstract scene" prompt = f"""You are an expert music producer and acoustic engineer. 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). Visual Context: {context_str}. Map this scene to exactly 6 acoustic features. Values MUST be floats between 0.0 and 1.0. 1. "energy": (Loudness/Density. High for massive/busy scenes, Low for calm) 2. "flux": (Rhythmic sharpness/Beat. High for action/people/cars, Low for static nature) 3. "centroid": (Brightness: 0=Dark/Bass/Massive, 1=Bright/Treble/Light) 4. "pitch": (Fundamental frequency: 0=Low pitch/Huge objects, 1=High pitch/Small objects) 5. "hnr": (Harmonics-to-Noise: 0=Noisy/Distorted textures, 1=Clear/Melodic/Smooth textures) 6. "zcr": (Percussiveness. High for detailed noise like leaves/rain, Low for solid blocks) Return ONLY a valid JSON object. Do not add any text or explanation. Example: {{"energy": 0.5, "flux": 0.2, "centroid": 0.4, "pitch": 0.3, "hnr": 0.8, "zcr": 0.1}}""" try: response = requests.post(self.api_url, json={ "model": self.model_name, "prompt": prompt, "stream": False, "format": "json" }, timeout=30) response.raise_for_status() result_text = response.json().get("response", "") profile = self._clean_json(result_text) # Проверяем, что все нужные ключи есть required_keys = ['energy', 'flux', 'centroid', 'pitch', 'hnr', 'zcr'] if profile and all(k in profile for k in required_keys): return profile return None except Exception as e: print(f"Ошибка связи с локальной LLM: {e}") return None