ускоренная работа

This commit is contained in:
2026-01-09 19:59:31 +03:00
parent ce28fede74
commit fd373d83f3
10 changed files with 322 additions and 46 deletions

View File

@@ -44,6 +44,14 @@ PREPOSITION_CASES = {
"перед": "ablt",
"за": "ablt",
"между": "ablt",
"около": "gent",
"против": "gent",
"вместо": "gent",
"кроме": "gent",
"из-за": "gent",
"сквозь": "accs",
"через": "accs",
"про": "accs",
}
# Соответствие падежей pymorphy и библиотеки num2words
@@ -60,6 +68,13 @@ PYMORPHY_TO_NUM2WORDS = {
"loc2": "prepositional",
}
# Соответствие родов pymorphy и num2words
PYMORPHY_TO_GENDER = {
"masc": "m",
"femn": "f",
"neut": "n",
}
# Названия месяцев в родительном падеже (для поиска дат в тексте)
MONTHS_GENITIVE = [
"января",
@@ -123,6 +138,12 @@ def numbers_to_words(text: str) -> str:
nw_case = PYMORPHY_TO_NUM2WORDS.get(case_tag, "nominative")
# FIX: Pymorphy часто определяет "год" как accs (винительный), что для num2words
# превращается в родительный (для одушевленных?), давая "2024 года".
# Если предлога нет, принудительно ставим именительный.
if not prep and year_word.lower().startswith("год"):
nw_case = "nominative"
# Конвертируем число в порядковое числительное (тысяча девятьсот девяносто девятом)
words = convert_number(
year_str, context_type="ordinal", case=nw_case, gender="m"
@@ -171,9 +192,9 @@ def numbers_to_words(text: str) -> str:
prefix = f"{prep} " if prep else ""
return f"{prefix}{words} {month_word}"
# Конкатенация regex для месяцев (ВАЖНО: month_regex должен быть вставлен в строку)
# Конкатенация regex для месяцев (FIX: используем f-строку)
text = re.sub(
r"(?i)\b((?:с|к|до|от|на|по)\s+)?(\d{1,2})\s+({month_regex})\b",
rf"(?i)\b((?:с|к|до|от|на|по)\s+)?(\d{{1,2}})\s+({month_regex})\b",
replace_date_match,
text,
)
@@ -182,20 +203,41 @@ def numbers_to_words(text: str) -> str:
def replace_cardinal_match(match):
prep = match.group(1)
num_str = match.group(2)
next_word = match.group(3)
case = "nominative"
gender = "m"
if prep:
morph_case = get_case_from_preposition(prep.strip())
if morph_case:
case = PYMORPHY_TO_NUM2WORDS.get(morph_case, "nominative")
words = convert_number(num_str, context_type="cardinal", case=case)
# Если есть следующее слово, проверяем его род (для "2 минуты" -> "две")
if next_word:
word_clean = next_word.strip()
parsed = morph.parse(word_clean)[0]
if "NOUN" in parsed.tag:
morph_gender = parsed.tag.gender
gender = PYMORPHY_TO_GENDER.get(morph_gender, "m")
words = convert_number(
num_str, context_type="cardinal", case=case, gender=gender
)
# Если конвертация вернула пустую строку (сбой?), возвращаем цифры
if not words:
words = num_str
prefix = f"{prep} " if prep else ""
# suffix removed (lookahead)
return f"{prefix}{words}"
# Регулярка теперь захватывает (опционально) следующее слово для определения рода
preps_list = "|".join(map(re.escape, PREPOSITION_CASES.keys()))
text = re.sub(
r"(?i)\b((?:в|на|о|об|обо|при|у|от|до|из|с|со|без|для|вокруг|после|к|ко|по|над|под|перед|за|между)\s+)?(\d+(?:[.,]\d+)?)\b",
rf"(?i)\b((?:{preps_list})\s+)?(\d+(?:[.,]\d+)?)(?=(\s+[а-яА-ЯёЁ]+))?\b",
replace_cardinal_match,
text,
)
@@ -234,13 +276,13 @@ def clean_response(text: str, language: str = "ru") -> str:
# Удаление заголовков Markdown (# Header)
text = re.sub(r"^#{1,6}\s*", "", text, flags=re.MULTILINE)
# Удаление картинок ![alt](url) -> удаляем полностью
text = re.sub(r"!\x5B([^\x5D]*)\x5D\([^)]+\)", "", text)
# Удаление ссылок [text](url) -> оставляем только text
# \x5B = [, \x5D = ]
text = re.sub(r"\x5B([^\x5D]+)\x5D\([^)]+\)", r"\1", text)
# Удаление картинок ![alt](url) -> удаляем полностью
text = re.sub(r"!\x5B([^\x5D]*)\x5D\([^)]+\)", "", text)
# Удаление inline кода `code`
text = re.sub(r"`([^`]+)`", r"\1", text)