Files
company-ai-platform/app/modules/ai_agent/adapters/hermes.py
JiuContinent d7db84571d ```
feat: 添加飞书用户模块和订阅功能支持

- 新增feishu_users模块用于处理飞书用户身份验证和权限管理
- 新增subscriptions模块用于处理订阅相关功能
- 新增personalization模块用于个性化服务
- 在alembic迁移配置中注册新的模型模块
- 在API路由器中添加feishu_users和subscriptions路由
- 实现事件调度服务的改进,包括错误处理和状态更新优化
- 添加飞书命令处理的权限检查机制
- 实现飞书应用票据事件处理
- 改进审计日志记录功能
```
2026-07-27 08:02:17 +08:00

92 lines
3.4 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,
AIContextKey,
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
)
request_context = context or {}
session_id = (
request_context.get(AIContextKey.PROVIDER_SESSION_ID)
or self.settings.hermes_session_id
)
if session_id:
headers[AIHttpHeader.HERMES_SESSION_ID] = str(session_id)
payload = {
AIHttpPayloadKey.MODEL: self.settings.hermes_model,
AIHttpPayloadKey.MESSAGES: _chat_messages(prompt, request_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),
}