一个基于 Dify API 的 AI 会话 Web 应用, 支持单应用、多应用等多种模式,提供开箱即用的应用配置管理功能。支持不同类型的 Dify 应用,适配深度思考、思维链、图表等多种形式输出。
如果你觉得这个项目还不错的话,请动动你的小手指点个 Star ⭐️ 吧~
加群沟通(提需求/ bug 请带 issue 发言) | 喂我花生(请在留言中备注自己的 Github 用户名哦) |
---|---|
![]() |
![]() |
注:每日手动更新
- forgoodthing
- Unmurphy
- 打豆豆
- TZP
- 匿名慈善家
- 📦 开箱即用:仅需 30 秒配置,即可开始使用
- 💬 随心所欲:支持单应用/多应用模式,满足不同企业级业务场景
- 💃 灵活部署:自身无任何后端依赖,可无缝对接 Dify Cloud 及私有化部署的 API 服务
- 📱 响应式设计:同时支持 PC 和移动端,双端功能同步
- 📝 支持渲染图片、视频、图表等丰富内容,让 AI 自由发挥
- 🔧 长期维护:日益增长的活跃社群,助力功能完善
应用列表:
管理应用配置:
对话参数设置:
<think>
标签(DeepSeek 深度思考):
Chatflow 工作流:
知识库引用链接:
Echarts
图表:
Mermaid
图表:
文档处理:
回复表单:
单应用模式:
移动端支持:
- React v18
- Ant Design v5
- Ant Design X v1
- Rsbuild v1
- Tailwind CSS v3
- TypeScript v5
开发/生产构建环境要求:
- Node.js ^22.5.1
- pnpm ^10.8.1
注意:本项目使用了 pnpm workspace 高级特性来实现 Monorepo 管理,其他包管理工具可能无法正常工作,请先确保你的环境满足以上要求。
本项目支持两种开箱即用的使用方式:
- 单应用模式: 全局只有一个 Dify 应用,用户无需选择,可直接开始对话
- 多应用模式: 提供应用聚合列表页,支持用户选择不同的 Dify 应用,可根据业务需求灵活配置
无论使用哪种模式,我们都需要对接 Dify API,你需要在 Dify 控制台获取几个关键变量:
变量 | 说明 |
---|---|
API Base | Dify API 请求前缀, 如果你使用的是 Dify 官方提供的云服务,则为 https://api.dify.ai/v1 |
Api Key | Dify API 密钥,用于访问对应应用的 API, Dify 应用和 API 密钥是一对多的关系 |
进入 Dify 的应用详情,点击左侧的 访问 API
:
API 服务器
后展示的域名即为 API Base
变量的值。
点击右侧的 API 密钥
按钮,即可看到 API Key 的管理弹窗:
你可以选择创建一个新的 API Key,或者复制现有的 API Key。
完成以上步骤后,我们将会得到如下信息:
- API Base:
https://api.dify.ai/v1
OR${SELF_HOSTED_API_DOMAIN}/v1
- API Key:
app-YOUR_API_KEY
如果你全局只需要一个 Dify 应用, 不想让用户手动修改,可以使用单应用模式。
只需简单修改 src/App.tsx
中 DifyChatProvider
的属性即可:
export default function App() {
return (
<DifyChatProvider
value={{
// 修改为单应用模式
mode: 'singleApp',
// 用户id,可以获取业务系统的用户 ID,动态传入
user: USER,
// 单应用模式下,需要传入 appConfig 配置
appConfig: {
requestConfig: {
apiBase: '上一步中获取到的 API Base',
apiKey: '上一步中获取到的 API Key',
},
},
}}
>
子组件
</DifyChatProvider>
)
}
如果你需要支持用户在界面上配置以及/或者切换多个 Dify 应用,多应用模式也是开箱即用的。
如果之前没有存量数据,第一次进入页面时会展示缺省状态,你需要点击页面底部的 "添加应用配置" 按钮:
此时会弹出添加应用配置的表单抽屉:
依次填入在上一步中获取的 API Base 和 API Secret:
注:其他配置非必需,保持默认值即可。
点击确定按钮,提示 “添加配置成功”,在应用列表中会多出一条数据:
此时你可以点击应用卡片右上角的 "更多" 图标,对应用进行编辑和删除操作:
点击应用卡片,即可进入应用详情页开始对话:
默认实现说明
为方便演示, 本项目默认使用 LocalStorage 进行应用配置管理。
但实际在生产环境中,由于应用配置涉及 API Secret 等机密信息,我们一般会将应用数据存储在服务端,此时就需要接入后端服务来实现应用配置管理。
为方便使用方自定义, 应用配置管理的服务是通过 src/App.tsx
中的 DifyChatProvider
组件注入的:
// src/App.tsx
import { DifyChatProvider } from '@dify-chat/core'
import DifyAppService from './services/app/localstorage'
export default function App() {
return (
<DifyChatProvider
value={{
...其他属性,
appService: new DifyAppService(),
}}
>
子组件
</DifyChatProvider>
)
}
在子组件中,会使用 useDifyChat
钩子获取在顶部注入的 appService
实例并调用相关方法实现应用配置的管理。
自定义后端服务示例
在 "./services/app/restful.ts"
文件有一个 Restful API 的最简实现, 你可以根据下面的步骤来进行体验:
- 运行
pnpm --filter dify-chat-app-server start
启动后端服务 - 将上面的
DifyAppService
导入路径换成"./services/app/restful"
- 运行
pnpm dev
启动前端应用, 访问http://localhost:5200/dify-chat
自定义后端服务实现
如果需要自定义你的后端服务,请遵循以下步骤:
首先,参考 packages/server
,实现以下接口:
- 获取 App 配置列表
- 获取 App 配置详情
- 添加 App 配置
- 更新 App 配置
- 删除 App 配置
然后在 src/services/app
中新建一个文件,只需要继承抽象类 DifyAppStore
并实现它的所有方法, 调用在上述服务中对应的接口即可。
当你不想让用户在界面上管理应用配置, 而是仅提供一个应用列表供用户切换,可以在 src/App.tsx
中添加一个配置项即可:
// src/App.tsx
import { DifyChatProvider } from '@dify-chat/core'
import DifyAppService from './services/app/localstorage'
export default function App() {
return (
<DifyChatProvider
value={{
...其他配置,
enableSetting: false,
}}
>
子组件
</DifyChatProvider>
)
}
此时,页面上就只会展示应用切换按钮, 用户仍然可以切换应用,但设置入口被隐藏:
Dify Cloud 以及私有化部署的 Dify 服务本身均支持跨域请求,无需额外处理,但如果你的私有化部署环境还存在额外的网关层,且对跨域资源访问有严格的限制,可能就会导致跨域问题,处理方式如下:
在你的网关层的响应 Header 处理中,增加 Access-Control-Allow-Origin
字段,允许 Dify-Chat 应用的部署域名访问,以 nginx 为例:
# nginx.conf
server {
listen 443;
server_name dify-chat.com # 这里换成你的前端部署域名
location / {
add_header Access-Control-Allow-Origin https://dify-chat.com; # 这里换成你的前端部署协议+域名
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
}
}
Dify 支持通过 jinja2
来配置回复表单供用户填写,本项目也支持了对应的功能。
Dify Chatflow 编排的回复内容示例:
<form data-format="json">
<label for="username">用户名字:</label>
<input
type="text"
name="username"
value="{{ username }}"
/>
<label for="phone">联系电话:</label>
<input
type="text"
name="phone"
value="{{ phone }}"
/>
<label for="content">投诉内容:</label>
<textarea name="content"></textarea>
<button
data-size="small"
data-variant="primary"
>
提交
</button>
</form>
注意:
- 你需要自行在 Chatflow 中对
sys.query
进行正确的逻辑处理,区分普通消息、触发表单的消息及提交信息。- form 标签的
data-format
属性用于指定表单数据的格式,目前支持json
和text
两种格式。
按照上面的内容回复后,默认情况下,在用户点击表单的提交按钮后,会将表单的值对象作为消息发送给同一个 Dify 应用,同时会在消息列表中展示。提交消息的示例文本:
{
"username": "lexmin",
"phone": "13123456789",
"content": "快递太慢啦,我要举报",
"isFormSubmit": true
}
其中,isFormSubmit
字段用于标识这是一个表单提交的消息, 你可以在 Chatflow 编排的条件分支中使用它来进行判断消息类型。
如果你不想展示具体的表单值 json 字符串,而是需要自定义发送的消息文本,可以按照下面的指引,在应用配置中进行配置(此配置只影响界面展示,实际提交到 Dify Chatflow 开始节点的仍然是用户填写的表单值 json 字符串)。
多应用模式
在添加/更新应用配置弹窗中填写字段:
- 表单回复 - 设置为 "启用"
- 提交消息文本 - 用于替换表单值对象的文本,如 "我提交了一个表单"
单应用模式
在入口文件中,添加对应的属性即可:
export default function App() {
return (
<DifyChatProvider
value={{
mode: 'singleApp',
user: USER,
appConfig: {
requestConfig: {
apiBase: '你的 API Base',
apiKey: '你的 API Secret',
},
answerForm: {
enabled: true,
feedbackText: '我提交了一个表单',
},
},
}}
>
子组件
</DifyChatProvider>
)
}
按照如上配置后,效果如下:
Dify 应用支持配置初始参数,在对话开启时,展示在界面上供用户输入。
默认情况下,同一个对话只允许输入一次参数值,在后续对话时,将会禁用输入控件。
在应用配置中,你可以选择是否允许用户在对话开始后更新参数值:
单应用模式:
增加 inputParams.enableUpdateAfterCvstStarts
配置项:
export default function App() {
return (
<DifyChatProvider
value={{
...其他配置,
appConfig: {
...其他配置,
inputParams: {
// 是否允许用户在对话中更新参数值
enableUpdateAfterCvstStarts: false,
},
},
}}
>
子组件
</DifyChatProvider>
)
}
多应用模式:
在界面上编辑应用配置,将 "对话参数配置" 中的 "更新历史参数" 设为 "启用" 即可。
在实际应用场景下,我们可能有需要在 URL 中动态传入参数值,填入表单。
为了支持此功能,你的 URL 需要定义成如下形式:
<dify-chat-address>/dify-chat/app/<appId>?<paramName>=<encodedParamValue>&isNewCvst=1
默认情况下,对话参数的值为空:
我们可以在 URL 中拼接参数:
http://localhost:5200/dify-chat/app/${appId}?orderNo=${encodedValue}&isNewCvst=1
说明:
appId
, 应用 IDencodedValue
, 经过Gzip
和encodeUriComponent
处理后的参数值isNewCvst
, 指定需要开启新对话(如果不指定且存在历史对话时,默认将会选中最近一个对话)
encodedValue
生成方式(NodeJS):
const zlib = require('zlib')
const originalOrderNo = '123456'
const buffer = Buffer.from(originalString, 'utf8')
let encodedValue = ''
zlib.gzip(buffer, (err, compressedBuffer) => {
if (err) {
console.error('压缩时出错:', err)
return
}
const encodedString = compressedBuffer.toString('base64')
encodedValue = encodeURIComponent(encodedString)
})
将 encodedValue
填入链接后访问,可以看到我们定义的 orderNo: 123456
已经被填入表单:
安装依赖:
pnpm install
启动开发服务器:
支持子包热更新,无需提前构建
pnpm dev
构建生产版本:
pnpm build
预览生产版本:
pnpm preview
进入docker目录启动容器编排:
docker compose up dify-chat -d
浏览器访问http://127.0.0.1:8080/dify-chat/
容器默认暴露http端口8080,https端口8443,可修改.env文件配置环境变量
默认配置的docker镜像为多应用模式,如需自定义使用(如单应用模式)请自行构建docker镜像
在操作之前请编辑.env文件修改以下几个参数:
NGINX_HTTPS_ENABLED=true
#域名
NGINX_SERVER_NAME
#待申请证书的域名
CERTBOT_DOMAIN
NGINX_ENABLE_CERTBOT_CHALLENGE=true
#域名邮箱,随便写
CERTBOT_EMAIL
#更多证书申请参数,可留空
CERTBOT_OPTIONS
注意:请确保你配置的域名可以使用80端口访问到你的 dify-chat 站点,详见:https://eff-certbot.readthedocs.io/en/latest/install.html#alternative-1-docker
在docker目录执行命令即可全自动申请、签发证书:
docker-compose --profile certbot up
签发的证书在[docker/certbot/conf/live/你的域名]目录下。
注意:以上路径的证书文件为替身,如需将证书用在其他项目上需要在[docker/certbot/conf/archive/你的域名]目录下获取真实证书文件
`privkey.pem` : the private key for your certificate.
`fullchain.pem`: the certificate file used in most server software.
`chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
`cert.pem` : will break many server configurations, and should not be used
without reading further documentation (see link below).
![注意:证书需要定期续期]
A: pnpm install 报错 Cannot find matching keyid: ${JSON.stringify({ signatures, keys })}
Q: 先运行 COREPACK_INTEGRITY_KEYS=0 corepack prepare
再执行 pnpm install
。
- 支持多个会话切换
- 支持运行时用户自定义 Dify API 配置
- 移动端适配
- 消息更新时自动滚动到最底部
- 拆分独立组件库,方便二次开发
- 会话操作
- 支持会话重命名
- 对话参数设置
- 支持修改对话参数
- 消息发送区域功能
- 支持发送图片
- 支持发送其他类型的文件
- 支持打断输出
- 支持语音输入转文字
- 消息内容渲染
- 支持深度思考标签展示(如 DeepSeek-R1 的输出)
- 支持工作流信息展示
- 支持思维链展示
- 支持知识库引用列表展示
- 支持图片展示
- 支持图片放大查看
- 支持
Echarts
渲染 - 支持数学公式渲染
- 支持文件卡片渲染
- 支持
Mermaid
渲染 - 支持图片/视频
- 消息内容交互
- 支持内容复制
- 支持点赞/点踩
- 支持消息文件点击下载
- 支持回复表单展示和提交
- 支持文字转语音
- 支持多应用模式
- Localstorage 实现
- Restful API 实现
- 支持自定义后端服务
- 配置和切换功能分离,支持隐藏配置入口
- 支持单应用模式
- 支持用户在界面上变更配置
- 子包发布
- 发布
@dify-chat/core
包 - 发布
@dify-chat/helpers
包 - 发布
@dify-chat/api
包 - 发布
@dify-chat/components
包
- 发布
- 国际化
- 支持单个会话视图
- 支持消息触顶/触底自动分页加载
- 支持回复重新生成、父级消息
- 支持夜间模式
- 支持自定义主题
- 补充不同类型应用场景的最佳实践
- 容器化部署支持