refactor(core,ai): 调整模块导入路径并移除废弃文件 - 修复 scheduler.py 中的导入路径错误,将 reports.service 改为 reports.services - 移除废弃的 app/core/background/task_queue.py 文件 - 移除废弃的 app/modules/ai_agent/adapters.py 文件 - 修复 ai_memory/service.py 中的导入路径错误,将 events.service 改为 events.services ```
86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
from typing import Any
|
|
|
|
from fastapi import HTTPException, status
|
|
|
|
from app.core.config import Settings
|
|
from app.modules.ai_agent.adapters import httpx
|
|
from app.modules.ai_agent.adapters.base import AIAdapter
|
|
from app.modules.ai_agent.adapters.common import (
|
|
_chat_completion_payload,
|
|
_chat_messages,
|
|
_response_payload,
|
|
_service_root,
|
|
)
|
|
from app.modules.ai_agent.constants import (
|
|
AUTHORIZATION_BEARER_TEMPLATE,
|
|
UNEXPECTED_HERMES_RESPONSE,
|
|
AIErrorKey,
|
|
AIHttpHeader,
|
|
AIHttpPath,
|
|
AIHttpPayloadKey,
|
|
AIProviderName,
|
|
AIResponseKey,
|
|
)
|
|
|
|
|
|
class HermesAdapter(AIAdapter):
|
|
"""Adapter for the Hermes OpenAI-compatible agent endpoint."""
|
|
|
|
provider_name = AIProviderName.HERMES
|
|
|
|
def __init__(self, settings: Settings):
|
|
self.settings = settings
|
|
|
|
def ask(self, prompt: str, context: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
url = f"{self.settings.hermes_base_url.rstrip('/')}{AIHttpPath.CHAT_COMPLETIONS}"
|
|
headers = {}
|
|
if self.settings.hermes_api_key:
|
|
headers[AIHttpHeader.AUTHORIZATION] = AUTHORIZATION_BEARER_TEMPLATE.format(
|
|
token=self.settings.hermes_api_key
|
|
)
|
|
if self.settings.hermes_session_id:
|
|
headers[AIHttpHeader.HERMES_SESSION_ID] = self.settings.hermes_session_id
|
|
payload = {
|
|
AIHttpPayloadKey.MODEL: self.settings.hermes_model,
|
|
AIHttpPayloadKey.MESSAGES: _chat_messages(prompt, context),
|
|
AIHttpPayloadKey.STREAM: False,
|
|
}
|
|
with httpx.Client(timeout=300, trust_env=False) as client:
|
|
response = client.post(url, json=payload, headers=headers)
|
|
if response.status_code >= status.HTTP_400_BAD_REQUEST:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
|
detail={AIErrorKey.HERMES: response.text},
|
|
)
|
|
data = _chat_completion_payload(response, AIErrorKey.HERMES)
|
|
try:
|
|
answer = data[AIHttpPayloadKey.CHOICES][0][AIHttpPayloadKey.MESSAGE][
|
|
AIHttpPayloadKey.CONTENT
|
|
]
|
|
except (KeyError, IndexError, TypeError) as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
|
detail={
|
|
AIErrorKey.HERMES: UNEXPECTED_HERMES_RESPONSE,
|
|
AIResponseKey.RAW: data,
|
|
},
|
|
) from exc
|
|
return {AIResponseKey.ANSWER: answer, AIResponseKey.RAW: data}
|
|
|
|
def health(self) -> dict[str, Any]:
|
|
"""Check Hermes Agent health without triggering a chat completion."""
|
|
|
|
url = f"{_service_root(self.settings.hermes_base_url, AIHttpPath.V1)}{AIHttpPath.HEALTH}"
|
|
headers = {}
|
|
if self.settings.hermes_api_key:
|
|
headers[AIHttpHeader.AUTHORIZATION] = AUTHORIZATION_BEARER_TEMPLATE.format(
|
|
token=self.settings.hermes_api_key
|
|
)
|
|
with httpx.Client(timeout=5, trust_env=False) as client:
|
|
response = client.get(url, headers=headers)
|
|
return {
|
|
AIResponseKey.OK: response.status_code < status.HTTP_400_BAD_REQUEST,
|
|
AIResponseKey.BASE_URL: self.settings.hermes_base_url.rstrip("/"),
|
|
AIResponseKey.HEALTH: _response_payload(response),
|
|
}
|