From ac9a53c1fa0c92c742b84a3d9ec774baea9eaca0 Mon Sep 17 00:00:00 2001 From: yasusan Date: Tue, 2 Jun 2026 13:11:19 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20setup=5Femotion.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup_emotion.sh | 283 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 setup_emotion.sh diff --git a/setup_emotion.sh b/setup_emotion.sh new file mode 100644 index 0000000..85bd0b2 --- /dev/null +++ b/setup_emotion.sh @@ -0,0 +1,283 @@ +#!/bin/bash +set -e + +# --- НАСТРОЙКИ (ПРОВЕРЬТЕ ПЕРЕД ЗАПУСКОМ) --- +EMOTION_HOST="192.168.254.37" +EMOTION_PORT="8001" +PROCESSOR_PORT="8003" +DB_HOST="192.168.254.35" +DB_PORT="5432" +DB_NAME="asr_db" +DB_USER="asr_user" +DB_PASSWORD="poluyan77" +# --- КОНЕЦ НАСТРОЕК --- + +echo "=== 1. Установка базовых пакетов ===" +sudo apt update +sudo apt install -y python3 python3-pip python3-venv ffmpeg git + +echo "=== 2. Создание проекта и виртуального окружения ===" +sudo mkdir -p /opt/emotion +sudo chown root:root /opt/emotion +cd /opt/emotion +python3 -m venv venv +source venv/bin/activate + +echo "=== 3. Установка Python-пакетов ===" +pip install torch==2.5.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cpu +pip install fastapi uvicorn python-multipart transformers psycopg2-binary requests + +echo "=== 4. Создание сервера эмоций (server_text_final.py) ===" +sudo tee /opt/emotion/server_text_final.py << 'EOF' +from fastapi import FastAPI, Form +from fastapi.responses import JSONResponse +from transformers import pipeline + +app = FastAPI(title="Text Emotion Recognition API") + +print("Загрузка модели...") +classifier = pipeline("text-classification", model="Aniemore/rubert-tiny2-russian-emotion-detection") +print("Модель загружена") + +emotions_map = { + "neutral": "нейтрально", + "happy": "радость", + "sadness": "грусть", + "sad": "грусть", + "anger": "злость", + "angry": "злость", + "fear": "страх", + "surprise": "удивление", + "surprised": "удивление", + "disgust": "отвращение" +} + +@app.post("/analyze") +async def analyze_emotion(text: str = Form(...)): + try: + result = classifier(text)[0] + emotion = emotions_map.get(result['label'], result['label']) + confidence = result['score'] + return {"status": "ok", "emotion": emotion, "confidence": confidence} + except Exception as e: + return JSONResponse(status_code=500, content={"error": str(e)}) + +@app.get("/health") +async def health(): + return {"status": "ok"} + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8001) +EOF + +echo "=== 5. Создание фонового процессора эмоций (emotion_processor.py) ===" +sudo tee /opt/emotion/emotion_processor.py << 'EOF' +#!/usr/bin/env python3 +import psycopg2 +import time +import requests +from datetime import datetime + +DB_CONFIG = { + "host": "192.168.254.35", + "port": 5432, + "database": "asr_db", + "user": "asr_user", + "password": "poluyan77" +} + +def log(msg): + print(f"[{datetime.now()}] {msg}") + +def process_pending_calls(): + conn = psycopg2.connect(**DB_CONFIG) + cursor = conn.cursor() + + cursor.execute(""" + SELECT c.id, t.full_text + FROM calls c + JOIN transcriptions t ON t.call_id = c.id + LEFT JOIN auto_tags at ON at.call_id = c.id AND at.tag_name LIKE 'эмоция_%' + WHERE at.id IS NULL + AND t.full_text IS NOT NULL + AND t.full_text != '' + LIMIT 10 + """) + calls = cursor.fetchall() + + if not calls: + cursor.close() + conn.close() + return 0 + + log(f"Найдено звонков без эмоций: {len(calls)}") + + for call_id, full_text in calls: + try: + response = requests.post('http://localhost:8001/analyze', data={'text': full_text}, timeout=10) + if response.status_code == 200: + result = response.json() + emotion = result.get('emotion') + confidence = result.get('confidence') + if emotion: + cursor.execute(""" + INSERT INTO auto_tags (call_id, tag_name, confidence) + VALUES (%s, %s, %s) + """, (call_id, f"эмоция_{emotion}", confidence)) + conn.commit() + log(f"✅ Звонок {call_id}: эмоция {emotion} ({confidence:.2f})") + else: + log(f"⚠️ Звонок {call_id}: ошибка HTTP {response.status_code}") + except Exception as e: + log(f"❌ Звонок {call_id}: ошибка {e}") + finally: + time.sleep(0.5) + + cursor.close() + conn.close() + return len(calls) + +if __name__ == "__main__": + log("Emotion processor started") + while True: + count = process_pending_calls() + if count == 0: + time.sleep(60) + else: + time.sleep(5) +EOF + +echo "=== 6. Создание командного сервера (command_server.py) ===" +sudo tee /opt/emotion/command_server.py << 'EOF' +#!/usr/bin/env python3 +import sys +import os +import json +import http.server +import threading + +sys.path.insert(0, '/opt/emotion') + +# Простая функция загрузки имён +def load_operator_names(): + import psycopg2 + DB_CONFIG = {"host": "192.168.254.35", "port": 5432, "database": "asr_db", "user": "asr_user", "password": "poluyan77"} + try: + conn = psycopg2.connect(**DB_CONFIG) + cursor = conn.cursor() + cursor.execute("SELECT name FROM operator_names ORDER BY name") + rows = cursor.fetchall() + cursor.close() + conn.close() + return [row[0] for row in rows] + except Exception as e: + print(f"Ошибка: {e}") + return [] + +def reload_operator_names(): + global _operator_names_cache + _operator_names_cache = load_operator_names() + return _operator_names_cache + +_operator_names_cache = load_operator_names() + +class CommandHandler(http.server.SimpleHTTPRequestHandler): + def do_POST(self): + if self.path == '/reload-names': + try: + names = reload_operator_names() + self.send_response(200) + self.send_header('Content-type', 'application/json') + self.end_headers() + self.wfile.write(json.dumps({"status": "ok", "count": len(names)}).encode()) + print(f"🔄 Кэш имён операторов обновлён, загружено {len(names)} имён") + except Exception as e: + self.send_response(500) + self.end_headers() + self.wfile.write(json.dumps({"status": "error", "error": str(e)}).encode()) + else: + self.send_response(404) + self.end_headers() + + def log_message(self, format, *args): + pass + +def start_command_server(port=8003): + server = http.server.HTTPServer(('0.0.0.0', port), CommandHandler) + print(f"🚀 Командный сервер запущен на порту {port}") + server.serve_forever() + +if __name__ == "__main__": + start_command_server() +EOF + +echo "=== 7. Создание systemd сервисов ===" +sudo tee /etc/systemd/system/emotion-api.service << 'EOF' +[Unit] +Description=Text Emotion Recognition API +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/emotion +Environment="PATH=/opt/emotion/venv/bin" +ExecStart=/opt/emotion/venv/bin/python /opt/emotion/server_text_final.py +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF + +sudo tee /etc/systemd/system/emotion-processor.service << 'EOF' +[Unit] +Description=Emotion Processor (background) +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/emotion +Environment="PATH=/opt/emotion/venv/bin" +ExecStart=/opt/emotion/venv/bin/python /opt/emotion/emotion_processor.py +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF + +sudo tee /etc/systemd/system/emotion-command.service << 'EOF' +[Unit] +Description=Emotion Command Server +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/emotion +Environment="PATH=/opt/emotion/venv/bin" +ExecStart=/opt/emotion/venv/bin/python /opt/emotion/command_server.py +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF + +echo "=== 8. Запуск сервисов ===" +sudo systemctl daemon-reload +sudo systemctl enable emotion-api emotion-processor emotion-command +sudo systemctl start emotion-api emotion-processor emotion-command + +echo "=== 9. Проверка статуса ===" +sleep 3 +sudo systemctl status emotion-api --no-pager +sudo systemctl status emotion-processor --no-pager +sudo systemctl status emotion-command --no-pager + +echo "=== Emotion ВМ готова ===" +echo "API эмоций: http://$EMOTION_HOST:$EMOTION_PORT" +echo "Командный сервер: порт $PROCESSOR_PORT" \ No newline at end of file