简化API的配置方式
This commit is contained in:
parent
67b4558ef0
commit
8bd7106d96
@ -1,6 +1,6 @@
|
|||||||
# Dify Model Configurations
|
# Dify API Keys Configuration
|
||||||
# Format: JSON string in one line
|
# Format: Comma-separated list of API keys
|
||||||
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=app-xxxxxxxxxxxxxxxx,app-yyyyyyyyyyyyyyyy,app-zzzzzzzzzzzzzzzz
|
||||||
|
|
||||||
# Dify API Base URL
|
# Dify API Base URL
|
||||||
DIFY_API_BASE="https://api.dify.example.com/v1"
|
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 客户端
|
- 兼容标准的 OpenAI API 客户端
|
||||||
- 灵活的模型配置支持
|
- 自动获取 Dify 应用信息
|
||||||
|
|
||||||
## 支持的模型
|
## 支持的模型
|
||||||
|
|
||||||
支持任意 Dify 模型,只需在配置文件中添加对应的 API Key 即可。
|
支持任意 Dify 应用,系统会自动从 Dify API 获取应用名称和信息。只需在配置文件中添加应用的 API Key 即可。
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
@ -45,13 +45,13 @@ cp .env.example .env
|
|||||||
- 发布应用
|
- 发布应用
|
||||||
- 进入"访问 API"页面,生成 API 密钥
|
- 进入"访问 API"页面,生成 API 密钥
|
||||||
|
|
||||||
> **重要说明**:Dify 不支持在请求时动态传入提示词、切换模型及其他参数。所有这些配置都需要在创建应用时设置好。Dify 会根据 API 密钥来确定使用哪个应用及其对应的配置。
|
> **重要说明**:Dify 不支持在请求时动态传入提示词、切换模型及其他参数。所有这些配置都需要在创建应用时设置好。Dify 会根据 API 密钥来确定使用哪个应用及其对应的配置。系统会自动从 Dify API 获取应用的名称和描述信息。
|
||||||
|
|
||||||
3. 在 `.env` 文件中配置你的 Dify 模型和 API Keys:
|
3. 在 `.env` 文件中配置你的 Dify API Keys:
|
||||||
```env
|
```env
|
||||||
# Dify Model Configurations
|
# Dify API Keys Configuration
|
||||||
# 注意:必须是单行的 JSON 字符串格式
|
# Format: Comma-separated list of API keys
|
||||||
MODEL_CONFIG={"claude-3-5-sonnet-v2":"your-claude-api-key","custom-model":"your-custom-api-key"}
|
DIFY_API_KEYS=app-xxxxxxxx,app-yyyyyyyy,app-zzzzzzzz
|
||||||
|
|
||||||
# Dify API Base URL
|
# Dify API Base URL
|
||||||
DIFY_API_BASE="https://your-dify-api-base-url/v1"
|
DIFY_API_BASE="https://your-dify-api-base-url/v1"
|
||||||
@ -61,16 +61,10 @@ SERVER_HOST="127.0.0.1"
|
|||||||
SERVER_PORT=5000
|
SERVER_PORT=5000
|
||||||
```
|
```
|
||||||
|
|
||||||
你可以根据需要添加或删除模型配置,但必须保持 JSON 格式在单行内。这是因为 python-dotenv 的限制。
|
配置说明:
|
||||||
|
- `DIFY_API_KEYS`:以逗号分隔的 API Keys 列表,每个 Key 对应一个 Dify 应用
|
||||||
每个模型配置的格式为:`"模型名称": "Dify应用的API密钥"`。其中:
|
- 系统会自动从 Dify API 获取每个应用的名称和信息
|
||||||
- 模型名称:可以自定义,用于在 API 调用时识别不同的应用
|
- 无需手动配置模型名称和映射关系
|
||||||
- API 密钥:从 Dify 平台获取的应用 API 密钥
|
|
||||||
|
|
||||||
例如,如果你在 Dify 上创建了一个使用 Claude 的翻译应用和一个使用 Gemini 的代码助手应用,可以这样配置:
|
|
||||||
```env
|
|
||||||
MODEL_CONFIG={"translator":"app-xxxxxx","code-assistant":"app-yyyyyy"}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 运行服务
|
### 运行服务
|
||||||
|
|
||||||
@ -101,23 +95,22 @@ print(models)
|
|||||||
"object": "list",
|
"object": "list",
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"id": "claude-3-5-sonnet-v2",
|
"id": "My Translation App", # Dify 应用名称
|
||||||
"object": "model",
|
"object": "model",
|
||||||
"created": 1704603847,
|
"created": 1704603847,
|
||||||
"owned_by": "dify"
|
"owned_by": "dify"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gemini-2.0-flash-thinking-exp-1219",
|
"id": "Code Assistant", # 另一个 Dify 应用名称
|
||||||
"object": "model",
|
"object": "model",
|
||||||
"created": 1704603847,
|
"created": 1704603847,
|
||||||
"owned_by": "dify"
|
"owned_by": "dify"
|
||||||
},
|
}
|
||||||
// ... 其他在 MODEL_CONFIG 中配置的模型
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
只有在 `.env` 文件的 `MODEL_CONFIG` 中配置了 API Key 的模型才会出现在列表中。
|
系统会自动从 Dify API 获取应用名称,并用作模型 ID。
|
||||||
|
|
||||||
### Chat Completions
|
### Chat Completions
|
||||||
|
|
||||||
@ -128,7 +121,7 @@ openai.api_base = "http://127.0.0.1:5000/v1"
|
|||||||
openai.api_key = "any" # 可以使用任意值
|
openai.api_key = "any" # 可以使用任意值
|
||||||
|
|
||||||
response = openai.ChatCompletion.create(
|
response = openai.ChatCompletion.create(
|
||||||
model="claude-3-5-sonnet-v2", # 使用在 MODEL_CONFIG 中配置的模型名称
|
model="My Translation App", # 使用 Dify 应用的名称
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "user", "content": "你好"}
|
{"role": "user", "content": "你好"}
|
||||||
],
|
],
|
||||||
@ -155,9 +148,9 @@ for chunk in response:
|
|||||||
|
|
||||||
### 配置灵活性
|
### 配置灵活性
|
||||||
|
|
||||||
- 支持动态添加新模型
|
- 自动获取应用信息
|
||||||
- 支持 JSON 格式配置
|
- 简化的配置方式
|
||||||
- 支持自定义模型名称
|
- 动态模型名称映射
|
||||||
|
|
||||||
## 贡献指南
|
## 贡献指南
|
||||||
|
|
||||||
|
|||||||
118
main.py
118
main.py
@ -21,51 +21,83 @@ logging.getLogger("httpx").setLevel(logging.DEBUG)
|
|||||||
# 加载环境变量
|
# 加载环境变量
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
def parse_model_config():
|
class DifyModelManager:
|
||||||
"""
|
def __init__(self):
|
||||||
从环境变量解析模型配置
|
self.api_keys = []
|
||||||
返回一个字典 {model_name: api_key}
|
self.name_to_api_key = {} # 应用名称到API Key的映射
|
||||||
"""
|
self.api_key_to_name = {} # API Key到应用名称的映射
|
||||||
try:
|
self.load_api_keys()
|
||||||
config_str = os.getenv('MODEL_CONFIG', '{}')
|
|
||||||
# 尝试作为Python字典解析
|
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:
|
try:
|
||||||
return ast.literal_eval(config_str)
|
async with httpx.AsyncClient() as client:
|
||||||
except (SyntaxError, ValueError) as e:
|
headers = {
|
||||||
logger.error(f"Failed to parse MODEL_CONFIG as Python dict: {e}")
|
"Authorization": f"Bearer {api_key}",
|
||||||
try:
|
"Content-Type": "application/json"
|
||||||
# 尝试作为JSON解析
|
}
|
||||||
return json.loads(config_str)
|
response = await client.get(
|
||||||
except json.JSONDecodeError as e:
|
f"{DIFY_API_BASE}/info",
|
||||||
logger.error(f"Failed to parse MODEL_CONFIG as JSON: {e}")
|
headers=headers,
|
||||||
return {}
|
params={"user": "default_user"}
|
||||||
except Exception as e:
|
)
|
||||||
logger.error(f"Error parsing MODEL_CONFIG: {e}")
|
|
||||||
return {}
|
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 fetching app info: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
# 从环境变量获取配置
|
async def refresh_model_info(self):
|
||||||
MODEL_TO_API_KEY = parse_model_config()
|
"""刷新所有应用信息"""
|
||||||
|
self.name_to_api_key.clear()
|
||||||
|
self.api_key_to_name.clear()
|
||||||
|
|
||||||
|
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]}...")
|
||||||
|
|
||||||
# 根据MODEL_TO_API_KEY自动生成模型信息
|
def get_api_key(self, model_name):
|
||||||
AVAILABLE_MODELS = [
|
"""根据模型名称获取API Key"""
|
||||||
{
|
return self.name_to_api_key.get(model_name)
|
||||||
"id": model_id,
|
|
||||||
"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的模型
|
|
||||||
]
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
def get_available_models(self):
|
||||||
|
"""获取可用模型列表"""
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": name,
|
||||||
|
"object": "model",
|
||||||
|
"created": int(time.time()),
|
||||||
|
"owned_by": "dify"
|
||||||
|
}
|
||||||
|
for name in self.name_to_api_key.keys()
|
||||||
|
]
|
||||||
|
|
||||||
|
# 创建模型管理器实例
|
||||||
|
model_manager = DifyModelManager()
|
||||||
|
|
||||||
# 从环境变量获取API基础URL
|
# 从环境变量获取API基础URL
|
||||||
DIFY_API_BASE = os.getenv("DIFY_API_BASE", "https://mify-be.pt.xiaomi.com/api/v1")
|
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):
|
def get_api_key(model_name):
|
||||||
"""根据模型名称获取对应的API密钥"""
|
"""根据模型名称获取对应的API密钥"""
|
||||||
api_key = MODEL_TO_API_KEY.get(model_name)
|
api_key = model_manager.get_api_key(model_name)
|
||||||
if not api_key:
|
if not api_key:
|
||||||
logger.warning(f"No API key found for model: {model_name}")
|
logger.warning(f"No API key found for model: {model_name}")
|
||||||
return api_key
|
return api_key
|
||||||
@ -149,7 +181,7 @@ def chat_completions():
|
|||||||
# 验证模型是否支持
|
# 验证模型是否支持
|
||||||
api_key = get_api_key(model)
|
api_key = get_api_key(model)
|
||||||
if not api_key:
|
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)
|
logger.error(error_msg)
|
||||||
return {
|
return {
|
||||||
"error": {
|
"error": {
|
||||||
@ -375,11 +407,12 @@ def chat_completions():
|
|||||||
def list_models():
|
def list_models():
|
||||||
"""返回可用的模型列表"""
|
"""返回可用的模型列表"""
|
||||||
logger.info("Listing available models")
|
logger.info("Listing available models")
|
||||||
# 过滤掉没有API密钥的模型
|
|
||||||
available_models = [
|
# 刷新模型信息
|
||||||
model for model in AVAILABLE_MODELS
|
asyncio.run(model_manager.refresh_model_info())
|
||||||
if MODEL_TO_API_KEY.get(model["id"])
|
|
||||||
]
|
# 获取可用模型列表
|
||||||
|
available_models = model_manager.get_available_models()
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
"object": "list",
|
"object": "list",
|
||||||
@ -389,6 +422,9 @@ def list_models():
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
# 启动时初始化模型信息
|
||||||
|
asyncio.run(model_manager.refresh_model_info())
|
||||||
|
|
||||||
host = os.getenv("SERVER_HOST", "127.0.0.1")
|
host = os.getenv("SERVER_HOST", "127.0.0.1")
|
||||||
port = int(os.getenv("SERVER_PORT", 5000))
|
port = int(os.getenv("SERVER_PORT", 5000))
|
||||||
logger.info(f"Starting server on http://{host}:{port}")
|
logger.info(f"Starting server on http://{host}:{port}")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user