Улучшенная работа погоды + ускорение работы + фикс неработоспособности после пары часов

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-02-02 21:06:14 +03:00
parent 2d40bc0f9b
commit 845ef7c531
7 changed files with 661 additions and 72 deletions

View File

@@ -20,6 +20,7 @@ import re
import signal
import sys
import threading
import time
from collections import deque
# Для воспроизведения звуков (mp3)
@@ -61,8 +62,14 @@ def signal_handler(sig, frame):
Позволяет корректно завершить работу программы, освободив ресурсы (микрофон, модели).
"""
print("\n\n👋 Завершение работы...")
cleanup_wakeword() # Остановка Porcupine
cleanup_stt() # Остановка Deepgram
try:
cleanup_wakeword() # Остановка Porcupine
except Exception as e:
print(f"Ошибка при остановке wakeword: {e}")
try:
cleanup_stt() # Остановка Deepgram
except Exception as e:
print(f"Ошибка при остановке STT: {e}")
sys.exit(0)
@@ -180,8 +187,20 @@ def main():
# (True = режим диалога, слушаем сразу. False = ждем "Alexandr")
skip_wakeword = False
# Переменная для отслеживания последней проверки здоровья STT
last_stt_check = time.time()
# БЕСКОНЕЧНЫЙ ЦИКЛ РАБОТЫ
while True:
# Периодическая проверка здоровья STT каждые 10 минут
if time.time() - last_stt_check > 600: # 10 минут = 600 секунд
try:
recognizer = get_recognizer()
if hasattr(recognizer, 'check_connection_health'):
recognizer.check_connection_health()
last_stt_check = time.time()
except Exception as e:
print(f"Ошибка при проверке здоровья STT: {e}")
try:
# Гарантируем, что микрофон детектора wake word освобожден
stop_wakeword_monitoring()
@@ -201,8 +220,8 @@ def main():
# --- Шаг 1: Активация ---
if not skip_wakeword:
# Ожидание фразы "Alexandr". Используем таймаут 1 сек, чтобы часто проверять будильники.
detected = wait_for_wakeword(timeout=1.0)
# Ожидание фразы "Alexandr". Используем таймаут 0.5 сек, чтобы чаще проверять будильники.
detected = wait_for_wakeword(timeout=0.5)
# Если время вышло, а фразы не было — начинаем цикл заново (проверяем будильники)
if not detected:
@@ -212,13 +231,34 @@ def main():
if ding_sound:
ding_sound.play()
# Фраза услышана! Слушаем команду пользователя (7 секунд тишины макс)
user_text = listen(timeout_seconds=7.0)
# Фраза услышана! Слушаем команду пользователя (5 секунд тишины макс)
try:
user_text = listen(timeout_seconds=5.0)
except Exception as e:
print(f"Ошибка при прослушивании: {e}")
print("Переинициализация STT...")
try:
cleanup_stt()
get_recognizer().initialize()
except Exception as init_error:
print(f"Ошибка переинициализации STT: {init_error}")
continue # Продолжаем цикл
else:
# Режим диалога (Follow-up): ждем продолжения речи без "Alexandr"
print("👂 Слушаю продолжение диалога (5 сек)...")
# Ждем начала речи 5 сек. Если начали говорить, слушаем до 10 сек.
user_text = listen(timeout_seconds=10.0, detection_timeout=5.0)
print("👂 Слушаю продолжение диалога (3 сек)...")
# Ждем начала речи 3 сек. Если начали говорить, слушаем до 7 сек.
try:
user_text = listen(timeout_seconds=7.0, detection_timeout=3.0)
except Exception as e:
print(f"Ошибка при прослушивании: {e}")
print("Переинициализация STT...")
try:
cleanup_stt()
get_recognizer().initialize()
except Exception as init_error:
print(f"Ошибка переинициализации STT: {init_error}")
skip_wakeword = False
continue
if not user_text:
# Пользователь промолчал — выходим из режима диалога, засыпаем.
@@ -326,10 +366,42 @@ def main():
"нужен ли зонт",
"брать ли зонт",
"прогноз погоды",
"че там на улице",
"что там на улице",
"как на улице",
"как на улице-то",
]
if any(trigger in user_text.lower() for trigger in weather_triggers):
weather_report = get_weather_report()
# Проверяем, содержит ли запрос информацию о конкретном городе
requested_city = None
user_text_lower = user_text.lower()
# Проверяем наличие упоминания города в запросе (например, "погода в Нью-Йорке", "какая погода в Москве")
import re
city_patterns = [
r"в\s+городе\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)", # "в городе Волгоград"
r"в\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)", # "в Нью-Йорке" - улучшенный паттерн для составных названий
r"погода\s+в\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)", # "погода в Москве" - улучшенный паттерн
r"погода\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)\s+(?:какая|сейчас|там)", # "погода Москва какая"
r"(?:какая|как)\s+погода\s+в\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)", # "какая погода в Москве"
]
for pattern in city_patterns:
match = re.search(pattern, user_text_lower, re.IGNORECASE)
if match:
potential_city = match.group(1).strip()
# Проверяем, что это не местоимение или другое слово, а реально название города
invalid_words = ["этом", "том", "той", "тут", "здесь", "там", "всё", "все", "всей", "всего", "всем", "всеми", "городе", "город", "село", "деревня", "посёлок", "аул", "станция", "область", "район", "край", "республика"]
if potential_city and len(potential_city) > 1 and not any(word in potential_city for word in invalid_words):
requested_city = potential_city.title() # Приводим к формату "Нью-Йорк", "Москва"
break
# Проверяем, содержит ли запрос одну из погодных команд
has_weather_trigger = any(trigger in user_text_lower for trigger in weather_triggers)
if has_weather_trigger:
from .features.weather import get_weather_report
weather_report = get_weather_report(requested_city)
clean_report = clean_response(weather_report, language="ru")
speak(clean_report)
last_response = clean_report
@@ -362,9 +434,21 @@ def main():
)
speak(prompt)
# Слушаем саму фразу на нужном языке
text_to_translate = listen(
timeout_seconds=7.0, detection_timeout=5.0, lang=source_lang
)
try:
text_to_translate = listen(
timeout_seconds=7.0, detection_timeout=5.0, lang=source_lang
)
except Exception as e:
print(f"Ошибка при прослушивании для перевода: {e}")
print("Переинициализация STT...")
try:
cleanup_stt()
get_recognizer().initialize()
except Exception as init_error:
print(f"Ошибка переинициализации STT: {init_error}")
speak("Произошла ошибка при распознавании речи.")
skip_wakeword = False
continue
if not text_to_translate:
speak("Я не расслышал текст для перевода.")