重构:移除 AI 管理模块
This commit is contained in:
@@ -1,172 +0,0 @@
|
||||
from importlib import import_module
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from config.database import async_engine
|
||||
from config.env import DataBaseConfig
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from agno.db.base import AsyncBaseDb
|
||||
from agno.models.base import Model
|
||||
|
||||
# 提供商名称 -> (模块路径, 类名) 的映射,延迟导入避免启动时加载所有AI SDK
|
||||
_PROVIDER_REGISTRY: dict[str, tuple[str, str]] = {
|
||||
'AIMLAPI': ('agno.models.aimlapi', 'AIMLAPI'),
|
||||
'Anthropic': ('agno.models.anthropic', 'Claude'),
|
||||
'Cerebras': ('agno.models.cerebras', 'Cerebras'),
|
||||
'CerebrasOpenAI': ('agno.models.cerebras', 'CerebrasOpenAI'),
|
||||
'Cohere': ('agno.models.cohere', 'Cohere'),
|
||||
'CometAPI': ('agno.models.cometapi', 'CometAPI'),
|
||||
'DashScope': ('agno.models.dashscope', 'DashScope'),
|
||||
'DeepInfra': ('agno.models.deepinfra', 'DeepInfra'),
|
||||
'DeepSeek': ('agno.models.deepseek', 'DeepSeek'),
|
||||
'Fireworks': ('agno.models.fireworks', 'Fireworks'),
|
||||
'Google': ('agno.models.google', 'Gemini'),
|
||||
'Groq': ('agno.models.groq', 'Groq'),
|
||||
'HuggingFace': ('agno.models.huggingface', 'HuggingFace'),
|
||||
'LangDB': ('agno.models.langdb', 'LangDB'),
|
||||
'LiteLLM': ('agno.models.litellm', 'LiteLLM'),
|
||||
'LiteLLMOpenAI': ('agno.models.litellm', 'LiteLLMOpenAI'),
|
||||
'LlamaCpp': ('agno.models.llama_cpp', 'LlamaCpp'),
|
||||
'LMStudio': ('agno.models.lmstudio', 'LMStudio'),
|
||||
'Meta': ('agno.models.meta', 'Llama'),
|
||||
'Mistral': ('agno.models.mistral', 'MistralChat'),
|
||||
'N1N': ('agno.models.n1n', 'N1N'),
|
||||
'Nebius': ('agno.models.nebius', 'Nebius'),
|
||||
'Nexus': ('agno.models.nexus', 'Nexus'),
|
||||
'Nvidia': ('agno.models.nvidia', 'Nvidia'),
|
||||
'Ollama': ('agno.models.ollama', 'Ollama'),
|
||||
'OpenAI': ('agno.models.openai', 'OpenAIChat'),
|
||||
'OpenAIResponses': ('agno.models.openai.responses', 'OpenAIResponses'),
|
||||
'OpenRouter': ('agno.models.openrouter', 'OpenRouter'),
|
||||
'Perplexity': ('agno.models.perplexity', 'Perplexity'),
|
||||
'Portkey': ('agno.models.portkey', 'Portkey'),
|
||||
'Requesty': ('agno.models.requesty', 'Requesty'),
|
||||
'Sambanova': ('agno.models.sambanova', 'Sambanova'),
|
||||
'SiliconFlow': ('agno.models.siliconflow', 'Siliconflow'),
|
||||
'Together': ('agno.models.together', 'Together'),
|
||||
'Vercel': ('agno.models.vercel', 'V0'),
|
||||
'VLLM': ('agno.models.vllm', 'VLLM'),
|
||||
'xAI': ('agno.models.xai', 'xAI'),
|
||||
}
|
||||
|
||||
# 存储引擎名称 -> (模块路径, 类名) 的映射
|
||||
_STORAGE_ENGINE_REGISTRY: dict[str, tuple[str, str]] = {
|
||||
'mysql': ('agno.db.mysql', 'AsyncMySQLDb'),
|
||||
'postgresql': ('agno.db.postgres', 'AsyncPostgresDb'),
|
||||
}
|
||||
|
||||
# 已加载的提供商类缓存,避免重复import_module
|
||||
_provider_class_cache: dict[str, 'type[Model]'] = {}
|
||||
_storage_class_cache: dict[str, 'type[AsyncBaseDb]'] = {}
|
||||
|
||||
|
||||
class AiUtil:
|
||||
"""
|
||||
AI工具类
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _resolve_provider_class(cls, provider: str) -> 'type[Model] | None':
|
||||
"""
|
||||
按需加载并缓存提供商模型类
|
||||
|
||||
:param provider: 提供商名称
|
||||
:return: 模型类,未找到返回None
|
||||
"""
|
||||
if provider in _provider_class_cache:
|
||||
return _provider_class_cache[provider]
|
||||
entry = _PROVIDER_REGISTRY.get(provider)
|
||||
if entry is None:
|
||||
return None
|
||||
module_path, class_name = entry
|
||||
provider_cls = getattr(import_module(module_path), class_name)
|
||||
_provider_class_cache[provider] = provider_cls
|
||||
return provider_cls
|
||||
|
||||
@classmethod
|
||||
def _resolve_storage_class(cls, db_type: str) -> 'type[AsyncBaseDb]':
|
||||
"""
|
||||
按需加载并缓存存储引擎类
|
||||
|
||||
:param db_type: 数据库类型
|
||||
:return: 存储引擎类
|
||||
"""
|
||||
if db_type in _storage_class_cache:
|
||||
return _storage_class_cache[db_type]
|
||||
entry = _STORAGE_ENGINE_REGISTRY.get(db_type)
|
||||
if entry is None:
|
||||
# 默认使用MySQL
|
||||
entry = _STORAGE_ENGINE_REGISTRY['mysql']
|
||||
module_path, class_name = entry
|
||||
storage_cls = getattr(import_module(module_path), class_name)
|
||||
_storage_class_cache[db_type] = storage_cls
|
||||
return storage_cls
|
||||
|
||||
@classmethod
|
||||
def get_storage_engine(cls) -> 'AsyncBaseDb':
|
||||
"""
|
||||
获取存储引擎实例
|
||||
|
||||
:return: 存储引擎实例
|
||||
"""
|
||||
storage_engine_class = cls._resolve_storage_class(DataBaseConfig.db_type)
|
||||
|
||||
return storage_engine_class(
|
||||
db_engine=async_engine,
|
||||
db_schema=DataBaseConfig.db_database if DataBaseConfig.db_type == 'mysql' else 'public',
|
||||
session_table='ai_sessions',
|
||||
memory_table='ai_memories',
|
||||
metrics_table='ai_metrics',
|
||||
eval_table='ai_eval_runs',
|
||||
knowledge_table='ai_knowledge',
|
||||
culture_table='ai_culture',
|
||||
traces_table='ai_traces',
|
||||
spans_table='ai_spans',
|
||||
versions_table='ai_schema_versions',
|
||||
create_schema=False,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_model_from_factory(
|
||||
cls,
|
||||
provider: str,
|
||||
model_code: str,
|
||||
model_name: str | None = None,
|
||||
api_key: str | None = None,
|
||||
base_url: str | None = None,
|
||||
temperature: float | None = None,
|
||||
max_tokens: int | None = None,
|
||||
**kwargs,
|
||||
) -> 'Model':
|
||||
"""
|
||||
从工厂获取模型实例
|
||||
|
||||
:param provider: 提供商
|
||||
:param model_code: 模型编码
|
||||
:param model_name: 模型名称
|
||||
:param api_key: API密钥
|
||||
:param base_url: 基础URL
|
||||
:param temperature: 温度
|
||||
:param max_tokens: 最大令牌数
|
||||
:return: 模型实例
|
||||
"""
|
||||
params = {
|
||||
'id': model_code,
|
||||
'name': model_name,
|
||||
'base_url': base_url,
|
||||
'api_key': api_key,
|
||||
'temperature': temperature,
|
||||
'max_tokens': max_tokens,
|
||||
**kwargs,
|
||||
}
|
||||
params = {k: v for k, v in params.items() if v is not None}
|
||||
if provider == 'Ollama':
|
||||
params['host'] = base_url
|
||||
if provider == 'DashScope' and not base_url:
|
||||
params['base_url'] = 'https://dashscope.aliyuncs.com/compatible-mode/v1'
|
||||
model_class = cls._resolve_provider_class(provider)
|
||||
if model_class is None:
|
||||
# 未知提供商,回退到OpenAI
|
||||
model_class = cls._resolve_provider_class('OpenAI')
|
||||
|
||||
return model_class(**params)
|
||||
@@ -1,58 +0,0 @@
|
||||
import base64
|
||||
import hashlib
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
from config.env import JwtConfig
|
||||
from exceptions.exception import ServiceException
|
||||
|
||||
|
||||
class CryptoUtil:
|
||||
"""
|
||||
加解密工具类
|
||||
"""
|
||||
|
||||
_cipher_suite = None
|
||||
|
||||
@classmethod
|
||||
def _get_cipher_suite(cls) -> Fernet:
|
||||
if cls._cipher_suite is None:
|
||||
# 使用 JWT secret key 派生 Fernet key
|
||||
# SHA256 hash (32 bytes) -> Base64 encoded (44 bytes) -> Fernet key
|
||||
key = base64.urlsafe_b64encode(hashlib.sha256(JwtConfig.jwt_secret_key.encode()).digest())
|
||||
cls._cipher_suite = Fernet(key)
|
||||
return cls._cipher_suite
|
||||
|
||||
@classmethod
|
||||
def encrypt(cls, data: str) -> str:
|
||||
"""
|
||||
加密字符串
|
||||
|
||||
:param data: 明文
|
||||
:return: 密文
|
||||
"""
|
||||
if not data:
|
||||
return data
|
||||
try:
|
||||
cipher_suite = cls._get_cipher_suite()
|
||||
encrypted_bytes = cipher_suite.encrypt(data.encode('utf-8'))
|
||||
return encrypted_bytes.decode('utf-8')
|
||||
except Exception as e:
|
||||
raise ServiceException('加密失败') from e
|
||||
|
||||
@classmethod
|
||||
def decrypt(cls, token: str) -> str:
|
||||
"""
|
||||
解密字符串
|
||||
|
||||
:param token: 密文
|
||||
:return: 明文
|
||||
"""
|
||||
if not token:
|
||||
return token
|
||||
try:
|
||||
cipher_suite = cls._get_cipher_suite()
|
||||
decrypted_bytes = cipher_suite.decrypt(token.encode('utf-8'))
|
||||
return decrypted_bytes.decode('utf-8')
|
||||
except Exception as e:
|
||||
raise ServiceException('解密失败') from e
|
||||
@@ -590,9 +590,6 @@ class LoggerInitializer:
|
||||
for logger_name in ('uvicorn', 'uvicorn.error', 'uvicorn.access', 'fastapi'):
|
||||
logging.getLogger(logger_name).handlers = [InterceptHandler()]
|
||||
logging.getLogger(logger_name).propagate = False
|
||||
for logger_name in ('LiteLLM', 'litellm'):
|
||||
logging.getLogger(logger_name).setLevel(logging.WARNING)
|
||||
|
||||
def init_log(self) -> Logger:
|
||||
"""
|
||||
初始化 Loguru 输出与标准 logging 配置
|
||||
|
||||
Reference in New Issue
Block a user