> 技术文档 > chatwoot 开源客服系统搭建

chatwoot 开源客服系统搭建


1. 准备开源客服系统(我是用的Chatwoot )

可以选择以下开源客服系统作为基础:

  • Chatwoot: 开源,多语言,跟踪和分析,支持多渠道客户对接,自动化和工作流等。源码
  • Zammad: 现代的开源工单系统。
  • FreeScout: 免费且轻量化的 Help Desk 系统。

Chatwoot 移动应用项目常见问题解决方案。


2. 创建 Docker 配置文件

  • 创建chatwoot目录
mkdir chatwootcd chatwoot# 新建docker挂载的子目录mkdir -p ./{postgres,redis,storage}# 给chatwoot目录授权chmod -R 777 chatwoot
  • 在chatwoot目录下创建一个 docker-compose.yml 文件来定义服务:
version: \'3\'services: base: &base image: chatwoot/chatwoot:latest #container_name: chatwoot-base env_file: env.txt ## Change this file for customized env variables volumes: - ./storage:/app/storage rails: <<: *base depends_on: - postgres - redis ports: - 3000:3000 environment: - NODE_ENV=production - RAILS_ENV=production - INSTALLATION_ENV=docker entrypoint: docker/entrypoints/rails.sh command: [\'bundle\', \'exec\', \'rails\', \'s\', \'-p\', \'3000\', \'-b\', \'0.0.0.0\'] sidekiq: <<: *base depends_on: - postgres - redis environment: - NODE_ENV=production - RAILS_ENV=production - INSTALLATION_ENV=docker command: [\'bundle\', \'exec\', \'sidekiq\', \'-C\', \'config/sidekiq.yml\'] postgres: image: postgres:14 container_name: chatwoot-postgres restart: always #ports: # - 5432:5432 volumes: - ./postgres:/var/lib/postgresql/data environment: - POSTGRES_DB=chatwoot - POSTGRES_USER=postgres # Please provide your own password. - POSTGRES_PASSWORD=数据库密码 redis: image: redis:6.2-alpine container_name: chatwoot-redis restart: always command: [\"sh\", \"-c\", \"redis-server --requirepass \\\"$REDIS_PASSWORD\\\"\"] env_file: env.txt volumes: - ./redis:/data #ports: # - 6379:6379# middleware:# build: ./middleware# restart: always# ports:# - \"4000:4000\"# environment:# - CHATWOOT_BOT_TOKEN=你的CHATWOOT机器人token# - CHATWOOT_URL=http://CHATWOOT的ip:3000# - RASA_URL=http://RASA的ip:5005
  • 在chatwoot目录下创建一个 env.txt文件来定义服务配置:
# Learn about the various environment variables at# https://www.chatwoot.com/docs/self-hosted/configuration/environment-variables/#rails-production-variables# Used to verify the integrity of signed cookies. so ensure a secure value is set# SECRET_KEY_BASE should be alphanumeric. Avoid special characters or symbols. # Use `rake secret` to generate this variable# 用于验证签名cookie的完整性。因此,请确保设置了一个安全值!SECRET_KEY_BASE=6eONF6WVhCjbsPMOawORdTF0MccxXgheFvklSzH5ud0=# Replace with the URL you are planning to use for your app# 替换你运行的域名或者IP地址FRONTEND_URL=https://你的ip:3000# To use a dedicated URL for help center pages# HELPCENTER_URL=http://0.0.0.0:3000# If the variable is set, all non-authenticated pages would fallback to the default locale.# Whenever a new account is created, the default language will be DEFAULT_LOCALE instead of en# DEFAULT_LOCALE=en# If you plan to use CDN for your assets, set Asset CDN HostASSET_CDN_HOST=# Force all access to the app over SSL, default is set to falseFORCE_SSL=false# This lets you control new sign ups on your chatwoot installation# true : default option, allows sign ups# false : disables all the end points related to sign ups# api_only: disables the UI for signup, but you can create sign ups via the account apis# 注册选项# true : 允许注册# false : 关闭注册# api_only: 关闭UI上的注册,但可以通过API注册ENABLE_ACCOUNT_SIGNUP=false# Redis config# Redis 配置# specify the configs via single URL or individual variables# ref: https://www.iana.org/assignments/uri-schemes/prov/redis# You can also use the following format for the URL: redis://:password@host:port/db_numberREDIS_URL=redis://redis:6379# If you are using docker-compose, set this variable\'s value to be any string,# which will be the password for the redis service running inside the docker-compose# to make it secure# 设置REDIS的密码,建议复杂一点REDIS_PASSWORD=# Redis Sentinel can be used by passing list of sentinel host and ports e,g. sentinel_host1:port1,sentinel_host2:port2REDIS_SENTINELS=# Redis sentinel master name is required when using sentinel, default value is \"mymaster\".# You can find list of master using \"SENTINEL masters\" commandREDIS_SENTINEL_MASTER_NAME=# By default Chatwoot will pass REDIS_PASSWORD as the password value for sentinels# Use the following environment variable to customize passwords for sentinels.# Use empty string if sentinels are configured with out passwords# REDIS_SENTINEL_PASSWORD=# Redis premium breakage in heroku fix# enable the following configuration# ref: https://github.com/chatwoot/chatwoot/issues/2420# REDIS_OPENSSL_VERIFY_MODE=none# Postgres Database config variables# Postgres Database 配置,密码复杂一点# You can leave POSTGRES_DATABASE blank. The default name of# the database in the production environment is chatwoot_production# POSTGRES_DATABASE=POSTGRES_HOST=postgresPOSTGRES_USERNAME=postgresPOSTGRES_PASSWORD=postgresRAILS_ENV=development# Changes the Postgres query timeout limit. The default is 14 seconds. Modify only when required.# POSTGRES_STATEMENT_TIMEOUT=14sRAILS_MAX_THREADS=5# The email from which all outgoing emails are sent# 下面时SMTP配置,可以用来配置邮件通知。具体配置信息建议到你的邮箱服务商那里查看。# could user either `email@yourdomain.com` or `BrandName `MAILER_SENDER_EMAIL=Chatwoot SMTP_DOMAIN=qq.com# Set the value to \"mailhog\" if using docker-compose for development environments,# Set the value as \"localhost\" or your SMTP address in other environments# If SMTP_ADDRESS is empty, Chatwoot would try to use sendmail(postfix)SMTP_ADDRESS=SMTP_PORT=SMTP_USERNAME=SMTP_PASSWORD=# plain,login,cram_md5SMTP_AUTHENTICATION=loginSMTP_ENABLE_STARTTLS_AUTO=trueSMTP_DEBUG_OUTPUT=true# Can be: \'none\', \'peer\', \'client_once\', \'fail_if_no_peer_cert\', see http://api.rubyonrails.org/classes/ActionMailer/Base.htmlSMTP_OPENSSL_VERIFY_MODE=noneRAILS_MAILER_TIMEOUT=60# Comment out the following environment variables if required by your SMTP server# 如果您的SMTP服务器需要,请注释掉以下环境变量。#SMTP_TLS=false#SMTP_SSL=false# SMTP_OPEN_TIMEOUT# SMTP_READ_TIMEOUT# Mail Incoming# 下面是连续会话使用的邮箱# This is the domain set for the reply emails when conversation continuity is enabledMAILER_INBOUND_EMAIL_DOMAIN=# Set this to the appropriate ingress channel with regards to incoming emails# 将此设置为适当的接收渠道,以接收到电子邮件# 支持的邮箱 :# Possible values are :# relay for Exim, Postfix, Qmail# mailgun for Mailgun# mandrill for Mandrill# postmark for Postmark# sendgrid for SendgridRAILS_INBOUND_EMAIL_SERVICE=# Use one of the following based on the email ingress service# Ref: https://edgeguides.rubyonrails.org/action_mailbox_basics.html# Set this to a password of your choice and use it in the Inbound webhook# 根据电子邮件入口服务,使用以下其中一个# 参考: https://edgeguides.rubyonrails.org/action_mailbox_basics.html# 将其设置为您选择的密码,并在入站webhook中使用它RAILS_INBOUND_EMAIL_PASSWORD=MAILGUN_INGRESS_SIGNING_KEY=MANDRILL_INGRESS_API_KEY=# Creating Your Inbound Webhook Instructions for Postmark and Sendgrid:# Inbound webhook URL format:# https://actionmailbox:[YOUR_RAILS_INBOUND_EMAIL_PASSWORD]@[YOUR_CHATWOOT_DOMAIN.COM]/rails/action_mailbox/[RAILS_INBOUND_EMAIL_SERVICE]/inbound_emails# Note: Replace the values inside the brackets; do not include the brackets themselves.# Example: https://actionmailbox:mYRandomPassword3@chatwoot.example.com/rails/action_mailbox/postmark/inbound_emails# For Postmark# Ensure the \'Include raw email content in JSON payload\' checkbox is selected in the inbound webhook section.# Storage# 存储信息的形式,默认本地ACTIVE_STORAGE_SERVICE=local# Amazon S3# documentation(参考文档): https://www.chatwoot.com/docs/configuring-s3-bucket-as-cloud-storageS3_BUCKET_NAME=AWS_ACCESS_KEY_ID=AWS_SECRET_ACCESS_KEY=AWS_REGION=# Log settings(日志设置)# Disable if you want to write logs to a fileRAILS_LOG_TO_STDOUT=trueLOG_LEVEL=infoLOG_SIZE=500# Configure this environment variable if you want to use lograge instead of rails logger#LOGRAGE_ENABLED=true### This environment variables are only required if you are setting up social media channels# Facebook# documentation: https://www.chatwoot.com/docs/facebook-setupFB_VERIFY_TOKEN=FB_APP_SECRET=FB_APP_ID=# https://developers.facebook.com/docs/messenger-platform/instagram/get-started#app-dashboardIG_VERIFY_TOKEN=# Twitter# documentation: https://www.chatwoot.com/docs/twitter-app-setupTWITTER_APP_ID=TWITTER_CONSUMER_KEY=TWITTER_CONSUMER_SECRET=TWITTER_ENVIRONMENT=#slack integrationSLACK_CLIENT_ID=SLACK_CLIENT_SECRET=# Google OAuthGOOGLE_OAUTH_CLIENT_ID=GOOGLE_OAUTH_CLIENT_SECRET=GOOGLE_OAUTH_CALLBACK_URL=### Change this env variable only if you are using a custom build mobile app## Mobile app env variablesIOS_APP_ID=L7YLMN4634.com.chatwoot.appANDROID_BUNDLE_ID=com.chatwoot.app# https://developers.google.com/android/guides/client-auth (use keytool to print the fingerprint in the first section)ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:D4:5D:D4:53:F8:3B:FB:D3:C6:28:64:1D:AA:08:1E:D8### Smart App Banner# https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html# You can find your app-id in https://itunesconnect.apple.com#IOS_APP_IDENTIFIER=1495796682## Push Notification## generate a new key value here : https://d3v.one/vapid-key-generator/# VAPID_PUBLIC_KEY=# VAPID_PRIVATE_KEY=## for mobile apps# FCM_SERVER_KEY=### APM and Error Monitoring configurations## Elastic APM## https://www.elastic.co/guide/en/apm/agent/ruby/current/getting-started-rails.html# ELASTIC_APM_SERVER_URL=# ELASTIC_APM_SECRET_TOKEN=## Sentry# SENTRY_DSN=## Scout## https://scoutapm.com/docs/ruby/configuration# SCOUT_KEY=YOURKEY# SCOUT_NAME=YOURAPPNAME (Production)# SCOUT_MONITOR=true## NewRelic# https://docs.newrelic.com/docs/agents/ruby-agent/configuration/ruby-agent-configuration/# NEW_RELIC_LICENSE_KEY=# Set this to true to allow newrelic apm to send logs.# This is turned off by default.# NEW_RELIC_APPLICATION_LOGGING_ENABLED=## Datadog## https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#environment-variables# DD_TRACE_AGENT_URL=# MaxMindDB API key to download GeoLite2 City database# IP_LOOKUP_API_KEY=## Rack Attack configuration## To prevent and throttle abusive requests# ENABLE_RACK_ATTACK=true# RACK_ATTACK_LIMIT=300# ENABLE_RACK_ATTACK_WIDGET_API=true## Running chatwoot as an API only server## setting this value to true will disable the frontend dashboard endpoints# CW_API_ONLY_SERVER=false## Development Only Config# if you want to use letter_opener for local emails# LETTER_OPENER=true# meant to be used in github codespaces# WEBPACKER_DEV_SERVER_PUBLIC=# If you want to use official mobile app,# the notifications would be relayed via a Chatwoot serverENABLE_PUSH_RELAY_SERVER=true# Stripe API keySTRIPE_SECRET_KEY=STRIPE_WEBHOOK_SECRET=# Set to true if you want to upload files to cloud storage using the signed url# Make sure to follow https://edgeguides.rubyonrails.org/active_storage_overview.html#cross-origin-resource-sharing-cors-configuration on the cloud storage after setting this to true.DIRECT_UPLOADS_ENABLED=#MS OAUTH credsAZURE_APP_ID=AZURE_APP_SECRET=## Advanced configurations## Change these values to fine tune performance# control the concurrency setting of sidekiq# SIDEKIQ_CONCURRENCY=10# AI powered features## OpenAI key# OPENAI_API_KEY=# Housekeeping/Performance related configurations# Set to true if you want to remove stale contact inboxes# contact_inboxes with no conversation older than 90 days will be removed# REMOVE_STALE_CONTACT_INBOX_JOB_STATUS=false
  • 在env.txt文件中配置好以下参数:
SECRET_KEY_BASE=你的系统令牌ley (可以用命令 openssl rand -base64 32 来生成)FRONTEND_URL=https://你的ip:3000 (前端地址,根据实际情况填写)HELPCENTER_URL=https://你的ip:3000 (帮助中心地址,可以和FRONTEND_URL一样)REDIS_URL=redis://password@redis:6379/1 (redis://:password@host:port/db_number)REDIS_PASSWORD=redis密码POSTGRES_HOST=postgresPOSTGRES_USERNAME=postgresPOSTGRES_PASSWORD=(数据库密码,需与docker-compose.yaml中的postgres数据库密码保持一致)

3. 启动服务

通过运行迁移来准备数据库

# `docker compose` 是新版 cli 命令,如果执行不了,就换成 `docker-compose`
# 即 `docker-compose run --rm rails bundle exec rails db:chatwoot_prepare` 
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
 

ubuntu@ubuntu:~/chatwoot$ docker compose run --rm rails bundle exec rails db:chatwoot_prepare[+] Creating 2/2 ✔ Container chatwoot-postgres-1 Recreated  0.1s.....fatal: not a git repository (or any of the parent directories): .gitCreated database \'chatwoot_production\'ubuntu@ubuntu:~/chatwoot$

当看到 Created database \'chatwoot_production\' 即表示创建成功,继续执行下面的命令


docker-compose down &&  docker-compose up -d


备注:chatwoot-base-1不会运行,显示的是exit状态,不影响使用。

 使用浏览器管理后台访问:http://你的ip:3000/     

 注意事项

  • 第一次进来先要初始化账号信息,设置好系统语言

超级管理员后台:http://你的ip:3000/super_admin

设置中文:Settings --> Account Setting --> Site language ,下拉找到简体中文

创建web收件箱,按照步骤正确填写信息后创建

创建收件箱最后一步,生成 script 代码

将生成的js代码放到你的html中

最后效果


4. 扩展功能

  • 对接邮箱功能(env.txt 文件中配置好以下参数:
# 发送者,格式:“好日子 ” 或 123456789@qq.comMAILER_SENDER_EMAIL=好日子 # SMTP 邮件服务器域名(例:qq.com,gmail.com)SMTP_DOMAIN=cannmax.vip# SMTP 邮件服务器地址(例:qq邮箱:smtp.qq.com,谷歌:smtp.gmail.com)SMTP_ADDRESS=# 587(TLS)或 465(SSL)SMTP_PORT=# 邮箱账号SMTP_USERNAME=# 邮箱密码或授权码(根据邮箱服务器规则去填,例:qq邮箱为邮箱授权码,)SMTP_PASSWORD=# 邮箱服务器SMTP 认证方式,通常为 plain,参数有plain,login,cram_md5SMTP_AUTHENTICATION=login# 是否使用TLS协议发送邮件SMTP_ENABLE_STARTTLS_AUTO=true# 开启debug调式(有些邮箱必须在debug情况下才能使用)SMTP_DEBUG_OUTPUT=true# 是否有ssl校验 Can be: \'none\', \'peer\', \'client_once\', \'fail_if_no_peer_cert\', see SMTP_OPENSSL_VERIFY_MODE=none#发送等待时长RAILS_MAILER_TIMEOUT=60# 如果SMTP服务器需要,则注释掉以下环境变量#SMTP_TLS=false#SMTP_SSL=false

注意:

  • 如果使用 Gmail 或 QQ 邮箱,需要启用“允许低安全性应用访问”或使用授权码而非直接密码。
  • 配置中邮箱和密码需与 SMTP 服务一致。
  • 自定义机器人
        1.生成chatwoot机器人token

方式一:通过超级管理员后台(http://你的ip:3000/super_admin),生成机器人token

 

方式二:通过 Rails控制台创建代理机器人

  • 进入rails容器
 docker exec -it chatwoot-rails-1 sh
  • 启动 rails 控制台
bundle exec rails c
  • 在 Rails 控制台中,输入以下命令来创建代理机器人并获取其访问令牌。保存检索到的令牌(token),因为在调用 chatwoot API 时需要使用它。
# 在驻留bot逻辑时指定url# 如果传参了account_id属性来创建帐户bot,而不是全局botbot = AgentBot.create!(name: \"机器人名\", outgoing_url: \"http://localhost:8000\")bot.access_token.token
  • 为您的机器人添加头像(可选)
avatar_file = Down.download(\"image url 你的头像图片链接\")bot.avatar.attach(io: avatar_file, filename: avatar_file.original_filename, content_type: avatar_file.content_type)
  • 通过运行以下命令将 Agent Bot 连接到您的收件箱
# 取代的收件箱。首先使用Inbox.find(inbox_id)查找特定的收件箱AgentBotInbox.create!(inbox: Inbox.first, agent_bot: bot)
        2.创建智能机器人对话服务系统(我用的是rasa)

部署文件我已经全部压缩,直接运行即可,下面是部署文件下载地址:https://download.csdn.net/download/ko_10086/90192098

注意:

     想更多了解rasa,请百度,我这里就不细讲了。

     我的对话模型仅为测试模型,如需替换成其它模型,将模型下载地址替换,重新运行即可

        4.测试 rasa服务API

使用postman或者Apifox测试

curl -X POST http://你的rasa的Ip:5005/webhooks/rest/webhook \\ -H \"Content-Type: application/json\" \\ -d \'{\"sender\": \"test_user\", \"message\": \"hello\"}\'

预期响应:

[ { \"recipient_id\": \"test_user\", \"text\": \"Hey! How are you?\" }]
        3.rasa与 chatwoot整合对接
  • 在chatwoot目录下创建middleware
  • 在middleware目录下创建一个app.py,来执行rasa与 chatwoot的交互
# middleware/app.pyfrom flask import Flask, request,jsonifyimport requestsimport osapp = Flask(__name__)CHATWOOT_BOT_TOKEN = os.getenv(\"CHATWOOT_BOT_TOKEN\")CHATWOOT_URL = os.getenv(\"CHATWOOT_URL\")RASA_URL = os.getenv(\"RASA_URL\")@app.route(\'/rasa\', methods=[\'POST\'])def rasa(): data = request.get_json() event = data.get(\'event\') if \'message_created\' == event: message_type = data[\'message_type\'] message = data[\'content\'] conversation = data[\'conversation\'][\'id\'] contact = data[\'sender\'][\'id\'] account = data[\'account\'][\'id\'] if (message_type == \"incoming\"): bot_response = send_to_bot(contact, message) create_message = send_to_chatwoot(account, conversation, bot_response) print(create_message) if \'automation_event.message_created\' == event: message = data[\'messages\'][0][\'content\'] conversation = data[\'messages\'][0][\'conversation_id\'] contact = data[\'messages\'][0][\'sender\'][\'id\'] account = data[\'messages\'][0][\'account_id\'] message_type = data[\'messages\'][0][\'message_type\'] if (message_type == 0): bot_response = send_to_bot(contact, message) create_message = send_to_chatwoot(account, conversation, bot_response) print(create_message) return jsonify({\"status\": \"success\"}), 200def send_to_bot(sender, message): data = { \'sender\': sender, \'message\': message } headers = {\"Content-Type\": \"application/json\",  \"Accept\": \"application/json\"} r = requests.post(f\'{RASA_URL}/webhooks/rest/webhook\',json=data, headers=headers) return r.json()[0][\'text\']def send_to_chatwoot(account, conversation, message): data = { \'content\': message } url = f\"{CHATWOOT_URL}/api/v1/accounts/{account}/conversations/{conversation}/messages\" headers = {\"Content-Type\": \"application/json\",  \"Accept\": \"application/json\",  \"api_access_token\": f\"{CHATWOOT_BOT_TOKEN}\"} r = requests.post(url,json=data, headers=headers) return r.json()if __name__ == \'__main__\': app.run(host=\'0.0.0.0\', port=4000)
  • 在middleware目录下创建一个 requirements.txt 文件来导入app.py相关工具
Flaskrequests
  • 在middleware目录下创建一个Dockerfile 文件来构建服务
# middleware/DockerfileFROM python:3.8-slimWORKDIR /appCOPY requirements.txt requirements.txtRUN pip install --no-cache-dir -r requirements.txtRUN pip install --upgrade Jinja2 FlaskCOPY app.py .CMD [\"python\", \"app.py\"]
  • chatwoot目录下的 docker-compose.yml 文件里加上middleware服务(上面已经加上了,取消注释即可),然后运行,如果运行不了,就单写一个docker-compose.yml文件来运行middleware服务
  • 运行命令:docker-compose down &&  docker-compose up -d --build
4.测试智能机器人 
  • chatwoot的收件箱绑定好上面配置好的机器人

  • 在集成方式里面配置rasachatwoot交互的api,并选中对应交互事件

  • 然后去客户端发送消息测试即可,如以下这样

  • 还有一种配置rasachatwoot交互的api的方式,即在Automation配置规则

两种方式都是一样的

  • 队列分析和监控

http://你chatwoot的ip:3000/monitoring/sidekiq