Optimize hot paths and reuse HTTP sessions
This commit is contained in:
@@ -7,6 +7,7 @@ import requests
|
||||
import re
|
||||
from .config import PERPLEXITY_API_KEY, PERPLEXITY_MODEL, PERPLEXITY_API_URL
|
||||
|
||||
_HTTP = requests.Session()
|
||||
|
||||
# Системный промпт (инструкция) для AI.
|
||||
# Задает личность ассистента: имя "Александр", стиль общения, краткость.
|
||||
@@ -53,7 +54,7 @@ def _send_request(messages, max_tokens, temperature, error_text):
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
response = _HTTP.post(
|
||||
PERPLEXITY_API_URL, headers=headers, json=payload, timeout=15 # Уменьшаем таймаут
|
||||
)
|
||||
response.raise_for_status() # Проверка на ошибки HTTP (4xx, 5xx)
|
||||
@@ -134,16 +135,16 @@ def ask_ai_stream(messages_history: list):
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
response = _HTTP.post(
|
||||
PERPLEXITY_API_URL, headers=headers, json=payload, timeout=15, stream=True # Уменьшаем таймаут
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
import json
|
||||
|
||||
for line in response.iter_lines():
|
||||
for line in response.iter_lines(decode_unicode=True):
|
||||
if line:
|
||||
line_text = line.decode("utf-8")
|
||||
line_text = line
|
||||
if line_text.startswith("data: "):
|
||||
data_str = line_text[6:] # Skip "data: "
|
||||
if data_str == "[DONE]":
|
||||
|
||||
@@ -7,6 +7,7 @@ import requests
|
||||
from datetime import datetime
|
||||
from ..core.config import WEATHER_LAT, WEATHER_LON, WEATHER_CITY
|
||||
|
||||
_HTTP = requests.Session()
|
||||
def get_wmo_description(code: int) -> str:
|
||||
"""Decodes WMO weather code to Russian description."""
|
||||
codes = {
|
||||
@@ -348,7 +349,7 @@ def get_coordinates_by_city(city_name: str) -> tuple:
|
||||
"format": "json"
|
||||
}
|
||||
|
||||
response = requests.get(geocode_url, params=params, timeout=10)
|
||||
response = _HTTP.get(geocode_url, params=params, timeout=10)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
@@ -403,7 +404,7 @@ def get_weather_report(requested_city: str = None) -> str:
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(url, params=params, timeout=10)
|
||||
response = _HTTP.get(url, params=params, timeout=10)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
|
||||
205
app/main.py
205
app/main.py
@@ -58,6 +58,120 @@ from .features.weather import get_weather_report
|
||||
from .features.music import get_music_controller
|
||||
from .features.cities_game import get_cities_game
|
||||
|
||||
_TRANSLATION_COMMANDS = [
|
||||
("переведи на английский с русского", "ru", "en"),
|
||||
("переведи на русский с английского", "en", "ru"),
|
||||
("переведи на английский язык с русского", "ru", "en"),
|
||||
("переведи на русский язык с английского", "en", "ru"),
|
||||
("переведи с русского на английский", "ru", "en"),
|
||||
("переведи с русского в английский", "ru", "en"),
|
||||
("переведи с английского на русский", "en", "ru"),
|
||||
("переведи с английского в русский", "en", "ru"),
|
||||
("переведи с русского языка", "ru", "en"),
|
||||
("переведи с английского языка", "en", "ru"),
|
||||
("переведи на английский язык", "ru", "en"),
|
||||
("переведи на русский язык", "en", "ru"),
|
||||
("переведи на английский", "ru", "en"),
|
||||
("переведи на русский", "en", "ru"),
|
||||
("переведи с английского", "en", "ru"),
|
||||
("переведи с русского", "ru", "en"),
|
||||
("как по-английски", "ru", "en"),
|
||||
("как по английски", "ru", "en"),
|
||||
("как по-русски", "en", "ru"),
|
||||
("как по русски", "en", "ru"),
|
||||
("translate to english from russian", "ru", "en"),
|
||||
("translate to russian from english", "en", "ru"),
|
||||
("translate from russian to english", "ru", "en"),
|
||||
("translate from english to russian", "en", "ru"),
|
||||
("translate into english", "ru", "en"),
|
||||
("translate into russian", "en", "ru"),
|
||||
("translate to english", "ru", "en"),
|
||||
("translate to russian", "en", "ru"),
|
||||
("translate from english", "en", "ru"),
|
||||
("translate from russian", "ru", "en"),
|
||||
]
|
||||
_TRANSLATION_COMMANDS_SORTED = sorted(
|
||||
_TRANSLATION_COMMANDS, key=lambda item: len(item[0]), reverse=True
|
||||
)
|
||||
|
||||
_REPEAT_PHRASES = {
|
||||
"еще раз",
|
||||
"повтори",
|
||||
"скажи еще раз",
|
||||
"что ты сказал",
|
||||
"повтори пожалуйста",
|
||||
"александр еще раз",
|
||||
"еще раз александр",
|
||||
"александр повтори",
|
||||
"повтори александр",
|
||||
}
|
||||
|
||||
_WEATHER_TRIGGERS = (
|
||||
"погода",
|
||||
"погоду",
|
||||
"что на улице",
|
||||
"какая температура",
|
||||
"сколько градусов",
|
||||
"холодно ли",
|
||||
"жарко ли",
|
||||
"нужен ли зонт",
|
||||
"брать ли зонт",
|
||||
"прогноз погоды",
|
||||
"че там на улице",
|
||||
"что там на улице",
|
||||
"как на улице",
|
||||
"как на улице-то",
|
||||
)
|
||||
|
||||
_CITY_INVALID_WORDS = {
|
||||
"этом",
|
||||
"том",
|
||||
"той",
|
||||
"тут",
|
||||
"здесь",
|
||||
"там",
|
||||
"всё",
|
||||
"все",
|
||||
"всей",
|
||||
"всего",
|
||||
"всем",
|
||||
"всеми",
|
||||
"городе",
|
||||
"город",
|
||||
"село",
|
||||
"деревня",
|
||||
"посёлок",
|
||||
"аул",
|
||||
"станция",
|
||||
"область",
|
||||
"район",
|
||||
"край",
|
||||
"республика",
|
||||
}
|
||||
|
||||
_CITY_PATTERNS = [
|
||||
re.compile(
|
||||
r"в\s+городе\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)",
|
||||
re.IGNORECASE,
|
||||
),
|
||||
re.compile(
|
||||
r"в\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)",
|
||||
re.IGNORECASE,
|
||||
),
|
||||
re.compile(
|
||||
r"погода\s+в\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)",
|
||||
re.IGNORECASE,
|
||||
),
|
||||
re.compile(
|
||||
r"погода\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)\s+(?:какая|сейчас|там)",
|
||||
re.IGNORECASE,
|
||||
),
|
||||
re.compile(
|
||||
r"(?:какая|как)\s+погода\s+в\s+([а-яёa-z]+[-\s]*[а-яёa-z]*(?:[-\s]+[а-яёa-z]+)*)",
|
||||
re.IGNORECASE,
|
||||
),
|
||||
]
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
"""
|
||||
Обработчик сигнала Ctrl+C.
|
||||
@@ -87,42 +201,7 @@ def parse_translation_request(text: str):
|
||||
# Список префиксов команд перевода и соответствующих направлений языков.
|
||||
# Важно: более длинные префиксы должны проверяться первыми (например,
|
||||
# "переведи с русского на английский" не должен схватиться как "переведи с русского").
|
||||
commands = [
|
||||
("переведи на английский с русского", "ru", "en"),
|
||||
("переведи на русский с английского", "en", "ru"),
|
||||
("переведи на английский язык с русского", "ru", "en"),
|
||||
("переведи на русский язык с английского", "en", "ru"),
|
||||
("переведи с русского на английский", "ru", "en"),
|
||||
("переведи с русского в английский", "ru", "en"),
|
||||
("переведи с английского на русский", "en", "ru"),
|
||||
("переведи с английского в русский", "en", "ru"),
|
||||
("переведи с русского языка", "ru", "en"),
|
||||
("переведи с английского языка", "en", "ru"),
|
||||
("переведи на английский язык", "ru", "en"),
|
||||
("переведи на русский язык", "en", "ru"),
|
||||
("переведи на английский", "ru", "en"),
|
||||
("переведи на русский", "en", "ru"),
|
||||
("переведи с английского", "en", "ru"),
|
||||
("переведи с русского", "ru", "en"),
|
||||
("как по-английски", "ru", "en"),
|
||||
("как по английски", "ru", "en"),
|
||||
("как по-русски", "en", "ru"),
|
||||
("как по русски", "en", "ru"),
|
||||
("translate to english from russian", "ru", "en"),
|
||||
("translate to russian from english", "en", "ru"),
|
||||
("translate from russian to english", "ru", "en"),
|
||||
("translate from english to russian", "en", "ru"),
|
||||
("translate into english", "ru", "en"),
|
||||
("translate into russian", "en", "ru"),
|
||||
("translate to english", "ru", "en"),
|
||||
("translate to russian", "en", "ru"),
|
||||
("translate from english", "en", "ru"),
|
||||
("translate from russian", "ru", "en"),
|
||||
]
|
||||
|
||||
for prefix, source_lang, target_lang in sorted(
|
||||
commands, key=lambda item: len(item[0]), reverse=True
|
||||
):
|
||||
for prefix, source_lang, target_lang in _TRANSLATION_COMMANDS_SORTED:
|
||||
if text_lower.startswith(prefix):
|
||||
# Отрезаем команду (префикс), оставляем только текст для перевода
|
||||
rest = text[len(prefix) :].strip()
|
||||
@@ -284,19 +363,8 @@ def main():
|
||||
|
||||
# Проверка на команду "Повтори" / "Еще раз"
|
||||
user_text_lower = user_text.lower().strip()
|
||||
repeat_phrases = [
|
||||
"еще раз",
|
||||
"повтори",
|
||||
"скажи еще раз",
|
||||
"что ты сказал",
|
||||
"повтори пожалуйста",
|
||||
"александр еще раз",
|
||||
"еще раз александр",
|
||||
"александр повтори",
|
||||
"повтори александр",
|
||||
]
|
||||
# Проверяем точное совпадение или если фраза начинается с "повтори" (но не "повтори за мной")
|
||||
if user_text_lower in repeat_phrases or (
|
||||
if user_text_lower in _REPEAT_PHRASES or (
|
||||
user_text_lower.startswith("повтори")
|
||||
and "за мной" not in user_text_lower
|
||||
):
|
||||
@@ -358,49 +426,28 @@ def main():
|
||||
continue
|
||||
|
||||
# Проверка команды "Погода"
|
||||
weather_triggers = [
|
||||
"погода",
|
||||
"погоду",
|
||||
"что на улице",
|
||||
"какая температура",
|
||||
"сколько градусов",
|
||||
"холодно ли",
|
||||
"жарко ли",
|
||||
"нужен ли зонт",
|
||||
"брать ли зонт",
|
||||
"прогноз погоды",
|
||||
"че там на улице",
|
||||
"что там на улице",
|
||||
"как на улице",
|
||||
"как на улице-то",
|
||||
]
|
||||
|
||||
# Проверяем, содержит ли запрос информацию о конкретном городе
|
||||
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)
|
||||
for pattern in _CITY_PATTERNS:
|
||||
match = pattern.search(user_text_lower)
|
||||
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):
|
||||
if (
|
||||
potential_city
|
||||
and len(potential_city) > 1
|
||||
and not any(word in potential_city for word in _CITY_INVALID_WORDS)
|
||||
):
|
||||
requested_city = potential_city.title() # Приводим к формату "Нью-Йорк", "Москва"
|
||||
break
|
||||
|
||||
# Проверяем, содержит ли запрос одну из погодных команд
|
||||
has_weather_trigger = any(trigger in user_text_lower for trigger in weather_triggers)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user