fix: исправлены критические ошибки в коде
- GigaChatProvider: добавлено наследование от BaseAIProvider и методы - Компактификация: исправлен парсинг JSON-ответа Qwen - Compactor: добавлена проверка на None - Векторный поиск: исправлена структура результатов ChromaDB - extract_facts_with_ai: добавлена проверка авторизации Qwen - SSH сессия: исправлена логика буфера вывода - Cron job: добавлено обновление next_run после выполнения
This commit is contained in:
parent
107685771c
commit
719dfa2015
6
bot.py
6
bot.py
|
|
@ -376,8 +376,10 @@ async def handle_ai_task(update: Update, text: str):
|
|||
# Формируем контекст с историей + памятью + summary
|
||||
# Получаем summary и последние сообщения из ChromaDB
|
||||
summary = None
|
||||
recent_messages = []
|
||||
try:
|
||||
summary, recent_messages = compactor.get_context_with_summary(limit=20)
|
||||
if compactor is not None:
|
||||
summary, recent_messages = compactor.get_context_with_summary(limit=20)
|
||||
# Формируем историю из последних сообщений
|
||||
history_context = "\n".join([f"{msg['role']}: {msg['content']}" for msg in recent_messages])
|
||||
except Exception as e:
|
||||
|
|
@ -859,7 +861,7 @@ async def handle_ssh_session_input(update: Update, text: str, session: SSHSessio
|
|||
while not is_done:
|
||||
more_output, is_done = await read_ssh_output(session.process, timeout=5.0)
|
||||
output += more_output
|
||||
session.output_buffer += output
|
||||
session.output_buffer += more_output
|
||||
session.last_activity = datetime.now()
|
||||
|
||||
new_input_type = detect_input_type(output)
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ class DialogueCompactor:
|
|||
logger.info("Запуск Qwen Code для сжатия...")
|
||||
|
||||
# Запускаем задачу
|
||||
await self.qwen_manager.run_task(
|
||||
result = await self.qwen_manager.run_task(
|
||||
user_id=999, # Системный user_id для компактификации
|
||||
task=prompt,
|
||||
on_output=on_output,
|
||||
|
|
@ -349,9 +349,30 @@ class DialogueCompactor:
|
|||
use_system_prompt=False # Не добавляем системный промпт бота
|
||||
)
|
||||
|
||||
summary = "".join(output_parts)
|
||||
# Парсим результат - извлекаем текст из JSON как в основном коде
|
||||
import re
|
||||
summary = "".join(output_parts).strip()
|
||||
|
||||
# Извлекаем текст из JSON ответа (как в bot.py)
|
||||
text_matches = re.findall(r'"text":"([^"]+)"', summary)
|
||||
if text_matches:
|
||||
summary = " ".join(text_matches).replace("\\n", "\n")
|
||||
else:
|
||||
# Fallback: пробуем найти result поле
|
||||
try:
|
||||
import json
|
||||
for line in summary.split('\n'):
|
||||
line = line.strip()
|
||||
if line.startswith('{'):
|
||||
data = json.loads(line)
|
||||
if data.get('type') == 'result':
|
||||
summary = data.get('result', summary)
|
||||
break
|
||||
if data.get('result'):
|
||||
summary = data.get('result', summary)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Очищаем summary от служебных символов
|
||||
summary = summary.strip()
|
||||
|
||||
if not summary:
|
||||
|
|
|
|||
|
|
@ -501,6 +501,9 @@ class CronTool(BaseTool):
|
|||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
# Обновляем next_run после успешного выполнения
|
||||
await self.update_next_run(job_id)
|
||||
|
||||
return ToolResult(
|
||||
success=True,
|
||||
data=result_data,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,14 @@ from datetime import datetime, timedelta
|
|||
from typing import Optional, Dict, Callable, Any, List, Union
|
||||
from enum import Enum
|
||||
|
||||
from bot.base_ai_provider import (
|
||||
BaseAIProvider,
|
||||
ProviderResponse,
|
||||
AIMessage,
|
||||
ToolCall,
|
||||
ToolCallStatus,
|
||||
)
|
||||
|
||||
# Импортируем OAuth модуль и константы
|
||||
from bot.utils.qwen_oauth import (
|
||||
get_authorization_url,
|
||||
|
|
@ -596,7 +604,7 @@ class QwenCodeManager:
|
|||
return '\n'.join(cleaned) if cleaned else output
|
||||
|
||||
|
||||
class GigaChatProvider:
|
||||
class GigaChatProvider(BaseAIProvider):
|
||||
"""
|
||||
AI-провайдер для работы с GigaChat API.
|
||||
|
||||
|
|
@ -605,10 +613,23 @@ class GigaChatProvider:
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._tool = None
|
||||
self._initialized = False
|
||||
self._config_error: Optional[str] = None
|
||||
|
||||
@property
|
||||
def provider_name(self) -> str:
|
||||
return "GigaChat"
|
||||
|
||||
@property
|
||||
def supports_tools(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def supports_streaming(self) -> bool:
|
||||
return False
|
||||
|
||||
def _ensure_initialized(self):
|
||||
"""Ленивая инициализация инструмента"""
|
||||
if self._initialized:
|
||||
|
|
@ -729,6 +750,94 @@ class GigaChatProvider:
|
|||
self._ensure_initialized()
|
||||
return self._config_error
|
||||
|
||||
async def chat(
|
||||
self,
|
||||
prompt: str,
|
||||
system_prompt: Optional[str] = None,
|
||||
context: Optional[List[Dict[str, str]]] = None,
|
||||
tools: Optional[List[Dict[str, Any]]] = None,
|
||||
on_chunk: Optional[Callable[[str], Any]] = None,
|
||||
user_id: Optional[int] = None,
|
||||
**kwargs
|
||||
) -> ProviderResponse:
|
||||
"""Реализация метода chat для интерфейса BaseAIProvider."""
|
||||
result = await self.chat(
|
||||
prompt=prompt,
|
||||
system_prompt=system_prompt,
|
||||
on_chunk=on_chunk,
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
return ProviderResponse(
|
||||
success=True,
|
||||
message=AIMessage(
|
||||
content=result.get("content", ""),
|
||||
metadata={"model": result.get("model")}
|
||||
),
|
||||
provider_name=self.provider_name,
|
||||
usage=result.get("usage")
|
||||
)
|
||||
else:
|
||||
return ProviderResponse(
|
||||
success=False,
|
||||
error=result.get("error", "Unknown error"),
|
||||
provider_name=self.provider_name
|
||||
)
|
||||
|
||||
async def execute_tool(
|
||||
self,
|
||||
tool_name: str,
|
||||
tool_args: Dict[str, Any],
|
||||
tool_call_id: Optional[str] = None,
|
||||
**kwargs
|
||||
) -> ToolCall:
|
||||
"""GigaChat не поддерживает инструменты нативно."""
|
||||
return ToolCall(
|
||||
tool_name=tool_name,
|
||||
tool_args=tool_args,
|
||||
tool_call_id=tool_call_id,
|
||||
status=ToolCallStatus.PENDING
|
||||
)
|
||||
|
||||
async def process_with_tools(
|
||||
self,
|
||||
prompt: str,
|
||||
system_prompt: Optional[str] = None,
|
||||
context: Optional[List[Dict[str, str]]] = None,
|
||||
tools_registry: Optional[Dict[str, Any]] = None,
|
||||
on_chunk: Optional[Callable[[str], Any]] = None,
|
||||
max_iterations: int = 5,
|
||||
**kwargs
|
||||
) -> ProviderResponse:
|
||||
"""Обработка запроса с инструментами для GigaChat.
|
||||
|
||||
GigaChat не поддерживает инструменты нативно, поэтому просто
|
||||
выполняем запрос без инструментов.
|
||||
"""
|
||||
# GigaChat не поддерживает инструменты - выполняем обычный запрос
|
||||
result = await self.chat(
|
||||
prompt=prompt,
|
||||
system_prompt=system_prompt,
|
||||
on_chunk=on_chunk,
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
return ProviderResponse(
|
||||
success=True,
|
||||
message=AIMessage(
|
||||
content=result.get("content", ""),
|
||||
metadata={"model": result.get("model")}
|
||||
),
|
||||
provider_name=self.provider_name,
|
||||
usage=result.get("usage")
|
||||
)
|
||||
else:
|
||||
return ProviderResponse(
|
||||
success=False,
|
||||
error=result.get("error", "Unknown error"),
|
||||
provider_name=self.provider_name
|
||||
)
|
||||
|
||||
|
||||
# Глобальный менеджер
|
||||
qwen_manager = QwenCodeManager()
|
||||
|
|
|
|||
|
|
@ -180,18 +180,22 @@ class VectorMemoryStorage:
|
|||
# Преобразуем результаты
|
||||
found_messages = []
|
||||
|
||||
if results and results['ids'] and results['ids'][0]:
|
||||
if results and results.get('ids') and results['ids']:
|
||||
docs = results.get('documents', [[]])[0]
|
||||
metas = results.get('metadatas', [[]])[0]
|
||||
dists = results.get('distances', [[]])[0] if results.get('distances') else []
|
||||
|
||||
for i, doc_id in enumerate(results['ids'][0]):
|
||||
doc_text = results['documents'][0][i]
|
||||
metadata = results['metadatas'][0][i]
|
||||
distance = results['distances'][0][i] if results['distances'] else 0.0
|
||||
doc_text = docs[i] if i < len(docs) else ""
|
||||
metadata = metas[i] if i < len(metas) else {}
|
||||
distance = dists[i] if i < len(dists) else 0.0
|
||||
|
||||
message = Message(
|
||||
id=None,
|
||||
user_id=int(metadata['user_id']),
|
||||
role=metadata['role'],
|
||||
user_id=int(metadata.get('user_id', 0)),
|
||||
role=metadata.get('role', 'user'),
|
||||
content=doc_text,
|
||||
timestamp=datetime.fromisoformat(metadata['timestamp']),
|
||||
timestamp=datetime.fromisoformat(metadata.get('timestamp', datetime.now().isoformat())),
|
||||
session_id=metadata.get('session_id')
|
||||
)
|
||||
|
||||
|
|
@ -226,10 +230,13 @@ class VectorMemoryStorage:
|
|||
)
|
||||
|
||||
messages = []
|
||||
if results and results.get('ids') and results['ids'][0]:
|
||||
if results and results.get('ids') and results['ids']:
|
||||
docs = results.get('documents', [[]])[0] if results.get('documents') else []
|
||||
metas = results.get('metadatas', [[]])[0] if results.get('metadatas') else []
|
||||
|
||||
for i, doc_id in enumerate(results['ids'][0]):
|
||||
doc_text = results['documents'][0][i] if 'documents' in results else ""
|
||||
metadata = results['metadatas'][0][i] if 'metadatas' in results else {}
|
||||
doc_text = docs[i] if i < len(docs) else ""
|
||||
metadata = metas[i] if i < len(metas) else {}
|
||||
|
||||
message = Message(
|
||||
id=None,
|
||||
|
|
@ -480,8 +487,14 @@ class HybridMemoryManager:
|
|||
"""
|
||||
|
||||
try:
|
||||
# Импортируем qwen_manager
|
||||
# Импортируем qwen_manager и проверяем авторизацию
|
||||
from qwen_integration import qwen_manager
|
||||
from bot.utils.qwen_oauth import is_authorized
|
||||
|
||||
# Проверяем авторизацию перед выполнением
|
||||
if not await is_authorized():
|
||||
logger.warning(f"Qwen не авторизован, пропускаем извлечение фактов для пользователя {user_id}")
|
||||
return []
|
||||
|
||||
output_buffer = []
|
||||
def on_output(text):
|
||||
|
|
|
|||
Loading…
Reference in New Issue