简化API的配置方式

This commit is contained in:
LzSkyline 2025-01-08 14:42:27 +08:00
parent 67b4558ef0
commit 8bd7106d96
3 changed files with 99 additions and 70 deletions

View File

@ -1,6 +1,6 @@
# Dify Model Configurations
# Format: JSON string in one line
MODEL_CONFIG={"claude-3-5-sonnet-v2":"app-xxxxxxxxxxxxxxxx","gemini-2.0-flash-thinking-exp-1219":"app-xxxxxxxxxxxxxxxx","o1-preview":"app-xxxxxxxxxxxxxxxx"}
# Dify API Keys Configuration
# Format: Comma-separated list of API keys
DIFY_API_KEYS=app-xxxxxxxxxxxxxxxx,app-yyyyyyyyyyyyyyyy,app-zzzzzzzzzzzzzzzz
# Dify API Base URL
DIFY_API_BASE="https://api.dify.example.com/v1"

View File

@ -12,11 +12,11 @@ OpenDify 是一个将 Dify API 转换为 OpenAI API 格式的代理服务器。
- 支持多个模型配置
- 完整的错误处理和日志记录
- 兼容标准的 OpenAI API 客户端
- 灵活的模型配置支持
- 自动获取 Dify 应用信息
## 支持的模型
支持任意 Dify 模型,只需在配置文件中添加对应的 API Key 即可。
支持任意 Dify 应用,系统会自动从 Dify API 获取应用名称和信息。只需在配置文件中添加应用的 API Key 即可。
## 快速开始
@ -45,13 +45,13 @@ cp .env.example .env
- 发布应用
- 进入"访问 API"页面,生成 API 密钥
> **重要说明**Dify 不支持在请求时动态传入提示词、切换模型及其他参数。所有这些配置都需要在创建应用时设置好。Dify 会根据 API 密钥来确定使用哪个应用及其对应的配置。
> **重要说明**Dify 不支持在请求时动态传入提示词、切换模型及其他参数。所有这些配置都需要在创建应用时设置好。Dify 会根据 API 密钥来确定使用哪个应用及其对应的配置。系统会自动从 Dify API 获取应用的名称和描述信息。
3. 在 `.env` 文件中配置你的 Dify 模型和 API Keys
3. 在 `.env` 文件中配置你的 Dify API Keys
```env
# Dify Model Configurations
# 注意:必须是单行的 JSON 字符串格式
MODEL_CONFIG={"claude-3-5-sonnet-v2":"your-claude-api-key","custom-model":"your-custom-api-key"}
# Dify API Keys Configuration
# Format: Comma-separated list of API keys
DIFY_API_KEYS=app-xxxxxxxx,app-yyyyyyyy,app-zzzzzzzz
# Dify API Base URL
DIFY_API_BASE="https://your-dify-api-base-url/v1"
@ -61,16 +61,10 @@ SERVER_HOST="127.0.0.1"
SERVER_PORT=5000
```
你可以根据需要添加或删除模型配置,但必须保持 JSON 格式在单行内。这是因为 python-dotenv 的限制。
每个模型配置的格式为:`"模型名称": "Dify应用的API密钥"`。其中:
- 模型名称:可以自定义,用于在 API 调用时识别不同的应用
- API 密钥:从 Dify 平台获取的应用 API 密钥
例如,如果你在 Dify 上创建了一个使用 Claude 的翻译应用和一个使用 Gemini 的代码助手应用,可以这样配置:
```env
MODEL_CONFIG={"translator":"app-xxxxxx","code-assistant":"app-yyyyyy"}
```
配置说明:
- `DIFY_API_KEYS`:以逗号分隔的 API Keys 列表,每个 Key 对应一个 Dify 应用
- 系统会自动从 Dify API 获取每个应用的名称和信息
- 无需手动配置模型名称和映射关系
### 运行服务
@ -101,23 +95,22 @@ print(models)
"object": "list",
"data": [
{
"id": "claude-3-5-sonnet-v2",
"id": "My Translation App", # Dify 应用名称
"object": "model",
"created": 1704603847,
"owned_by": "dify"
},
{
"id": "gemini-2.0-flash-thinking-exp-1219",
"id": "Code Assistant", # 另一个 Dify 应用名称
"object": "model",
"created": 1704603847,
"owned_by": "dify"
},
// ... 其他在 MODEL_CONFIG 中配置的模型
}
]
}
```
只有在 `.env` 文件的 `MODEL_CONFIG` 中配置了 API Key 的模型才会出现在列表中
系统会自动从 Dify API 获取应用名称,并用作模型 ID
### Chat Completions
@ -128,7 +121,7 @@ openai.api_base = "http://127.0.0.1:5000/v1"
openai.api_key = "any" # 可以使用任意值
response = openai.ChatCompletion.create(
model="claude-3-5-sonnet-v2", # 使用在 MODEL_CONFIG 中配置的模型名称
model="My Translation App", # 使用 Dify 应用的名称
messages=[
{"role": "user", "content": "你好"}
],
@ -155,9 +148,9 @@ for chunk in response:
### 配置灵活性
- 支持动态添加新模型
- 支持 JSON 格式配置
- 支持自定义模型名称
- 自动获取应用信息
- 简化的配置方式
- 动态模型名称映射
## 贡献指南

106
main.py
View File

@ -21,51 +21,83 @@ logging.getLogger("httpx").setLevel(logging.DEBUG)
# 加载环境变量
load_dotenv()
def parse_model_config():
"""
从环境变量解析模型配置
返回一个字典 {model_name: api_key}
"""
class DifyModelManager:
def __init__(self):
self.api_keys = []
self.name_to_api_key = {} # 应用名称到API Key的映射
self.api_key_to_name = {} # API Key到应用名称的映射
self.load_api_keys()
def load_api_keys(self):
"""从环境变量加载API Keys"""
api_keys_str = os.getenv('DIFY_API_KEYS', '')
if api_keys_str:
self.api_keys = [key.strip() for key in api_keys_str.split(',') if key.strip()]
logger.info(f"Loaded {len(self.api_keys)} API keys")
async def fetch_app_info(self, api_key):
"""获取Dify应用信息"""
try:
config_str = os.getenv('MODEL_CONFIG', '{}')
# 尝试作为Python字典解析
try:
return ast.literal_eval(config_str)
except (SyntaxError, ValueError) as e:
logger.error(f"Failed to parse MODEL_CONFIG as Python dict: {e}")
try:
# 尝试作为JSON解析
return json.loads(config_str)
except json.JSONDecodeError as e:
logger.error(f"Failed to parse MODEL_CONFIG as JSON: {e}")
return {}
async with httpx.AsyncClient() as client:
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
response = await client.get(
f"{DIFY_API_BASE}/info",
headers=headers,
params={"user": "default_user"}
)
if response.status_code == 200:
app_info = response.json()
return app_info.get("name", "Unknown App")
else:
logger.error(f"Failed to fetch app info for API key: {api_key[:8]}...")
return None
except Exception as e:
logger.error(f"Error parsing MODEL_CONFIG: {e}")
return {}
logger.error(f"Error fetching app info: {str(e)}")
return None
# 从环境变量获取配置
MODEL_TO_API_KEY = parse_model_config()
async def refresh_model_info(self):
"""刷新所有应用信息"""
self.name_to_api_key.clear()
self.api_key_to_name.clear()
# 根据MODEL_TO_API_KEY自动生成模型信息
AVAILABLE_MODELS = [
for api_key in self.api_keys:
app_name = await self.fetch_app_info(api_key)
if app_name:
self.name_to_api_key[app_name] = api_key
self.api_key_to_name[api_key] = app_name
logger.info(f"Mapped app '{app_name}' to API key: {api_key[:8]}...")
def get_api_key(self, model_name):
"""根据模型名称获取API Key"""
return self.name_to_api_key.get(model_name)
def get_available_models(self):
"""获取可用模型列表"""
return [
{
"id": model_id,
"id": name,
"object": "model",
"created": int(time.time()),
"owned_by": "dify"
}
for model_id, api_key in MODEL_TO_API_KEY.items()
if api_key is not None # 只包含配置了API Key的模型
]
for name in self.name_to_api_key.keys()
]
app = Flask(__name__)
# 创建模型管理器实例
model_manager = DifyModelManager()
# 从环境变量获取API基础URL
DIFY_API_BASE = os.getenv("DIFY_API_BASE", "https://mify-be.pt.xiaomi.com/api/v1")
app = Flask(__name__)
def get_api_key(model_name):
"""根据模型名称获取对应的API密钥"""
api_key = MODEL_TO_API_KEY.get(model_name)
api_key = model_manager.get_api_key(model_name)
if not api_key:
logger.warning(f"No API key found for model: {model_name}")
return api_key
@ -149,7 +181,7 @@ def chat_completions():
# 验证模型是否支持
api_key = get_api_key(model)
if not api_key:
error_msg = f"Model {model} is not supported. Available models: {', '.join(MODEL_TO_API_KEY.keys())}"
error_msg = f"Model {model} is not supported. Available models: {', '.join(model_manager.name_to_api_key.keys())}"
logger.error(error_msg)
return {
"error": {
@ -375,11 +407,12 @@ def chat_completions():
def list_models():
"""返回可用的模型列表"""
logger.info("Listing available models")
# 过滤掉没有API密钥的模型
available_models = [
model for model in AVAILABLE_MODELS
if MODEL_TO_API_KEY.get(model["id"])
]
# 刷新模型信息
asyncio.run(model_manager.refresh_model_info())
# 获取可用模型列表
available_models = model_manager.get_available_models()
response = {
"object": "list",
@ -389,6 +422,9 @@ def list_models():
return response
if __name__ == '__main__':
# 启动时初始化模型信息
asyncio.run(model_manager.refresh_model_info())
host = os.getenv("SERVER_HOST", "127.0.0.1")
port = int(os.getenv("SERVER_PORT", 5000))
logger.info(f"Starting server on http://{host}:{port}")