Dify2OpenAI is a gateway service that transforms Dify applications into OpenAI API-compatible interfaces, allowing you to access Dify's LLM, Knowledge Base, Tools, and Workflows using OpenAI API-compatible methods.
- Convert Dify API to OpenAI API
- Support streaming and blocking
- Support Chat, Completion, Agent, and Workflow bots API on Dify
- Image Support
- Variable Support
- Continuous Conversation
- Workflow Bot
- Streaming & Blocking
- Agent & Chat bots
git clone https://github.com/onenov/Dify2OpenAI.git
cd Dify2OpenAI
npm installUsing PM2 (Recommended):
# Directly using PM2 command
pm2 start ecosystem.config.cjs
# Or using npm scripts
npm run pm2:startOr start normally:
npm run startThe service will run on http://localhost:3099 by default.
Manage directly with PM2:
# View application status
pm2 list
# View logs
pm2 logs
# Restart application
pm2 restart dify2openai
# Stop application
pm2 stop dify2openai
# Delete application
pm2 delete dify2openai
# Monitor application
pm2 monitManage using npm scripts:
# Start application
npm run pm2:start
# View logs
npm run pm2:logs
# Restart application
npm run pm2:restart
# Stop application
npm run pm2:stop
# Delete application
npm run pm2:delete
# Monitor application
npm run pm2:monit- Click the button above to go to Vercel
- Create and import the project
- Deploy directly, no environment variables needed
- After deployment, you can access it in three ways:
- Pass all configurations in the Authorization Header
- Pass API_KEY in the Authorization Header, other configurations through the model parameter
- Pass DIFY_API_URL in the Authorization Header, other configurations through the model parameter
Note: Vercel serverless functions have a 10-second timeout limit.
The current version only keeps one unified access mode:
Authorizationonly carriesDIFY_API_URLmodelmust bedify|BOT_TYPE|API_KEY
Authorization Header Format:
Authorization: Bearer <DIFY_API_URL>
Model Parameter Format:
"model": "dify|BOT_TYPE|API_KEY"Completion: text generation app, routed to/completion-messagesChat: chat app, routed to/chat-messagesWorkflow: workflow app, routed to/workflows/run
Note: workflow-orchestrated chat apps also use BOT_TYPE=Chat, while preserving richer raw Dify events through x_dify.
curl http://localhost:3099/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer https://api.dify.ai/v1" \
-X POST \
-d '{
"model": "dify|Chat|app-xxxx",
"stream": true,
"response_mode": "streaming",
"user": "demo-user",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Hello"
}
]
}'curl http://localhost:3099/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer https://api.dify.ai/v1" \
-X POST \
-d '{
"model": "dify|Workflow|app-xxxx",
"stream": true,
"response_mode": "streaming",
"user": "demo-user",
"query": "Please execute this task.",
"variable": {
"task_type": "generic",
"priority": "normal"
}
}'curl http://localhost:3099/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer https://api.dify.ai/v1" \
-X POST \
-d '{
"model": "dify|Chat|app-xxxx",
"stream": true,
"response_mode": "streaming",
"user": "abc-123",
"query": "What are the specs of the iPhone 13 Pro Max?",
"conversation_id": "",
"variable": {},
"files": [
"https://example.com/a.png",
"https://example.com/b.txt",
"https://example.com/c.mp4"
]
}'curl http://localhost:3099/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer https://api.dify.ai/v1" \
-X POST \
-d '{
"model": "dify|Chat|app-xxxx",
"stream": true,
"response_mode": "streaming",
"user": "abc-123",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "What are the specs of the iPhone 13 Pro Max?"
},
{
"type": "image_url",
"image_url": {
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
}
]
}
]
}'- Parameter Replacement: Replace
https://api.dify.ai/v1,app-xxxx, andBOT_TYPEwith your actual values. - Fixed
modelFormat: You must usedify|BOT_TYPE|API_KEY. - Fixed
AuthorizationFormat: You must useBearer <DIFY_API_URL>. BOT_TYPE: Available values areChat,Completion, orWorkflow.variable: Supports custom variables and passes them through to Difyinputsas-is. You can use variable names such asinput_*,output_*,custom_*,system_*, anduser_*; make sure to create the corresponding paragraph-type input fields in the Dify Start node first.files: Supports top-levelfilesas a string array, with automatic type inference by URL suffix or Data URL MIME.messages[].content[].image_urlis also supported.stream: Setstreamtotruefor streaming responses, otherwise omit it or set it tofalse.x_difyExtension Field: Both streaming and blocking modes preserve Dify raw events and metadata as much as possible for debugging and workflow event consumption.- Security: Keep your
API_KEYsecure and do not share it with unauthorized parties.
.
├── app.js # Application entry file
├── botType/ # Bot type handlers
│ ├── chatHandler.js # Chat handler
│ ├── completionHandler.js # Completion handler
│ ├── utils.js # Utility functions
│ └── workflowHandler.js # Workflow handler
├── config/ # Configuration files
│ └── logger.js # Logger configuration
├── public/ # Static files directory
│ └── index.html # API documentation page
├── ecosystem.config.cjs # PM2 configuration file
├── nodemon.json # Nodemon configuration file
└── package.json # Project configuration file
The project uses nodemon for hot reloading in development mode:
{
"watch": ["*.js", "botType/*.js", "config/*.js"],
"ext": "js,json,env",
"ignore": [
"node_modules/",
"*.test.js",
"logs/*",
".git",
"public/*"
],
"delay": "500",
"verbose": true
}watch: Files and directories to monitorext: File extensions to monitorignore: Files and directories to ignoredelay: Restart delay in millisecondsverbose: Show detailed logs
- Clone the project
git clone https://github.com/onenov/Dify2OpenAI.git
cd Dify2OpenAI- Install dependencies
npm install- Start development server
npm run dev- Production deployment
npm start
# or using PM2
pm2 start ecosystem.config.cjs- Use ES Modules for imports/exports
- Use async/await for asynchronous operations
- Use try/catch for error handling
- Use winston for logging
By default:
- Production environment (
npm start): Only logs error level, console output only - Development environment (
npm run dev): Logs all levels, outputs to both console and file
Log files are stored in the logs directory:
combined-%DATE%.log: Logs of all levelserror-%DATE%.log: Error level logs only
Supports the following log levels (in order of severity):
error: Error messageswarn: Warning messagesinfo: General informationdebug: Debug information
Each log entry contains:
- Timestamp
- Log level
- Detailed message
- Metadata (if any)
Example:
{
"level": "info",
"message": "Server started successfully",
"timestamp": "2024-12-24T01:51:10+08:00",
"port": 3099
}Log files are automatically rotated according to:
- Daily rotation (new file each day)
- Maximum file size of 20MB
- Keep logs for the last 14 days
- Automatically delete logs exceeding limits
For performance, the logging system:
- Uses buffered writing to reduce I/O operations
- Writes asynchronously to avoid blocking the main thread
- Automatically cleans up expired logs to control disk usage
WeChat:AOKIEO | Mail: dev@orence.ai
This project is licensed under the MIT License - see the LICENSE file for details.
-
Unified authentication format simplified
- Removed the previous mixed configuration modes.
- The gateway now only supports
Authorization: Bearer <DIFY_API_URL>plusmodel=dify|BOT_TYPE|API_KEY. - This keeps runtime behavior and documentation aligned.
-
Unified OpenAI-compatible entry improved
POST /v1/chat/completionsremains the only public entry.- It now clearly covers text generation apps, chat apps, workflow-orchestrated chat apps, and workflow apps.
- Requests are routed automatically to
/completion-messages,/chat-messages, or/workflows/runbased onBOT_TYPE.
-
Fixed
variablewrapper object- The current version uses the top-level
variableobject as the documented way to pass Difyinputs. variablesupports custom variables such asinput_*,output_*,custom_*,system_*, anduser_*, and passes them through to Difyinputsas-is.- Make sure the corresponding paragraph-type input fields are created in the Dify Start node first.
- The current version uses the top-level
-
Top-level
filesstring array support- Added unified handling for top-level
files. - Supports URL strings, base64 Data URLs, and native Dify file objects.
- File type is inferred automatically as
image,document,audio,video, orcustom.
- Added unified handling for top-level
-
messages.image_urlcompatibility retainedmessages[].content[].image_urlis still supported.- It is now collected and normalized together with top-level
filesfor a more consistent multimodal pipeline.
-
Raw Dify event passthrough enhanced
- The
x_difyextension field has been strengthened in both streaming and blocking modes. - Raw Dify events, workflow node events, and metadata are preserved as much as possible for debugging and upper-layer consumers.
- The
-
Workflow-orchestrated chat compatibility improved
- Workflow-orchestrated chat is handled through the more general
Chatpath instead of a single narrow scenario. - Workflow events such as
workflow_started,node_started,node_finished,node_retry, andworkflow_finishedare preserved more clearly.
- Workflow-orchestrated chat is handled through the more general
-
Static documentation page rebuilt
- Removed the OpenAPI / Scalar runtime documentation dependency from the main page.
public/index.htmlnow serves as the single static documentation page.
-
Documentation interaction improved
- The page now supports dynamic
DIFY_API_URL,API_KEY, andBOT_TYPEinputs for generating request schemas and cURL examples. - Request schema tabs are split into
Completion,Chat,Advanced Chat, andWorkflow. - Code blocks support copy buttons, the header includes mail and GitHub icons, and the footer uses an auto-updated year.
- The page now supports dynamic
Thank you for using Dify2OpenAI! If you encounter any problems during use, please feel free to ask and we will assist you as soon as possible.
