Update 86 files

- /rag/commands/expert.py
- /core/services/__init__.py
- /core/services/embedding_service.py
- /core/services/file_service.py
- /core/services/giga_client.py
- /core/services/kb_service.py
- /core/services/postgres_service.py
- /core/services/qdrant_service.py
- /core/services/reranker_service.py
- /core/functions/__init__.py
- /core/functions/check_consistency.py
- /core/functions/check_spelling.py
- /core/functions/critique_answer.py
- /core/functions/expand_query.py
- /core/functions/extract_metrics.py
- /core/functions/file_processor.py
- /core/functions/generate_document.py
- /core/functions/intent_classify.py
- /core/functions/rerank_context.py
- /core/functions/summarize_document.py
- /core/utils/__init__.py
- /core/utils/arg_parser.py
- /core/utils/config_loader.py
- /core/utils/layout_converter.py
- /core/utils/logger.py
- /core/utils/text_utils.py
- /core/utils/web_utils.py
- /bots/commands/__init__.py
- /bots/commands/base.py
- /bots/commands/create.py
- /core/commands/global_remove.py
- /core/commands/help.py
- /core/commands/info.py
- /core/commands/kb.py
- /core/commands/learn.py
- /core/commands/other.py
- /core/commands/registry.py
- /core/commands/stats.py
- /core/commands/template.py
- /core/handlers/__init__.py
- /core/handlers/message_handler.py
- /core/workers/__init__.py
- /core/workers/indexing_worker.py
- /core/xmpp/__init__.py
- /core/xmpp/client.py
- /bots/commands/global_remove.py
- /bots/commands/help.py
- /bots/commands/info.py
- /bots/commands/kb.py
- /bots/commands/registry.py
- /bots/commands/other.py
- /bots/commands/template.py
- /bots/commands/learn.py
- /bots/commands/stats.py
- /bots/handlers/message_handler.py
- /bots/handlers/__init__.py
- /bots/workers/__init__.py
- /bots/workers/indexing_worker.py
- /bots/xmpp/__init__.py
- /bots/xmpp/client.py
- /rag/services/qdrant_service.py
- /rag/services/giga_client.py
- /rag/services/embedding_service.py
- /rag/services/reranker_service.py
- /rag/services/__init__.py
- /rag/services/file_service.py
- /rag/services/postgres_service.py
- /rag/services/kb_service.py
- /rag/functions/check_spelling.py
- /rag/functions/__init__.py
- /rag/functions/extract_metrics.py
- /rag/functions/generate_document.py
- /rag/functions/expand_query.py
- /rag/functions/critique_answer.py
- /rag/functions/file_processor.py
- /rag/functions/check_consistency.py
- /rag/functions/summarize_document.py
- /rag/functions/rerank_context.py
- /rag/functions/intent_classify.py
- /rag/utils/__init__.py
- /rag/utils/layout_converter.py
- /rag/utils/text_utils.py
- /rag/utils/arg_parser.py
- /rag/utils/config_loader.py
- /rag/utils/logger.py
- /rag/utils/web_utils.py
This commit is contained in:
Markov Andrey
2026-06-30 10:33:28 +00:00
parent ea0d42de9c
commit 63900feece
45 changed files with 0 additions and 265 deletions

View File

@@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
"""
Модуль проверки орфографии и пунктуации в тексте документа.
Разбивает документ на чанки, обрабатывает каждый чанк через GigaChat,
собирает словарь замен (старое -> новое) и список изменений.
АДАПТАЦИЯ: теперь функция принимает промпт и конфиг как аргументы.
"""
import asyncio
import logging
import re
from core.utils.text_utils import split_into_chunks
from core.services.giga_client import GigaClient
logger = logging.getLogger(__name__)
async def check_spelling(
giga: GigaClient,
original_text: str,
prompt_text: str,
config,
) -> tuple[dict, list[str]]:
"""
Проверяет орфографию документа, возвращает замены и список изменений.
Аргументы:
giga (GigaClient): клиент GigaChat
original_text (str): исходный текст документа
prompt_text (str): содержимое промпта проверки орфографии
config (BotConfig): объект конфигурации
Возвращает:
tuple: (словарь_замен, список_изменений_в_виде_строк)
В случае, если парсинг изменений не удался, возвращается:
({"_raw": сырой_ответ_LLM}, ["Сообщение для пользователя"])
"""
if not prompt_text:
logger.error("Промпт проверки орфографии не загружен")
return {}, ["❌ Промпт проверки орфографии не загружен."]
# Параметры чанкинга из конфига
chunk_size_tokens = config.chunk_size_tokens
overlap_tokens = config.overlap_tokens
approx_chunk_chars = config.chunking_approx_chunk_chars
approx_overlap_chars = config.chunking_approx_overlap_chars
# Разбиваем текст на чанки
chunks = split_into_chunks(
original_text,
chunk_size_tokens=chunk_size_tokens,
overlap_tokens=overlap_tokens,
approx_chunk_chars=approx_chunk_chars,
approx_overlap_chars=approx_overlap_chars,
strategy="recursive_split_by_sentences"
)
logger.info(f"Разбито на {len(chunks)} чанков для проверки орфографии")
all_replacements = {}
all_changes = []
temperature = getattr(config, 'spellcheck_temperature', 0.1)
# Обрабатываем каждый чанк
for idx, chunk in enumerate(chunks):
logger.info(f"Обработка чанка {idx+1}/{len(chunks)}")
full_prompt = f"{prompt_text}\n\nТЕКСТ ДЛЯ ПРОВЕРКИ (часть {idx+1} из {len(chunks)}):\n{chunk}"
try:
response = await giga.chat(
history=[],
query=full_prompt,
system_prompt=None,
file_id=None,
temperature=temperature
)
corrected_match = re.search(r'\[CORRECTED\](.*?)\[/CORRECTED\]', response, re.DOTALL)
changes_match = re.search(r'\[CHANGES\](.*?)\[/CHANGES\]', response, re.DOTALL)
if changes_match:
changes_text = changes_match.group(1).strip()
for line in changes_text.split('\n'):
line = line.strip()
if not line or line.startswith('#'):
continue
patterns = [
r'было\s*["«](.+?)["»]\s*[→-]>\s*стало\s*["«](.+?)["»]',
r'было\s*:\s*["«](.+?)["»]\s*[→-]>\s*стало\s*:\s*["«](.+?)["»]',
r'было\s*["«](.+?)["»]\s*[→-]>\s*(.+)',
r'было\s*:\s*(.+?)\s*[→-]>\s*стало\s*:\s*(.+)',
r'было\s*(.+?)\s*[→-]>\s*стало\s*(.+)'
]
match = None
for pattern in patterns:
match = re.search(pattern, line, re.IGNORECASE)
if match:
old, new = match.group(1).strip(), match.group(2).strip()
break
if match:
all_replacements[old] = new
all_changes.append(f'было "{old}" → стало "{new}"')
else:
all_changes.append(line)
# Если список изменений не распарсился, но есть исправленный текст
if corrected_match and (not changes_match or not changes_match.group(1).strip()):
logger.warning(f"Не удалось распарсить список изменений для чанка {idx+1}, возвращаем сырой ответ")
return {"_raw": response}, [
f"⚠️ Не удалось распарсить список изменений (чанк {idx+1}). Вот сырой ответ LLM:\n{response}"
]
except Exception as e:
logger.error(f"Ошибка при проверке чанка {idx+1}: {e}", exc_info=True)
all_changes.append(f"⚠️ Ошибка в части {idx+1}: {e}")
await asyncio.sleep(0.5)
# Удаляем дубликаты
unique_replacements = {}
unique_changes = []
seen = set()
for old, new in all_replacements.items():
key = f"{old}{new}"
if key not in seen:
seen.add(key)
unique_replacements[old] = new
for change in all_changes:
if change not in seen:
seen.add(change)
unique_changes.append(change)
return unique_replacements, unique_changes