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:
135
rag/functions/check_spelling.py
Normal file
135
rag/functions/check_spelling.py
Normal 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
|
||||
Reference in New Issue
Block a user