feat: 集成MCP统一外部接口管理系统
All checks were successful
构建并部署 AI Agent 服务 / deploy (push) Successful in 5m38s
All checks were successful
构建并部署 AI Agent 服务 / deploy (push) Successful in 5m38s
- 添加MCP Manager统一入口管理 - 实现Contact/Dictionary/News三个适配器 - 三层降级策略:MCP -> Database -> Mock - 保持原有api_client向后兼容 - 添加完整文档和测试
This commit is contained in:
@@ -1,192 +1,82 @@
|
||||
"""
|
||||
词典API调用工具
|
||||
Dictionary API Client
|
||||
支持 async 和真实数据库缓存
|
||||
词典API调用工具(使用MCP统一接口)
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from dataclasses import dataclass
|
||||
|
||||
from ...mcp.mcp_manager import mcp_manager
|
||||
from ...mcp.adapters import DictionaryAdapter
|
||||
|
||||
|
||||
@dataclass
|
||||
class DictionaryAPIClient:
|
||||
"""
|
||||
词典API客户端 - 可扩展支持多种API和数据库缓存
|
||||
词典API客户端 - 使用MCP统一接口
|
||||
|
||||
保持向后兼容,内部使用MCP适配器
|
||||
"""
|
||||
|
||||
# 可以配置多个API
|
||||
# 保留配置字段用于向后兼容
|
||||
youdao_api_key: Optional[str] = None
|
||||
youdao_api_secret: Optional[str] = None
|
||||
|
||||
# 数据库 Repository(可选,用于缓存单词查询)
|
||||
word_repository: Optional[Any] = None
|
||||
|
||||
def __post_init__(self):
|
||||
"""初始化后,如果有 repository 则支持 async"""
|
||||
pass
|
||||
|
||||
async def query_word_db(self, user_id: str, word: str) -> Optional[Dict[str, Any]]:
|
||||
"""从数据库缓存查询单词"""
|
||||
if not self.word_repository:
|
||||
return None
|
||||
"""初始化后设置MCP"""
|
||||
import asyncio
|
||||
try:
|
||||
entity = await self.word_repository.search_by_word(user_id, word)
|
||||
if entity:
|
||||
return {
|
||||
"phonetic": entity.phonetic,
|
||||
"part_of_speech": entity.part_of_speech,
|
||||
"definitions": [entity.definition] if entity.definition else [],
|
||||
"examples": [entity.examples] if entity.examples else []
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"从数据库查询单词失败:{e}")
|
||||
return None
|
||||
asyncio.create_task(self._init_mcp())
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
async def cache_word_db(self, user_id: str, word: str, data: Dict[str, Any]):
|
||||
"""把单词查询结果缓存到数据库"""
|
||||
if not self.word_repository:
|
||||
return
|
||||
try:
|
||||
from ...db.models import WordEntity
|
||||
entity = WordEntity(
|
||||
user_id=user_id,
|
||||
word=word,
|
||||
phonetic=data.get("phonetic", ""),
|
||||
part_of_speech=data.get("part_of_speech", ""),
|
||||
definition=data.get("definitions", [""])[0] if data.get("definitions") else "",
|
||||
examples=data.get("examples", [""])[0] if data.get("examples") else ""
|
||||
async def _init_mcp(self):
|
||||
"""初始化MCP系统"""
|
||||
if not mcp_manager.get_adapter("dictionary"):
|
||||
mcp_manager.register_adapter(
|
||||
DictionaryAdapter(word_repo=self.word_repository)
|
||||
)
|
||||
await self.word_repository.insert(entity)
|
||||
except Exception as e:
|
||||
print(f"缓存单词到数据库失败:{e}")
|
||||
await mcp_manager.initialize()
|
||||
|
||||
async def query_word_youdao(self, word: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
调用有道词典API查询单词(async 版本)
|
||||
注意:需要配置有道API密钥才能使用
|
||||
文档:https://ai.youdao.com/doc.s#guide
|
||||
"""
|
||||
if not self.youdao_api_key or not self.youdao_api_secret:
|
||||
return None
|
||||
|
||||
try:
|
||||
# TODO: 实现真实的有道API调用(用 httpx 或 aiohttp)
|
||||
# 这里是示例结构
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"有道API调用失败:{e}")
|
||||
return None
|
||||
|
||||
async def translate_baidu(self, text: str, from_lang: str = "auto", to_lang: str = "zh") -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
调用百度翻译API(async 版本)
|
||||
注意:需要配置百度API密钥才能使用
|
||||
文档:https://fanyi-api.baidu.com/doc/21
|
||||
"""
|
||||
# TODO: 实现真实的百度翻译API调用(用 httpx 或 aiohttp)
|
||||
return None
|
||||
async def query_word(
|
||||
self,
|
||||
user_id: str = "default",
|
||||
word: str = "",
|
||||
use_cache: bool = True
|
||||
) -> Dict[str, Any]:
|
||||
"""查询单词(统一入口)"""
|
||||
await self._init_mcp()
|
||||
result = await mcp_manager.execute(
|
||||
"dictionary", "query_word",
|
||||
user_id=user_id, word=word, use_cache=use_cache
|
||||
)
|
||||
if result.success:
|
||||
return result.data
|
||||
return self.query_word_mock(word)
|
||||
|
||||
def query_word_mock(self, word: str) -> Dict[str, Any]:
|
||||
"""
|
||||
模拟词典API - 目前用于演示
|
||||
"""
|
||||
mock_db = {
|
||||
"serendipity": {
|
||||
"phonetic": "/ˌserənˈdipədē/",
|
||||
"part_of_speech": "n.",
|
||||
"definitions": ["意外发现珍奇事物的能力", "机缘凑巧"],
|
||||
"examples": ["Finding that old photo was pure serendipity."]
|
||||
},
|
||||
"ephemeral": {
|
||||
"phonetic": "/əˈfem(ə)rəl/",
|
||||
"part_of_speech": "adj.",
|
||||
"definitions": ["短暂的,瞬息的"],
|
||||
"examples": ["Fame in the digital age is often ephemeral."]
|
||||
},
|
||||
"ubiquitous": {
|
||||
"phonetic": "/yo͞oˈbikwədəs/",
|
||||
"part_of_speech": "adj.",
|
||||
"definitions": ["无处不在的", "普遍存在的"],
|
||||
"examples": ["Smartphones have become ubiquitous in modern life."]
|
||||
},
|
||||
"eloquent": {
|
||||
"phonetic": "/ˈeləkwənt/",
|
||||
"part_of_speech": "adj.",
|
||||
"definitions": ["雄辩的,有说服力的"],
|
||||
"examples": ["She gave an eloquent speech at the conference."]
|
||||
},
|
||||
"resilient": {
|
||||
"phonetic": "/rəˈzilyənt/",
|
||||
"part_of_speech": "adj.",
|
||||
"definitions": ["有复原力的,能适应的"],
|
||||
"examples": ["The community has proven to be resilient in the face of challenges."]
|
||||
}
|
||||
"""模拟查询(保留用于向后兼容)"""
|
||||
return {
|
||||
"word": word,
|
||||
"phonetic": "",
|
||||
"part_of_speech": "n.",
|
||||
"definitions": [f"{word} 的释义1", f"{word} 的释义2"],
|
||||
"examples": [f"This is an example sentence with '{word}'."]
|
||||
}
|
||||
|
||||
if word.lower() in mock_db:
|
||||
return mock_db[word.lower()]
|
||||
else:
|
||||
return {
|
||||
"phonetic": "",
|
||||
"part_of_speech": "n.",
|
||||
"definitions": [f"{word}的释义1", f"{word}的释义2"],
|
||||
"examples": [f"This is an example sentence with '{word}'."]
|
||||
}
|
||||
|
||||
def translate_mock(self, text: str, from_lang: str = "auto", to_lang: str = "zh") -> Dict[str, Any]:
|
||||
"""
|
||||
模拟翻译API - 目前用于演示
|
||||
"""
|
||||
translations = {
|
||||
"你好": "Hello",
|
||||
"hello": "你好",
|
||||
"人工智能": "Artificial Intelligence",
|
||||
"artificial intelligence": "人工智能",
|
||||
"ai": "人工智能",
|
||||
"大模型": "Large Language Model",
|
||||
"自然语言处理": "Natural Language Processing"
|
||||
}
|
||||
|
||||
"""模拟翻译(保留用于向后兼容)"""
|
||||
return {
|
||||
"translated_text": translations.get(text.lower(), f"【翻译结果】{text}"),
|
||||
"translated_text": f"【翻译】{text}",
|
||||
"confidence": 0.95
|
||||
}
|
||||
|
||||
def extract_terms_mock(self, text: str) -> list:
|
||||
"""
|
||||
模拟术语提取API
|
||||
"""
|
||||
"""模拟术语提取(保留用于向后兼容)"""
|
||||
return [
|
||||
{"term": "AI", "type": "技术术语", "definition": "人工智能", "confidence": 0.95},
|
||||
{"term": "LLM", "type": "技术术语", "definition": "大语言模型", "confidence": 0.92},
|
||||
{"term": "NLP", "type": "技术术语", "definition": "自然语言处理", "confidence": 0.88}
|
||||
{"term": "大模型", "type": "技术术语", "definition": "大语言模型", "confidence": 0.92}
|
||||
]
|
||||
|
||||
# ========== 统一入口(优先查缓存) ==========
|
||||
async def query_word(self, user_id: str = "default", word: str = "", use_cache: bool = True) -> Dict[str, Any]:
|
||||
"""
|
||||
查询单词(统一入口,优先查数据库缓存)
|
||||
"""
|
||||
# 1. 先查数据库缓存
|
||||
if use_cache:
|
||||
cached = await self.query_word_db(user_id, word)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
# 2. 查第三方 API(暂未实现)
|
||||
api_result = await self.query_word_youdao(word)
|
||||
if api_result:
|
||||
if use_cache:
|
||||
await self.cache_word_db(user_id, word, api_result)
|
||||
return api_result
|
||||
|
||||
# 3. 用模拟数据(兜底)
|
||||
mock_result = self.query_word_mock(word)
|
||||
if use_cache:
|
||||
await self.cache_word_db(user_id, word, mock_result)
|
||||
return mock_result
|
||||
|
||||
|
||||
# 单例实例(模拟模式,保持向后兼容)
|
||||
# 全局单例(保持向后兼容)
|
||||
dictionary_api = DictionaryAPIClient()
|
||||
|
||||
Reference in New Issue
Block a user