Улучшенный будильник, таймер, перевод

This commit is contained in:
2026-02-01 19:59:18 +03:00
parent 49dbaad122
commit d0b12009b3
15 changed files with 1013 additions and 105 deletions

View File

@@ -4,6 +4,7 @@
# Обрабатывает запросы пользователя и переводы.
import requests
import re
from .config import PERPLEXITY_API_KEY, PERPLEXITY_MODEL, PERPLEXITY_API_URL
@@ -21,7 +22,9 @@ SYSTEM_PROMPT = """Ты — Александр, умный голосовой а
# Требует возвращать ТОЛЬКО перевод, без лишних слов ("Конечно, вот перевод...").
TRANSLATION_SYSTEM_PROMPT = """You are a translation engine.
Translate from {source} to {target}.
Return only the translated text, without quotes, comments, or explanations.
Return 2-3 short translation variants only.
No explanations, no quotes, no comments.
Separate variants with " / " (space slash space).
Keep the translation максимально кратким и естественным, без лишних слов."""
@@ -178,8 +181,22 @@ def translate_text(text: str, source_lang: str, target_lang: str) -> str:
response = _send_request(
messages,
max_tokens=400,
max_tokens=160,
temperature=0.2, # Низкая температура для точности перевода
error_text="Произошла ошибка при переводе. Попробуйте ещё раз.",
)
return response.strip()
cleaned = response.strip()
if not cleaned:
return cleaned
# Normalize to 2-3 variants separated by " / "
parts = []
for chunk in re.split(r"(?:\s*/\s*|\n|;|\|)", cleaned):
item = chunk.strip(" \t-•")
if item:
parts.append(item)
if not parts:
return cleaned
parts = parts[:3]
return " / ".join(parts)

View File

@@ -91,6 +91,9 @@ MONTHS_GENITIVE = [
"декабря",
]
# Леммы единиц времени (для корректного падежа числительных)
TIME_UNIT_LEMMAS = {"час", "минута", "секунда"}
def get_case_from_preposition(prep_token):
"""Определяет падеж по предлогу."""
@@ -127,7 +130,6 @@ def numbers_to_words(text: str) -> str:
# 1. Обработка годов: "в 1999 году", "2024 год"
def replace_year_match(match):
full_str = match.group(0)
prep = match.group(1) # Предлог (в, с, к...)
year_str = match.group(2) # Само число
year_word = match.group(3) # Слово "год", "году" и т.д.
@@ -207,9 +209,10 @@ def numbers_to_words(text: str) -> str:
case = "nominative"
gender = "m"
prep_clean = prep.strip().lower() if prep else None
if prep:
morph_case = get_case_from_preposition(prep.strip())
if prep_clean:
morph_case = get_case_from_preposition(prep_clean)
if morph_case:
case = PYMORPHY_TO_NUM2WORDS.get(morph_case, "nominative")
@@ -221,6 +224,16 @@ def numbers_to_words(text: str) -> str:
morph_gender = parsed.tag.gender
gender = PYMORPHY_TO_GENDER.get(morph_gender, "m")
# Спец-случай: "на 1 час" -> "на один час" (не "одного")
# Для неодушевленных муж./ср. рода в винительном падеже
# числительные должны совпадать с именительным.
if (
prep_clean == "на"
and parsed.normal_form in TIME_UNIT_LEMMAS
and parsed.tag.gender in ("masc", "neut")
):
case = "nominative"
words = convert_number(
num_str, context_type="cardinal", case=case, gender=gender
)

66
app/core/commands.py Normal file
View File

@@ -0,0 +1,66 @@
"""
Command parsing helpers.
"""
import re
_STOP_WORDS_STRICT = {
"стоп",
"хватит",
"перестань",
"замолчи",
"прекрати",
"тихо",
"stop",
}
_STOP_PATTERNS_LENIENT = [
r"\bстоп\w*\b",
r"\bstop\b",
r"\bхватит\b",
r"\bперестан\w*\b",
r"\bпрекрат\w*\b",
r"\амолч\w*\b",
r"\bтише\b",
r"\bтихо\b",
r"\bвыключ\w*\b",
r"\bотключ\w*\b",
r"\bостанов\w*\b",
r"\bотмен\w*\b",
r"\bпауза\b",
r"\остаточно\b",
]
_STOP_PATTERNS_LENIENT_COMPILED = [re.compile(p) for p in _STOP_PATTERNS_LENIENT]
def _normalize_text(text: str) -> str:
text = text.lower().replace("ё", "е")
text = re.sub(r"[^\w\s]+", " ", text, flags=re.UNICODE)
text = re.sub(r"\s+", " ", text, flags=re.UNICODE).strip()
return text
def is_stop_command(text: str, mode: str = "strict") -> bool:
"""
Detect stop commands in text.
mode:
- "strict": only exact stop words.
- "lenient": broader patterns for noisy recognition.
"""
if not text:
return False
normalized = _normalize_text(text)
if not normalized:
return False
if mode == "strict":
words = normalized.split()
return any(word in _STOP_WORDS_STRICT for word in words)
for pattern in _STOP_PATTERNS_LENIENT_COMPILED:
if pattern.search(normalized):
return True
return False

View File

@@ -7,6 +7,7 @@ Loads environment variables from .env file.
# Он загружает настройки из файла .env (переменные окружения) и определяет константы.
import os
import time
from pathlib import Path
from dotenv import load_dotenv
@@ -40,7 +41,6 @@ CHANNELS = 1
# --- Настройка времени ---
# Устанавливаем часовой пояс на Москву, чтобы будильник работал корректно
import time
os.environ["TZ"] = "Europe/Moscow"
time.tzset()