translator но без озвучивания слов на английском
This commit is contained in:
194
alarm.py
Normal file
194
alarm.py
Normal file
@@ -0,0 +1,194 @@
|
||||
"""
|
||||
Alarm clock module.
|
||||
Handles alarm scheduling, persistence, and playback.
|
||||
"""
|
||||
import json
|
||||
import time
|
||||
import subprocess
|
||||
import re
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from config import BASE_DIR
|
||||
from local_stt import listen_for_keywords
|
||||
|
||||
ALARM_FILE = BASE_DIR / "alarms.json"
|
||||
ALARM_SOUND = BASE_DIR / "Apex-1.mp3"
|
||||
|
||||
class AlarmClock:
|
||||
def __init__(self):
|
||||
self.alarms = []
|
||||
self.load_alarms()
|
||||
|
||||
def load_alarms(self):
|
||||
"""Load alarms from JSON file."""
|
||||
if ALARM_FILE.exists():
|
||||
try:
|
||||
with open(ALARM_FILE, "r", encoding="utf-8") as f:
|
||||
self.alarms = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка загрузки будильников: {e}")
|
||||
self.alarms = []
|
||||
|
||||
def save_alarms(self):
|
||||
"""Save alarms to JSON file."""
|
||||
try:
|
||||
with open(ALARM_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(self.alarms, f, indent=4)
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка сохранения будильников: {e}")
|
||||
|
||||
def add_alarm(self, hour: int, minute: int):
|
||||
"""Add a new alarm."""
|
||||
# Check if already exists
|
||||
for alarm in self.alarms:
|
||||
if alarm["hour"] == hour and alarm["minute"] == minute:
|
||||
alarm["active"] = True
|
||||
self.save_alarms()
|
||||
return
|
||||
|
||||
self.alarms.append({
|
||||
"hour": hour,
|
||||
"minute": minute,
|
||||
"active": True
|
||||
})
|
||||
self.save_alarms()
|
||||
print(f"⏰ Будильник установлен на {hour:02d}:{minute:02d}")
|
||||
|
||||
def cancel_all_alarms(self):
|
||||
"""Cancel all active alarms."""
|
||||
for alarm in self.alarms:
|
||||
alarm["active"] = False
|
||||
self.save_alarms()
|
||||
print("🔕 Все будильники отменены.")
|
||||
|
||||
def check_alarms(self):
|
||||
"""Check if any alarm should trigger now. Returns True if triggered."""
|
||||
now = datetime.now()
|
||||
triggered = False
|
||||
|
||||
for alarm in self.alarms:
|
||||
if alarm["active"]:
|
||||
if alarm["hour"] == now.hour and alarm["minute"] == now.minute:
|
||||
# Prevent re-triggering within the same minute?
|
||||
# We should disable it immediately or track last trigger time.
|
||||
# For simple logic: disable it (one-time alarm).
|
||||
|
||||
# But wait, checking every second?
|
||||
# If I disable it, it won't ring for the whole minute.
|
||||
# Correct.
|
||||
print(f"⏰ ВРЕМЯ БУДИЛЬНИКА: {alarm['hour']:02d}:{alarm['minute']:02d}")
|
||||
alarm["active"] = False
|
||||
triggered = True
|
||||
self.trigger_alarm()
|
||||
break # Trigger one at a time
|
||||
|
||||
if triggered:
|
||||
self.save_alarms()
|
||||
return True
|
||||
return False
|
||||
|
||||
def trigger_alarm(self):
|
||||
"""Play alarm sound and wait for stop command."""
|
||||
print("🔔 БУДИЛЬНИК ЗВОНИТ! (Скажите 'Стоп' или 'Александр стоп')")
|
||||
|
||||
# Start playing sound in loop
|
||||
# -q for quiet (no output)
|
||||
# --loop -1 for infinite loop
|
||||
cmd = ["mpg123", "-q", "--loop", "-1", str(ALARM_SOUND)]
|
||||
|
||||
try:
|
||||
process = subprocess.Popen(cmd)
|
||||
except FileNotFoundError:
|
||||
print("❌ Ошибка: mpg123 не найден. Установите его: sudo apt install mpg123")
|
||||
return
|
||||
|
||||
try:
|
||||
# Listen for stop command using local Vosk
|
||||
# Loop until stop word is heard
|
||||
stop_words = ["стоп", "хватит", "тихо", "замолчи", "отмена", "александр стоп"]
|
||||
|
||||
while True:
|
||||
# Listen in short bursts to be responsive
|
||||
text = listen_for_keywords(stop_words, timeout=3.0)
|
||||
if text:
|
||||
print(f"🛑 Будильник остановлен по команде: '{text}'")
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка во время будильника: {e}")
|
||||
finally:
|
||||
# Kill the player
|
||||
process.terminate()
|
||||
try:
|
||||
process.wait(timeout=1)
|
||||
except subprocess.TimeoutExpired:
|
||||
process.kill()
|
||||
print("🔕 Будильник выключен.")
|
||||
|
||||
def parse_command(self, text: str) -> str | None:
|
||||
"""
|
||||
Parse user text for alarm commands.
|
||||
Returns response string if command handled, None otherwise.
|
||||
"""
|
||||
text = text.lower()
|
||||
if "будильник" not in text and "разбуди" not in text:
|
||||
return None
|
||||
|
||||
if "отмени" in text:
|
||||
self.cancel_all_alarms()
|
||||
return "Хорошо, я отменил все будильники."
|
||||
|
||||
# Regex to find time: HH:MM, HH-MM, HH MM, HH часов MM минут
|
||||
# 1. "07:30", "7:30"
|
||||
match = re.search(r'\b(\d{1,2})[:.-](\d{2})\b', text)
|
||||
if match:
|
||||
h, m = int(match.group(1)), int(match.group(2))
|
||||
if 0 <= h <= 23 and 0 <= m <= 59:
|
||||
self.add_alarm(h, m)
|
||||
return f"Я установил будильник на {h} часов {m} минут."
|
||||
|
||||
# 2. "7 часов 30 минут" or "7 30"
|
||||
# Search for pattern: digits ... (digits)?
|
||||
# Complex to separate from other numbers.
|
||||
|
||||
# Simple heuristics:
|
||||
words = text.split()
|
||||
nums = [int(s) for s in text.split() if s.isdigit()]
|
||||
|
||||
# "на 7" -> 7:00
|
||||
if "на" in words or "в" in words:
|
||||
# Try to find number after preposition
|
||||
pass
|
||||
|
||||
# Let's rely on explicit digit search if regex failed
|
||||
# Patterns: "на 8", "на 8 30", "на 8 часов 30 минут", "на 8 часов"
|
||||
|
||||
# Regex to capture hour and optional minute
|
||||
# Matches: "на <H> [часов] [M] [минут]"
|
||||
match_time = re.search(r'на\s+(\d{1,2})(?:\s*(?:часов|часа|час))?(?:\s+(\d{1,2})(?:\s*(?:минут|минуты|минута))?)?', text)
|
||||
|
||||
if match_time:
|
||||
h = int(match_time.group(1))
|
||||
m = int(match_time.group(2)) if match_time.group(2) else 0
|
||||
|
||||
# Handle AM/PM if specified
|
||||
if "вечера" in text and h < 12:
|
||||
h += 12
|
||||
elif "утра" in text and h == 12:
|
||||
h = 0
|
||||
|
||||
if 0 <= h <= 23 and 0 <= m <= 59:
|
||||
self.add_alarm(h, m)
|
||||
return f"Хорошо, разбужу вас в {h}:{m:02d}."
|
||||
|
||||
return "Я не понял время для будильника. Пожалуйста, скажите точное время, например 'семь тридцать'."
|
||||
|
||||
# Global instance
|
||||
_alarm_clock = None
|
||||
|
||||
def get_alarm_clock():
|
||||
global _alarm_clock
|
||||
if _alarm_clock is None:
|
||||
_alarm_clock = AlarmClock()
|
||||
return _alarm_clock
|
||||
Reference in New Issue
Block a user