简化API的配置方式
This commit is contained in:
parent
67b4558ef0
commit
8bd7106d96
@ -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"
|
||||
|
||||
45
README.md
45
README.md
@ -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
106
main.py
@ -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}")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user