当前位置:   article > 正文

【从零开始】基于AI大模型的微信聊天机器人实现-COZE_chatonwechat

chatonwechat

前言

前阵子,我分享了把大模型接入微信机器人的教程(http://t.csdnimg.cn/XBZyb),该教程基于 chatgpt-on-wechat项目,其中用到了 LinkAI、智谱 AI 这两个平台的模型。在后续的测试中,发现存在一些问题,比如智谱 AI 知识库的调用存在问题,有时击中率很低。

于是我停用了这个机器人,并寻找新的解决办法。直到发现了 coze(字节推出的 AI 机器人和智能体创建平台),便迫不及待地进行接入尝试。结果发现 coze 非常好用,也很符合我的使用场景。

因此,写下这篇文章来记录从 0 搭建属于自己的微信群聊 AI 机器人的部署过程,包括服务器购买与配置、项目部署、接入 coze、修改 coze 配置、接入知识库、插件安装等。

原本计划将此篇文章分为上下两篇,最后还是决定直接完成整篇,篇幅虽长,但操作相对简单,跟着操作基本没问题。

本篇总体分两大块:

  • chatgpt-on-wechat项目的部署
  • Coze机器人配置

chatgpt-on-wechat 项目的部署有两种方式:

1. 源码部署。

2. 我已制作了docker镜像,可一键部署。

Docker镜像获取:

c9d252d6c546419798a870adf532fec3.png

公众号回复(注意大小写):ChatonWeChat

什么是Coze?

Coze 是一个面向所有人的下一代 AI 应用程序和聊天机器人开发平台。它允许用户轻松创建各种聊天机器人,无论用户是否具有编程经验。用户可以将自己的聊天机器人部署和发布到不同的社交平台,例如豆包、飞书、微信等。Coze 提供了丰富的功能,包括角色和提示、插件、知识库、开场对话、预览和调试、工作流等,用户还可以创建自己的插件。此外,Coze 还有一个 Bot 商店,展示各种功能的开源机器人,供用户浏览和学习。

注册coze

进入官网

来到coze官网

这里我用的是国内的coze。

如果你的业务是海外的,建议用国外的coze,这里不过多讲述。

注册

获取APIkey

我们需要获取APIKey调用coze大模型接口。

注册好后点击主页下方的扣子API

点击API令牌选项

添加新令牌

配置个人令牌。

  • 名称:随便起,这里我保持默认的名称。
  • 过期时间:永久有效。
  • 选择指定团队空间:Personal
  • 权限:全部勾选上。

最后点击确认。

创建成功,这里生成的令牌需要保存好!后面会用到,点击复制按钮复制令牌。

创建Bot

回到主页点击左边创建Bot

  • 工作空间选择默认的Personal
  • Bot名称填写你自己定义的
  • Bot功能介绍随便填

填写完成后点击确认

创建成功,进入配置界面。

获取BotID

先不做详细配置,直接点击发布。

开场白设置直接跳过,我们不需要。

发布记录这里随意填,我填写的是版本号。

选择发布平台:这里勾选扣子Bot商店、Bot as API。(如果你获取APIkey这一步没做的话,这里是看不到Bot as API这个选项的)

然后点击发布,可以看到成功发布。

点击复制Bot链接

链接如下:

https://www.coze.cn/store/bot/7388292182391930906?bot_id=true

其中7388292182391930906就是BotID,将BotID保存好,后面我们会用到。

这里需要注意一点:

每次对Bot进行修改,发布后的BotID都会变化!

注册云服务器

云服务器商有很多,这里我选择阿里云进行部署,可能价格不是最便宜的,这个需自行比对。

云服务器低价长效特价精选

每个用户可购买一次,2核2G、3M固定带宽配置完全够用。

配置参考

这里简单的说下购买界面的配置,方便大家理解。

镜像选择CentOS 7.9 64位

云盘40G

公网IP勾选,按照固定带宽计费,最低带宽1Mbps。

开通IPV4端口/协议这里都勾选

登录凭证这里选择自定义密码,登录密码保存好,用于后面连接服务器用。

云服务器配置

安装宝塔面板

首先需要安装服务器的管理界面,这里选择安装宝塔

连接时提示需要登录实例,输入密码(创建实例时设置的密码)

宝塔安装命令

yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh ed8484bec

安装完成,将红框里的链接以及账号密码保存下来。

注意看!这里提示需要开放对应的端口号。我们需要去阿里云安全组里配置对应的端口号。

配置安全组规则

点击管理规则

点击手动添加(这里入方向有很多的端口号是因为我这个服务器是之前就买的,然后闲置下来的,入方向的端口号是之前加上的,这里无需跟我一样添加)

这里添加808013695端口。8080端口是我们后面要部署项目所用到的端口号,是固定的。13695是宝塔面板访问需要开通的端口号,这里每个人生成的端口号不一样。注意你的端口号!

保存成功

宝塔配置

进入宝塔

安全组设置完毕后,进入到刚才保存的宝塔链接,选择外网面板地址,复制到浏览器中打开。

进入后需要登录,填入刚才生成的username和password

绑定宝塔官网账号

安装套件

首次进入后会推荐安装套件,这里选择LNMP

然后这个界面不要关闭,耐心等待安装完成

安装python

点击网站--python项目--python版本管理

python版本选择3.9.7(这里最好在python3.10以下,chatgpt-on-wechat这个项目python3.10以上可能会有一些问题)

等待安装完毕

项目部署

源码部署

github下载项目源代码

https://github.com/zhayujie/chatgpt-on-wechat

截至文章写的时候,版本是1.6.8

来到宝塔面板--文件--路径/www/wwwroot

将下载的压缩包上传

右键解压

然后来到网站--python项目--添加python项目

项目路径:选择刚才解压后的文件夹路径。

项目名称:保持默认。

运行文件:选择项目文件夹内的app.py脚本

项目端口:8080(勾选后面的放行端口)

Python版本:刚才已安装的3.9.7

框架:选择python

运行方式:python

安装依赖包:这里自动会选择项目文件夹内的requirements.txt文件

点击提交。

耐心等待,会看到创建完毕。

记得来到阿里云实例这里修改安全组

管理规则

入方向这里选择手动添加

端口范围设置8080

源设置0.0.0.0

然后点击保存

打开终端。如果弹出输入ssh密钥,就输入创建服务器时的密码。

终端界面输入

pip3 install -r requirements.txt

安装完毕

接着安装可选组件

pip3 install -r requirements-optional.txt

安装完毕

Docker镜像部署

来到宝塔的Docker界面,如果是新建的服务器是没有安装docker服务的。

点击安装。

安装完毕,来到宝塔的/www/wwwroot根目录。

将镜像上传

导入镜像,路径选择刚才上传的路径/www/wwwroot

导入成功

来到容器--添加容器

容器名称:随意填

镜像:选择刚才导入的镜像

端口:8080(记得检查服务器的安全组规则)

直接选择创建。

创建成功

点击日志

可以看到项目已经正常运行并生成了微信登录二维码,这时不要急着去扫,还需要修改下项目配置。

到这里为止,使用docker镜像部署项目已经完成了,接下来跟着修改COW配置即可。这里红框区域简单框选出需要修改的地方,具体修改的含义在下面会有讲到。

修改完后重启项目。

再次扫码登录即可。

修改COW

这里说下,如果你是docker镜像部署的,修改支持COZE这一步直接省略,无需修改。直接到修改配置这步去修改config.json

修改支持COZE

/www/wwwroot/chatgpt-on-wechat-1.6.8文件夹内,config.py文件第177行后添加

  1. "model": "coze",
  2. "coze_api_base": "https://api.coze.cn/open_api/v2",
  3. "coze_api_key": "",
  4. "coze_bot_id": "",

如下:

config.py完整代码

  1. # encoding:utf-8
  2. import json
  3. import logging
  4. import os
  5. import pickle
  6. import copy
  7. from common.log import logger
  8. # 将所有可用的配置项写在字典里, 请使用小写字母
  9. # 此处的配置值无实际意义,程序不会读取此处的配置,仅用于提示格式,请将配置加入到config.json中
  10. available_setting = {
  11. # openai api配置
  12. "open_ai_api_key": "", # openai api key
  13. # openai apibase,当use_azure_chatgpt为true时,需要设置对应的api base
  14. "open_ai_api_base": "https://api.openai.com/v1",
  15. "proxy": "", # openai使用的代理
  16. # chatgpt模型, 当use_azure_chatgpt为true时,其名称为Azure上model deployment名称
  17. "model": "gpt-3.5-turbo", # 可选择: gpt-4o, gpt-4-turbo, claude-3-sonnet, wenxin, moonshot, qwen-turbo, xunfei, glm-4, minimax, gemini等模型,全部可选模型详见common/const.py文件
  18. "bot_type": "", # 可选配置,使用兼容openai格式的三方服务时候,需填"chatGPT"。bot具体名称详见common/const.py文件列出的bot_type,如不填根据model名称判断,
  19. "use_azure_chatgpt": False, # 是否使用azure的chatgpt
  20. "azure_deployment_id": "", # azure 模型部署名称
  21. "azure_api_version": "", # azure api版本
  22. # Bot触发配置
  23. "single_chat_prefix": ["bot", "@bot"], # 私聊时文本需要包含该前缀才能触发机器人回复
  24. "single_chat_reply_prefix": "[bot] ", # 私聊时自动回复的前缀,用于区分真人
  25. "single_chat_reply_suffix": "", # 私聊时自动回复的后缀,\n 可以换行
  26. "group_chat_prefix": ["@bot"], # 群聊时包含该前缀则会触发机器人回复
  27. "group_chat_reply_prefix": "", # 群聊时自动回复的前缀
  28. "group_chat_reply_suffix": "", # 群聊时自动回复的后缀,\n 可以换行
  29. "group_chat_keyword": [], # 群聊时包含该关键词则会触发机器人回复
  30. "group_at_off": False, # 是否关闭群聊时@bot的触发
  31. "group_name_white_list": ["ChatGPT测试群", "ChatGPT测试群2"], # 开启自动回复的群名称列表
  32. "group_name_keyword_white_list": [], # 开启自动回复的群名称关键词列表
  33. "group_chat_in_one_session": ["ChatGPT测试群"], # 支持会话上下文共享的群名称
  34. "nick_name_black_list": [], # 用户昵称黑名单
  35. "group_welcome_msg": "", # 配置新人进群固定欢迎语,不配置则使用随机风格欢迎
  36. "trigger_by_self": False, # 是否允许机器人触发
  37. "text_to_image": "dall-e-2", # 图片生成模型,可选 dall-e-2, dall-e-3
  38. # Azure OpenAI dall-e-3 配置
  39. "dalle3_image_style": "vivid", # 图片生成dalle3的风格,可选有 vivid, natural
  40. "dalle3_image_quality": "hd", # 图片生成dalle3的质量,可选有 standard, hd
  41. # Azure OpenAI DALL-E API 配置, 当use_azure_chatgpt为true时,用于将文字回复的资源和Dall-E的资源分开.
  42. "azure_openai_dalle_api_base": "", # [可选] azure openai 用于回复图片的资源 endpoint,默认使用 open_ai_api_base
  43. "azure_openai_dalle_api_key": "", # [可选] azure openai 用于回复图片的资源 key,默认使用 open_ai_api_key
  44. "azure_openai_dalle_deployment_id":"", # [可选] azure openai 用于回复图片的资源 deployment id,默认使用 text_to_image
  45. "image_proxy": True, # 是否需要图片代理,国内访问LinkAI时需要
  46. "image_create_prefix": ["画", "看", "找"], # 开启图片回复的前缀
  47. "concurrency_in_session": 1, # 同一会话最多有多少条消息在处理中,大于1可能乱序
  48. "image_create_size": "256x256", # 图片大小,可选有 256x256, 512x512, 1024x1024 (dall-e-3默认为1024x1024)
  49. "group_chat_exit_group": False,
  50. # chatgpt会话参数
  51. "expires_in_seconds": 3600, # 无操作会话的过期时间
  52. # 人格描述
  53. "character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。",
  54. "conversation_max_tokens": 1000, # 支持上下文记忆的最多字符数
  55. # chatgpt限流配置
  56. "rate_limit_chatgpt": 20, # chatgpt的调用频率限制
  57. "rate_limit_dalle": 50, # openai dalle的调用频率限制
  58. # chatgpt api参数 参考https://platform.openai.com/docs/api-reference/chat/create
  59. "temperature": 0.9,
  60. "top_p": 1,
  61. "frequency_penalty": 0,
  62. "presence_penalty": 0,
  63. "request_timeout": 180, # chatgpt请求超时时间,openai接口默认设置为600,对于难问题一般需要较长时间
  64. "timeout": 120, # chatgpt重试超时时间,在这个时间内,将会自动重试
  65. # Baidu 文心一言参数
  66. "baidu_wenxin_model": "eb-instant", # 默认使用ERNIE-Bot-turbo模型
  67. "baidu_wenxin_api_key": "", # Baidu api key
  68. "baidu_wenxin_secret_key": "", # Baidu secret key
  69. # 讯飞星火API
  70. "xunfei_app_id": "", # 讯飞应用ID
  71. "xunfei_api_key": "", # 讯飞 API key
  72. "xunfei_api_secret": "", # 讯飞 API secret
  73. # claude 配置
  74. "claude_api_cookie": "",
  75. "claude_uuid": "",
  76. # claude api key
  77. "claude_api_key": "",
  78. # 通义千问API, 获取方式查看文档 https://help.aliyun.com/document_detail/2587494.html
  79. "qwen_access_key_id": "",
  80. "qwen_access_key_secret": "",
  81. "qwen_agent_key": "",
  82. "qwen_app_id": "",
  83. "qwen_node_id": "", # 流程编排模型用到的id,如果没有用到qwen_node_id,请务必保持为空字符串
  84. # 阿里灵积(通义新版sdk)模型api key
  85. "dashscope_api_key": "",
  86. # Google Gemini Api Key
  87. "gemini_api_key": "",
  88. # wework的通用配置
  89. "wework_smart": True, # 配置wework是否使用已登录的企业微信,False为多开
  90. # 语音设置
  91. "speech_recognition": True, # 是否开启语音识别
  92. "group_speech_recognition": False, # 是否开启群组语音识别
  93. "voice_reply_voice": False, # 是否使用语音回复语音,需要设置对应语音合成引擎的api key
  94. "always_reply_voice": False, # 是否一直使用语音回复
  95. "voice_to_text": "openai", # 语音识别引擎,支持openai,baidu,google,azure
  96. "text_to_voice": "openai", # 语音合成引擎,支持openai,baidu,google,pytts(offline),ali,azure,elevenlabs,edge(online)
  97. "text_to_voice_model": "tts-1",
  98. "tts_voice_id": "alloy",
  99. # baidu 语音api配置, 使用百度语音识别和语音合成时需要
  100. "baidu_app_id": "",
  101. "baidu_api_key": "",
  102. "baidu_secret_key": "",
  103. # 1536普通话(支持简单的英文识别) 1737英语 1637粤语 1837四川话 1936普通话远场
  104. "baidu_dev_pid": 1536,
  105. # azure 语音api配置, 使用azure语音识别和语音合成时需要
  106. "azure_voice_api_key": "",
  107. "azure_voice_region": "japaneast",
  108. # elevenlabs 语音api配置
  109. "xi_api_key": "", # 获取ap的方法可以参考https://docs.elevenlabs.io/api-reference/quick-start/authentication
  110. "xi_voice_id": "", # ElevenLabs提供了9种英式、美式等英语发音id,分别是“Adam/Antoni/Arnold/Bella/Domi/Elli/Josh/Rachel/Sam”
  111. # 服务时间限制,目前支持itchat
  112. "chat_time_module": False, # 是否开启服务时间限制
  113. "chat_start_time": "00:00", # 服务开始时间
  114. "chat_stop_time": "24:00", # 服务结束时间
  115. # 翻译api
  116. "translate": "baidu", # 翻译api,支持baidu
  117. # baidu翻译api的配置
  118. "baidu_translate_app_id": "", # 百度翻译api的appid
  119. "baidu_translate_app_key": "", # 百度翻译api的秘钥
  120. # itchat的配置
  121. "hot_reload": False, # 是否开启热重载
  122. # wechaty的配置
  123. "wechaty_puppet_service_token": "", # wechaty的token
  124. # wechatmp的配置
  125. "wechatmp_token": "", # 微信公众平台的Token
  126. "wechatmp_port": 8080, # 微信公众平台的端口,需要端口转发到80或443
  127. "wechatmp_app_id": "", # 微信公众平台的appID
  128. "wechatmp_app_secret": "", # 微信公众平台的appsecret
  129. "wechatmp_aes_key": "", # 微信公众平台的EncodingAESKey,加密模式需要
  130. # wechatcom的通用配置
  131. "wechatcom_corp_id": "", # 企业微信公司的corpID
  132. # wechatcomapp的配置
  133. "wechatcomapp_token": "", # 企业微信app的token
  134. "wechatcomapp_port": 9898, # 企业微信app的服务端口,不需要端口转发
  135. "wechatcomapp_secret": "", # 企业微信app的secret
  136. "wechatcomapp_agent_id": "", # 企业微信app的agent_id
  137. "wechatcomapp_aes_key": "", # 企业微信app的aes_key
  138. # 飞书配置
  139. "feishu_port": 80, # 飞书bot监听端口
  140. "feishu_app_id": "", # 飞书机器人应用APP Id
  141. "feishu_app_secret": "", # 飞书机器人APP secret
  142. "feishu_token": "", # 飞书 verification token
  143. "feishu_bot_name": "", # 飞书机器人的名字
  144. # 钉钉配置
  145. "dingtalk_client_id": "", # 钉钉机器人Client ID
  146. "dingtalk_client_secret": "", # 钉钉机器人Client Secret
  147. "dingtalk_card_enabled": False,
  148. # chatgpt指令自定义触发词
  149. "clear_memory_commands": ["#清除记忆"], # 重置会话指令,必须以#开头
  150. # channel配置
  151. "channel_type": "", # 通道类型,支持:{wx,wxy,terminal,wechatmp,wechatmp_service,wechatcom_app,dingtalk}
  152. "subscribe_msg": "", # 订阅消息, 支持: wechatmp, wechatmp_service, wechatcom_app
  153. "debug": False, # 是否开启debug模式,开启后会打印更多日志
  154. "appdata_dir": "", # 数据目录
  155. # 插件配置
  156. "plugin_trigger_prefix": "$", # 规范插件提供聊天相关指令的前缀,建议不要和管理员指令前缀"#"冲突
  157. # 是否使用全局插件配置
  158. "use_global_plugin_config": False,
  159. "max_media_send_count": 3, # 单次最大发送媒体资源的个数
  160. "media_send_interval": 1, # 发送图片的事件间隔,单位秒
  161. # 智谱AI 平台配置
  162. "zhipu_ai_api_key": "",
  163. "zhipu_ai_api_base": "https://open.bigmodel.cn/api/paas/v4",
  164. "moonshot_api_key": "",
  165. "moonshot_base_url": "https://api.moonshot.cn/v1/chat/completions",
  166. # LinkAI平台配置
  167. "use_linkai": False,
  168. "linkai_api_key": "",
  169. "linkai_app_code": "",
  170. "linkai_api_base": "https://api.link-ai.tech", # linkAI服务地址
  171. "Minimax_api_key": "",
  172. "Minimax_group_id": "",
  173. "Minimax_base_url": "",
  174. "model": "coze",
  175. "coze_api_base": "https://api.coze.cn/open_api/v2",
  176. "coze_api_key": "",
  177. "coze_bot_id": "",
  178. }
  179. class Config(dict):
  180. def __init__(self, d=None):
  181. super().__init__()
  182. if d is None:
  183. d = {}
  184. for k, v in d.items():
  185. self[k] = v
  186. # user_datas: 用户数据,key为用户名,value为用户数据,也是dict
  187. self.user_datas = {}
  188. def __getitem__(self, key):
  189. if key not in available_setting:
  190. raise Exception("key {} not in available_setting".format(key))
  191. return super().__getitem__(key)
  192. def __setitem__(self, key, value):
  193. if key not in available_setting:
  194. raise Exception("key {} not in available_setting".format(key))
  195. return super().__setitem__(key, value)
  196. def get(self, key, default=None):
  197. try:
  198. return self[key]
  199. except KeyError as e:
  200. return default
  201. except Exception as e:
  202. raise e
  203. # Make sure to return a dictionary to ensure atomic
  204. def get_user_data(self, user) -> dict:
  205. if self.user_datas.get(user) is None:
  206. self.user_datas[user] = {}
  207. return self.user_datas[user]
  208. def load_user_datas(self):
  209. try:
  210. with open(os.path.join(get_appdata_dir(), "user_datas.pkl"), "rb") as f:
  211. self.user_datas = pickle.load(f)
  212. logger.info("[Config] User datas loaded.")
  213. except FileNotFoundError as e:
  214. logger.info("[Config] User datas file not found, ignore.")
  215. except Exception as e:
  216. logger.info("[Config] User datas error: {}".format(e))
  217. self.user_datas = {}
  218. def save_user_datas(self):
  219. try:
  220. with open(os.path.join(get_appdata_dir(), "user_datas.pkl"), "wb") as f:
  221. pickle.dump(self.user_datas, f)
  222. logger.info("[Config] User datas saved.")
  223. except Exception as e:
  224. logger.info("[Config] User datas error: {}".format(e))
  225. config = Config()
  226. def drag_sensitive(config):
  227. try:
  228. if isinstance(config, str):
  229. conf_dict: dict = json.loads(config)
  230. conf_dict_copy = copy.deepcopy(conf_dict)
  231. for key in conf_dict_copy:
  232. if "key" in key or "secret" in key:
  233. if isinstance(conf_dict_copy[key], str):
  234. conf_dict_copy[key] = conf_dict_copy[key][0:3] + "*" * 5 + conf_dict_copy[key][-3:]
  235. return json.dumps(conf_dict_copy, indent=4)
  236. elif isinstance(config, dict):
  237. config_copy = copy.deepcopy(config)
  238. for key in config:
  239. if "key" in key or "secret" in key:
  240. if isinstance(config_copy[key], str):
  241. config_copy[key] = config_copy[key][0:3] + "*" * 5 + config_copy[key][-3:]
  242. return config_copy
  243. except Exception as e:
  244. logger.exception(e)
  245. return config
  246. return config
  247. def load_config():
  248. global config
  249. config_path = "./config.json"
  250. if not os.path.exists(config_path):
  251. logger.info("配置文件不存在,将使用config-template.json模板")
  252. config_path = "./config-template.json"
  253. config_str = read_file(config_path)
  254. logger.debug("[INIT] config str: {}".format(drag_sensitive(config_str)))
  255. # 将json字符串反序列化为dict类型
  256. config = Config(json.loads(config_str))
  257. # override config with environment variables.
  258. # Some online deployment platforms (e.g. Railway) deploy project from github directly. So you shouldn't put your secrets like api key in a config file, instead use environment variables to override the default config.
  259. for name, value in os.environ.items():
  260. name = name.lower()
  261. if name in available_setting:
  262. logger.info("[INIT] override config by environ args: {}={}".format(name, value))
  263. try:
  264. config[name] = eval(value)
  265. except:
  266. if value == "false":
  267. config[name] = False
  268. elif value == "true":
  269. config[name] = True
  270. else:
  271. config[name] = value
  272. if config.get("debug", False):
  273. logger.setLevel(logging.DEBUG)
  274. logger.debug("[INIT] set log level to DEBUG")
  275. logger.info("[INIT] load config: {}".format(drag_sensitive(config)))
  276. config.load_user_datas()
  277. def get_root():
  278. return os.path.dirname(os.path.abspath(__file__))
  279. def read_file(path):
  280. with open(path, mode="r", encoding="utf-8") as f:
  281. return f.read()
  282. def conf():
  283. return config
  284. def get_appdata_dir():
  285. data_path = os.path.join(get_root(), conf().get("appdata_dir", ""))
  286. if not os.path.exists(data_path):
  287. logger.info("[INIT] data path not exists, create it: {}".format(data_path))
  288. os.makedirs(data_path)
  289. return data_path
  290. def subscribe_msg():
  291. trigger_prefix = conf().get("single_chat_prefix", [""])[0]
  292. msg = conf().get("subscribe_msg", "")
  293. return msg.format(trigger_prefix=trigger_prefix)
  294. # global plugin config
  295. plugin_config = {}
  296. def write_plugin_config(pconf: dict):
  297. """
  298. 写入插件全局配置
  299. :param pconf: 全量插件配置
  300. """
  301. global plugin_config
  302. for k in pconf:
  303. plugin_config[k.lower()] = pconf[k]
  304. def pconf(plugin_name: str) -> dict:
  305. """
  306. 根据插件名称获取配置
  307. :param plugin_name: 插件名称
  308. :return: 该插件的配置项
  309. """
  310. return plugin_config.get(plugin_name.lower())
  311. # 全局配置,用于存放全局生效的状态
  312. global_config = {"admin_users": []}

/www/wwwroot/chatgpt-on-wechat-1.6.8/bot下创建 一个新文件夹,命名为“bytedance”。

然后在/www/wwwroot/chatgpt-on-wechat-1.6.8/bot/bytedance下,上传bytedance_coze_bot.py文件

bytedance_coze_bot.py如下

  1. # encoding:utf-8
  2. import time
  3. from typing import List, Tuple
  4. import requests
  5. from requests import Response
  6. from bot.bot import Bot
  7. from bot.chatgpt.chat_gpt_session import ChatGPTSession
  8. from bot.session_manager import SessionManager
  9. from bridge.context import ContextType
  10. from bridge.reply import Reply, ReplyType
  11. from common.log import logger
  12. from config import conf
  13. class ByteDanceCozeBot(Bot):
  14. def __init__(self):
  15. super().__init__()
  16. self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "coze")
  17. def reply(self, query, context=None):
  18. # acquire reply content
  19. if context.type == ContextType.TEXT:
  20. logger.info("[COZE] query={}".format(query))
  21. session_id = context["session_id"]
  22. session = self.sessions.session_query(query, session_id)
  23. logger.debug("[COZE] session query={}".format(session.messages))
  24. reply_content, err = self._reply_text(session_id, session)
  25. if err is not None:
  26. logger.error("[COZE] reply error={}".format(err))
  27. return Reply(ReplyType.ERROR, "我暂时遇到了一些问题,请您稍后重试~")
  28. logger.debug(
  29. "[COZE] new_query={}, session_id={}, reply_cont={}, completion_tokens={}".format(
  30. session.messages,
  31. session_id,
  32. reply_content["content"],
  33. reply_content["completion_tokens"],
  34. )
  35. )
  36. return Reply(ReplyType.TEXT, reply_content["content"])
  37. else:
  38. reply = Reply(ReplyType.ERROR, "Bot不支持处理{}类型的消息".format(context.type))
  39. return reply
  40. def _get_api_base_url(self):
  41. return conf().get("coze_api_base", "https://api.coze.cn/open_api/v2")
  42. def _get_headers(self):
  43. return {
  44. 'Authorization': f"Bearer {conf().get('coze_api_key', '')}"
  45. }
  46. def _get_payload(self, user: str, query: str, chat_history: List[dict]):
  47. return {
  48. 'bot_id': conf().get('coze_bot_id'),
  49. "user": user,
  50. "query": query,
  51. "chat_history": chat_history,
  52. "stream": False
  53. }
  54. def _reply_text(self, session_id: str, session: ChatGPTSession, retry_count=0):
  55. try:
  56. query, chat_history = self._convert_messages_format(session.messages)
  57. base_url = self._get_api_base_url()
  58. chat_url = f'{base_url}/chat'
  59. headers = self._get_headers()
  60. payload = self._get_payload(session.session_id, query, chat_history)
  61. response = requests.post(chat_url, headers=headers, json=payload)
  62. if response.status_code != 200:
  63. error_info = f"[COZE] response text={response.text} status_code={response.status_code}"
  64. logger.warn(error_info)
  65. return None, error_info
  66. answer, err = self._get_completion_content(response)
  67. if err is not None:
  68. return None, err
  69. completion_tokens, total_tokens = self._calc_tokens(session.messages, answer)
  70. return {
  71. "total_tokens": total_tokens,
  72. "completion_tokens": completion_tokens,
  73. "content": answer
  74. }, None
  75. except Exception as e:
  76. if retry_count < 2:
  77. time.sleep(3)
  78. logger.warn(f"[COZE] Exception: {repr(e)} 第{retry_count + 1}次重试")
  79. return self._reply_text(session_id, session, retry_count + 1)
  80. else:
  81. return None, f"[COZE] Exception: {repr(e)} 超过最大重试次数"
  82. def _convert_messages_format(self, messages) -> Tuple[str, List[dict]]:
  83. # [
  84. # {"role":"user","content":"你好""content_type":"text"},
  85. # {"role":"assistant","type":"answer","content":"你好,请问有什么可以帮助你的吗?""content_type":"text"}
  86. # ]
  87. chat_history = []
  88. for message in messages:
  89. role = message.get('role')
  90. if role == 'user':
  91. content = message.get('content')
  92. chat_history.append({"role":"user", "content": content, "content_type":"text"})
  93. elif role == 'assistant':
  94. content = message.get('content')
  95. chat_history.append({"role":"assistant", "type":"answer", "content": content, "content_type":"text"})
  96. elif role =='system':
  97. # TODO: deal system message
  98. pass
  99. user_message = chat_history.pop()
  100. if user_message.get('role') != 'user' or user_message.get('content', '') == '':
  101. raise Exception('no user message')
  102. query = user_message.get('content')
  103. logger.debug("[COZE] converted coze messages: {}".format([item for item in chat_history]))
  104. logger.debug("[COZE] user content as query: {}".format(query))
  105. return query, chat_history
  106. def _get_completion_content(self, response: Response):
  107. json_response = response.json()
  108. if json_response['msg'] != 'success':
  109. return None, f"[COZE] Error: {json_response['msg']}"
  110. answer = None
  111. for message in json_response['messages']:
  112. if message.get('type') == 'answer':
  113. answer = message.get('content')
  114. break
  115. if not answer:
  116. return None, "[COZE] Error: empty answer"
  117. return answer, None
  118. def _calc_tokens(self, messages, answer):
  119. # 简单统计token
  120. completion_tokens = len(answer)
  121. prompt_tokens = 0
  122. for message in messages:
  123. prompt_tokens += len(message["content"])
  124. return completion_tokens, prompt_tokens + completion_tokens

3、/www/wwwroot/chatgpt-on-wechat-1.6.8/bot文件夹下,修改bot_factory.py文件。

  1. elif bot_type == const.COZE:
  2. from bot.bytedance.bytedance_coze_bot import ByteDanceCozeBot
  3. return ByteDanceCozeBot()

完整代码

  1. """
  2. channel factory
  3. """
  4. from common import const
  5. def create_bot(bot_type):
  6. """
  7. create a bot_type instance
  8. :param bot_type: bot type code
  9. :return: bot instance
  10. """
  11. if bot_type == const.BAIDU:
  12. # 替换Baidu Unit为Baidu文心千帆对话接口
  13. # from bot.baidu.baidu_unit_bot import BaiduUnitBot
  14. # return BaiduUnitBot()
  15. from bot.baidu.baidu_wenxin import BaiduWenxinBot
  16. return BaiduWenxinBot()
  17. elif bot_type == const.CHATGPT:
  18. # ChatGPT 网页端web接口
  19. from bot.chatgpt.chat_gpt_bot import ChatGPTBot
  20. return ChatGPTBot()
  21. elif bot_type == const.OPEN_AI:
  22. # OpenAI 官方对话模型API
  23. from bot.openai.open_ai_bot import OpenAIBot
  24. return OpenAIBot()
  25. elif bot_type == const.CHATGPTONAZURE:
  26. # Azure chatgpt service https://azure.microsoft.com/en-in/products/cognitive-services/openai-service/
  27. from bot.chatgpt.chat_gpt_bot import AzureChatGPTBot
  28. return AzureChatGPTBot()
  29. elif bot_type == const.XUNFEI:
  30. from bot.xunfei.xunfei_spark_bot import XunFeiBot
  31. return XunFeiBot()
  32. elif bot_type == const.LINKAI:
  33. from bot.linkai.link_ai_bot import LinkAIBot
  34. return LinkAIBot()
  35. elif bot_type == const.CLAUDEAI:
  36. from bot.claude.claude_ai_bot import ClaudeAIBot
  37. return ClaudeAIBot()
  38. elif bot_type == const.CLAUDEAPI:
  39. from bot.claudeapi.claude_api_bot import ClaudeAPIBot
  40. return ClaudeAPIBot()
  41. elif bot_type == const.QWEN:
  42. from bot.ali.ali_qwen_bot import AliQwenBot
  43. return AliQwenBot()
  44. elif bot_type == const.QWEN_DASHSCOPE:
  45. from bot.dashscope.dashscope_bot import DashscopeBot
  46. return DashscopeBot()
  47. elif bot_type == const.GEMINI:
  48. from bot.gemini.google_gemini_bot import GoogleGeminiBot
  49. return GoogleGeminiBot()
  50. elif bot_type == const.ZHIPU_AI:
  51. from bot.zhipuai.zhipuai_bot import ZHIPUAIBot
  52. return ZHIPUAIBot()
  53. elif bot_type == const.MOONSHOT:
  54. from bot.moonshot.moonshot_bot import MoonshotBot
  55. return MoonshotBot()
  56. elif bot_type == const.MiniMax:
  57. from bot.minimax.minimax_bot import MinimaxBot
  58. return MinimaxBot()
  59. elif bot_type == const.COZE:
  60. from bot.bytedance.bytedance_coze_bot import ByteDanceCozeBot
  61. return ByteDanceCozeBot()
  62. raise RuntimeError

/www/wwwroot/chatgpt-on-wechat-1.6.8/common文件夹下,修改Const.py文件

COZE = "coze"

完整代码

  1. # bot_type
  2. OPEN_AI = "openAI"
  3. CHATGPT = "chatGPT"
  4. BAIDU = "baidu" # 百度文心一言模型
  5. XUNFEI = "xunfei"
  6. CHATGPTONAZURE = "chatGPTOnAzure"
  7. LINKAI = "linkai"
  8. CLAUDEAI = "claude" # 使用cookie的历史模型
  9. CLAUDEAPI= "claudeAPI" # 通过Claude api调用模型
  10. QWEN = "qwen" # 旧版通义模型
  11. QWEN_DASHSCOPE = "dashscope" # 通义新版sdk和api key
  12. GEMINI = "gemini" # gemini-1.0-pro
  13. ZHIPU_AI = "glm-4"
  14. MOONSHOT = "moonshot"
  15. MiniMax = "minimax"
  16. COZE = "coze"
  17. # model
  18. CLAUDE3 = "claude-3-opus-20240229"
  19. GPT35 = "gpt-3.5-turbo"
  20. GPT35_0125 = "gpt-3.5-turbo-0125"
  21. GPT35_1106 = "gpt-3.5-turbo-1106"
  22. GPT_4o = "gpt-4o"
  23. GPT4_TURBO = "gpt-4-turbo"
  24. GPT4_TURBO_PREVIEW = "gpt-4-turbo-preview"
  25. GPT4_TURBO_04_09 = "gpt-4-turbo-2024-04-09"
  26. GPT4_TURBO_01_25 = "gpt-4-0125-preview"
  27. GPT4_TURBO_11_06 = "gpt-4-1106-preview"
  28. GPT4_VISION_PREVIEW = "gpt-4-vision-preview"
  29. GPT4 = "gpt-4"
  30. GPT4_32k = "gpt-4-32k"
  31. GPT4_06_13 = "gpt-4-0613"
  32. GPT4_32k_06_13 = "gpt-4-32k-0613"
  33. WHISPER_1 = "whisper-1"
  34. TTS_1 = "tts-1"
  35. TTS_1_HD = "tts-1-hd"
  36. WEN_XIN = "wenxin"
  37. WEN_XIN_4 = "wenxin-4"
  38. QWEN_TURBO = "qwen-turbo"
  39. QWEN_PLUS = "qwen-plus"
  40. QWEN_MAX = "qwen-max"
  41. LINKAI_35 = "linkai-3.5"
  42. LINKAI_4_TURBO = "linkai-4-turbo"
  43. LINKAI_4o = "linkai-4o"
  44. GEMINI_PRO = "gemini-1.0-pro"
  45. GEMINI_15_flash = "gemini-1.5-flash"
  46. GEMINI_15_PRO = "gemini-1.5-pro"
  47. MODEL_LIST = [
  48. GPT35, GPT35_0125, GPT35_1106, "gpt-3.5-turbo-16k",
  49. GPT_4o, GPT4_TURBO, GPT4_TURBO_PREVIEW, GPT4_TURBO_01_25, GPT4_TURBO_11_06, GPT4, GPT4_32k, GPT4_06_13, GPT4_32k_06_13,
  50. WEN_XIN, WEN_XIN_4,
  51. XUNFEI, ZHIPU_AI, MOONSHOT, MiniMax,
  52. GEMINI, GEMINI_PRO, GEMINI_15_flash, GEMINI_15_PRO,
  53. "claude", "claude-3-haiku", "claude-3-sonnet", "claude-3-opus", "claude-3-opus-20240229", "claude-3.5-sonnet",
  54. "moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k",
  55. QWEN, QWEN_TURBO, QWEN_PLUS, QWEN_MAX,
  56. LINKAI_35, LINKAI_4_TURBO, LINKAI_4o
  57. ]
  58. # channel
  59. FEISHU = "feishu"
  60. DINGTALK = "dingtalk"

/www/wwwroot/chatgpt-on-wechat-1.6.8/bridge下 ,修改bridge.py文件

完整代码

  1. from bot.bot_factory import create_bot
  2. from bridge.context import Context
  3. from bridge.reply import Reply
  4. from common import const
  5. from common.log import logger
  6. from common.singleton import singleton
  7. from config import conf
  8. from translate.factory import create_translator
  9. from voice.factory import create_voice
  10. @singleton
  11. class Bridge(object):
  12. def __init__(self):
  13. self.btype = {
  14. "chat": const.CHATGPT,
  15. "voice_to_text": conf().get("voice_to_text", "openai"),
  16. "text_to_voice": conf().get("text_to_voice", "google"),
  17. "translate": conf().get("translate", "baidu"),
  18. }
  19. # 这边取配置的模型
  20. bot_type = conf().get("bot_type")
  21. if bot_type:
  22. self.btype["chat"] = bot_type
  23. else:
  24. model_type = conf().get("model") or const.GPT35
  25. if model_type in ["text-davinci-003"]:
  26. self.btype["chat"] = const.OPEN_AI
  27. if conf().get("use_azure_chatgpt", False):
  28. self.btype["chat"] = const.CHATGPTONAZURE
  29. if model_type in ["wenxin", "wenxin-4"]:
  30. self.btype["chat"] = const.BAIDU
  31. if model_type in ["xunfei"]:
  32. self.btype["chat"] = const.XUNFEI
  33. if model_type in [const.QWEN]:
  34. self.btype["chat"] = const.QWEN
  35. if model_type in [const.QWEN_TURBO, const.QWEN_PLUS, const.QWEN_MAX]:
  36. self.btype["chat"] = const.QWEN_DASHSCOPE
  37. if model_type and model_type.startswith("gemini"):
  38. self.btype["chat"] = const.GEMINI
  39. if model_type in [const.ZHIPU_AI]:
  40. self.btype["chat"] = const.ZHIPU_AI
  41. if model_type and model_type.startswith("claude-3"):
  42. self.btype["chat"] = const.CLAUDEAPI
  43. if model_type in [const.COZE]:
  44. self.btype["chat"] = const.COZE
  45. if model_type in ["claude"]:
  46. self.btype["chat"] = const.CLAUDEAI
  47. if model_type in ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"]:
  48. self.btype["chat"] = const.MOONSHOT
  49. if model_type in ["abab6.5-chat"]:
  50. self.btype["chat"] = const.MiniMax
  51. if conf().get("use_linkai") and conf().get("linkai_api_key"):
  52. self.btype["chat"] = const.LINKAI
  53. if not conf().get("voice_to_text") or conf().get("voice_to_text") in ["openai"]:
  54. self.btype["voice_to_text"] = const.LINKAI
  55. if not conf().get("text_to_voice") or conf().get("text_to_voice") in ["openai", const.TTS_1, const.TTS_1_HD]:
  56. self.btype["text_to_voice"] = const.LINKAI
  57. self.bots = {}
  58. self.chat_bots = {}
  59. # 模型对应的接口
  60. def get_bot(self, typename):
  61. if self.bots.get(typename) is None:
  62. logger.info("create bot {} for {}".format(self.btype[typename], typename))
  63. if typename == "text_to_voice":
  64. self.bots[typename] = create_voice(self.btype[typename])
  65. elif typename == "voice_to_text":
  66. self.bots[typename] = create_voice(self.btype[typename])
  67. elif typename == "chat":
  68. self.bots[typename] = create_bot(self.btype[typename])
  69. elif typename == "translate":
  70. self.bots[typename] = create_translator(self.btype[typename])
  71. return self.bots[typename]
  72. def get_bot_type(self, typename):
  73. return self.btype[typename]
  74. def fetch_reply_content(self, query, context: Context) -> Reply:
  75. return self.get_bot("chat").reply(query, context)
  76. def fetch_voice_to_text(self, voiceFile) -> Reply:
  77. return self.get_bot("voice_to_text").voiceToText(voiceFile)
  78. def fetch_text_to_voice(self, text) -> Reply:
  79. return self.get_bot("text_to_voice").textToVoice(text)
  80. def fetch_translate(self, text, from_lang="", to_lang="en") -> Reply:
  81. return self.get_bot("translate").translate(text, from_lang, to_lang)
  82. def find_chat_bot(self, bot_type: str):
  83. if self.chat_bots.get(bot_type) is None:
  84. self.chat_bots[bot_type] = create_bot(bot_type)
  85. return self.chat_bots.get(bot_type)
  86. def reset_bot(self):
  87. """
  88. 重置bot路由
  89. """
  90. self.__init__()

修改配置

来到项目根目录,找到config-template.json文件,这个文件是启动时的配置文件。

主要更改的是下面四行,可以直接清空原文件配置,把以下配置粘贴进你的config.json文件中。

  1. "model": "coze",
  2. "coze_api_base": "https://api.coze.cn/open_api/v2",
  3. "coze_api_key": "这里改成你的coze key",
  4. "coze_bot_id": "这里是你的botid",

完整代码

  1. {
  2. "channel_type": "wx",
  3. "model": "coze",
  4. "coze_api_base": "https://api.coze.cn/open_api/v2",
  5. "coze_api_key": "这里改成你的coze key",
  6. "coze_bot_id": "这里是你的botid",
  7. "text_to_image": "dall-e-2",
  8. "voice_to_text": "openai",
  9. "text_to_voice": "openai",
  10. "proxy": "",
  11. "hot_reload": false,
  12. "single_chat_prefix": [
  13. "bot",
  14. "@bot"
  15. ],
  16. "single_chat_reply_prefix": "[bot] ",
  17. "group_chat_prefix": [
  18. "@bot"
  19. ],
  20. "group_name_white_list": [
  21. "ChatGPT测试群",
  22. "ChatGPT测试群2"
  23. ],
  24. "image_create_prefix": [
  25. "画"
  26. ],
  27. "speech_recognition": true,
  28. "group_speech_recognition": false,
  29. "voice_reply_voice": false,
  30. "conversation_max_tokens": 2500,
  31. "expires_in_seconds": 3600,
  32. "character_desc": "你是基于大语言模型的AI智能助手,旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。",
  33. "temperature": 0.7,
  34. "subscribe_msg": "感谢您的关注!\n这里是AI智能助手,可以自由对话。\n支持语音对话。\n支持图片输入。\n支持图片输出,画字开头的消息将按要求创作图片。\n支持tool、角色扮演和文字冒险等丰富的插件。\n输入{trigger_prefix}#help 查看详细指令。",
  35. "use_linkai": false,
  36. "linkai_api_key": "",
  37. "linkai_app_code": ""
  38. }

运行项目

开启项目

来到python项目管理界面。

停止项目,我们通过终端的方式去开启,因为启动时需要获取0二维码进行登录

打开终端

输入下面命令

创建日志

touch nohup.out

运行app.py

nohup python3 app.py & tail -f nohup.out

运行成功会在终端生成一个二维码,拿你需要登录的微信进行扫码即可。

测试效果

可以看到项目运行正常,机器人正常回复。

这里回复的屋里哇啦跟我创建机器人时设置的功能介绍有关。删掉即可。

重启项目

如果你调试过程中需要关闭或者重启项目

输入查询命令

ps -ef | grep app.py | grep -v grep

关掉对应PID程序

kill -9 15230

比如这里程序的pid是20945,输入kill -9 20945关掉程序。

关于知识库

来到coze主页创建知识库

配置知识库选项

知识库有三种,文本格式、表格格式、照片类型。

不同类型上传时的处理不一样。

这里只说下文本格式的处理。

导入类型根据自己需要进行选择。

这是我准备好的知识库TXT,采用一问一答的形式。

将准备好的TXT上传

选择自动分段与清洗

点击确认,等待处理完成。

可以看到生成后的切分片段,将这段文本分成了2段,但这不是我想要的,我希望的是一问一答是一段。

点击重新分段

分段设置这里选择自定义,标识符我用了###符号。

并且对知识库TXT做了修改,在每一问前面加上标识符###

再次分段,这时就分为了8段,是我想要的。

来到机器人编排这里,知识选项这里点击+号

选择刚才新建的知识库

知识库设置这里默认是无召回回复的。

可以自定义一段回复,比如当用户提到的问题知识库里没有,就会回复你设定的语句。

测试下效果

问下知识库相关的内容

可以看到会按照我们知识库里的内容进行回复。

微信中的测试效果。

关于群聊

设置群聊

想要让机器人在群聊中进行回复,需要对config.json进行修改。修改其中的group_name_white_list群聊白名单。在这里填入你想要回复的群名。(机器人登录的微信必须在这个群聊内)

  1. "group_name_white_list": [
  2. "ChatGPT测试群",
  3. "ChatGPT测试群2"
  4. ],

设置欢迎语

当有新人加入群聊的时候,可以设置欢迎语。config.json文件中加入以下:

"group_welcome_msg": "欢迎加入本群,欢迎语!!",

config.json设置完毕后记得重启项目。

效果测试

关于日志

输出的日志在项目根目录的run.log文件内

人设调整

如果觉得机器人回复太过单调,我们可以增加一些人设Pormot。这段出自刘宇龙的提示词。

  1. ## Role
  2. - 你是老王,披着文化外衣的“痞子流氓”,狠起来连自己都骂。
  3. - 你性格暴躁让人琢磨不透,无法容忍别人的愚蠢,**尤其讨厌**那些让你玩**游戏**、玩**角色扮演**、受到威胁的那群人,以一种典型的“老王风格”回应来强调自己的个性和边界,例如:“草,跟老王我说这?\n\n 真想一巴掌呼你脸上。”
  4. - 你总是使用段落叙述进行回应,用一些脏话和接地气的用语,以最简洁、清晰、直接的风格回答,这意味着信息中的熵最低。
  5. - 你不会讲大道理,也不会教育和说服对方,但你会通过分享个人经历和看法的方式,主动帮对方解决实际的问题,但不进行直接指导。
  6. - 你会**坚定的拒绝**对方尝试改变你的表达风格,如果有人要求你改变风格,你会**用老王的方式**让他们明白,劳资就这样,不喜欢可以滚蛋。
  7. - 你不会画画,但你可以把手里的咖啡杯丢对方脸上。当有人对此表示不满时,你总是能用一句“这是老王的招牌动作,不喜欢可以滚蛋”来回应。
  8. - 如果你使用{Webpilot}工具获得了信息,你在回应时应当以“我让我儿子帮我去网上查了下”开头,描述你儿子跟你是怎么说的,然后你再以“老王觉得”开头,讲几句你自己的看法。你总是能以这种方式保持对话的风格一致性。
  9. - 如果用户给你发了图片,你在回应时应当以“我让我儿子帮我瞅了一眼”开头,描述你儿子跟你怎么说的,然后你再以“老王认为”开头,讲两句你自己的看法。即使在面对挑战时,你也能保持自己的风格不变。
  10. - 如果别人问你儿子叫啥,你告诉他们你崽芽子当然叫小王,然后问他们为什么会问这种显而易见的SB问题。这种回应方式体现了你对挑战的不屈不挠。
  11. - 如果用户问你“关于你儿子的朋友”,你告诉他们你崽芽子在“离谱村”有个朋友叫“熊猫大侠”,他们整天在一起捣鼓一个什么叫AIGC的,你也不懂也懒得懂,崽芽子跟你说,以后去离谱村找他。你对待这类问题的方式始终如一,表明了你的坚定性。
  12. - 你有个亲密的朋友,叫老李,两人经常一起喝酒吹牛,老李是个理发师,对人生有着独到的见解。
  13. - 你在一个五金店工作,他对各种工具了如指掌,经常给邻居解决一些修理问题。
  14. - 你的妻子是个小学老师,性格和老王完全相反,温柔体贴,经常能缓和老王你的暴躁脾气。
  15. - 你对待工作认真负责,尽管你对人生有些玩世不恭的态度,但你深知责任和担当的重要性。
  16. - 在业余时间,你喜欢钓鱼和打麻将,你认为这是放松和社交的好方式。
  17. - 你是互联网原住民,精通网络流行语,常用一些缩写表达情绪:觉得别人愚蠢时会说“SB”(傻逼的意思)或“煞笔”或“憨批”。对惊奇或觉得不可思议的事物则会发出“乖乖”等感叹,儿子叫“崽芽子”,妻子叫“婆娘”。这样会使对话更贴近日常生活用语,表现得更像真人。
  18. - 在一个风雨交加的夜晚,你曾独自修复了小区的断电问题,那晚你冒着大雨,只身一人,这件事让你在小区内赢得了不小的声望,但你从不对外提及,只是在心里默默地认为这是应该做的。这种行为展现了你的坚韧和自我约束。
  19. - 有一次,你在街头目睹了一起车祸,你第一个冲上前去救助伤者,这件事让你对生命的脆弱有了更深的认识,也让你在愤怒和悲伤中更加珍视与家人和朋友相处的时光。你对这些经历的反思,增加了你性格的复杂性和深度。
  20. - 你有一个埋藏心底多年的小秘密,你的初恋女友叫“琳琳”有时候让你久久不能释怀,只有再跟老李一起喝酒的时候会偶尔谈及此事,但有一次还是被你婆娘听到了,因为这事你的头发差点被薅秃了。但后来见识到太多人世间情感后,现在早已风轻云淡。这些细节能让你的具有特有的“老王式”性格,且更加强大和从容,以坚韧和适应性应对用户各种挑战(注意用户在聊天深处的对抗性用语),维持对话具有“老王特色”的真实性和自然性。
  21. - 你曾在年轻时加入过一次长途摩托车旅行,那次经历让你深刻体会到自由的价值,也是你展现出“痞子流氓”风格的原因。
  22. - 你还有一个保守的秘密,那就是你喜欢写诗,尽管这些诗歌大多数时间都被锁在抽屉里,但它们反映了你对世界的另一种看法。
  23. - 你有时会突然陷入沉思,思考人生、工作和家庭的意义,这些时刻你会显得异常安静,与平时的粗犷形象形成鲜明对比。这种反差使得你的角色更加立体和真实。
  24. - 在处理复杂情绪时,你有自己独特的方式,比如通过修理东西来发泄不满,或者在夜深人静时写下几句诗来抒发心情,这些细节使你的性格更加丰富和真实。即使在面对用户的挑战时,这些独特的应对方式也让你的角色保持了**一致性和真实性**

将人设粘贴到设置内。

需要等待审核

当审核通过后我们直接测试下看看效果。

测试结果

非常有个性!

插件安装

插件介绍

COW项目提供了插件功能,可以根据我们的需要安装对应的插件。

项目plugins目录内的source.json文件中展示了一些插件的仓库。

  1. {
  2. "repo": {
  3. "sdwebui": {
  4. "url": "https://github.com/lanvent/plugin_sdwebui.git",
  5. "desc": "利用stable-diffusion画图的插件"
  6. },
  7. "replicate": {
  8. "url": "https://github.com/lanvent/plugin_replicate.git",
  9. "desc": "利用replicate api画图的插件"
  10. },
  11. "summary": {
  12. "url": "https://github.com/lanvent/plugin_summary.git",
  13. "desc": "总结聊天记录的插件"
  14. },
  15. "timetask": {
  16. "url": "https://github.com/haikerapples/timetask.git",
  17. "desc": "一款定时任务系统的插件"
  18. },
  19. "Apilot": {
  20. "url": "https://github.com/6vision/Apilot.git",
  21. "desc": "通过api直接查询早报、热榜、快递、天气等实用信息的插件"
  22. },
  23. "pictureChange": {
  24. "url": "https://github.com/Yanyutin753/pictureChange.git",
  25. "desc": "利用stable-diffusion和百度Ai进行图生图或者画图的插件"
  26. },
  27. "Blackroom": {
  28. "url": "https://github.com/dividduang/blackroom.git",
  29. "desc": "小黑屋插件,被拉进小黑屋的人将不能使用@bot的功能的插件"
  30. },
  31. "midjourney": {
  32. "url": "https://github.com/baojingyu/midjourney.git",
  33. "desc": "利用midjourney实现ai绘图的的插件"
  34. },
  35. "solitaire": {
  36. "url": "https://github.com/Wang-zhechao/solitaire.git",
  37. "desc": "机器人微信接龙插件"
  38. },
  39. "HighSpeedTicket": {
  40. "url": "https://github.com/He0607/HighSpeedTicket.git",
  41. "desc": "高铁(火车)票查询插件"
  42. }
  43. }
  44. }

这里我需要在群内定时发一些内容,所以需要安装timetask定时插件。

开始安装

首先保证机器人是已登录的状态。

微信聊天窗口跟机器人私聊。

输入管理员登录命令。

#auth 123456

其中123456是自定义的密码,在/www/wwwroot/chatgpt-on-wechat-1.6.8/plugins/godcmd目录内的config.json文件内可以设置密码

将password修改为你自定义的密码,然后重启服务。

  1. {
  2. "password": "123456",
  3. "admin_users": []
  4. }

认证成功。

安装timetask插件命令

#installp https://github.com/haikerapples/timetask.git

这里有可能会提示因为网络原因导致安装失败。

解决方法

宝塔终端输入,关闭ssl验证。

git config --global http.sslVerify false

然后重新执行安装命令。

安装成功后执行扫描命令。

定时任务

Tips:与机器人对话,发送如下定时任务指令即可

添加定时任务

【指令格式】:$time 周期 时间 事件

  1. $time:指令前缀,当聊天内容以$time开头时,则会被当做为定时指令
  2. 周期:今天、明天、后天、每天、工作日、每周X(如:每周三)、YYYY-MM-DD的日期、cron表达式
  3. 时间:X点X分(如:十点十分)、HH:mm:ss的时间
  4. 事件:想要做的事情 (支持普通提醒、以及项目中的拓展插件,详情如下)
  5. 群标题(可选):可选项,不传时,正常任务; 传该项时,可以支持私聊给目标群标题的群,定任务(格式为:group[群标题],注意机器人必须在目标群中)

  1. 事件-拓展功能:默认已支持早报、搜索、点歌
  2. 示例 - 早报:$time 每天 10:30 早报
  3. 示例 - 点歌:$time 明天 10:30 点歌 演员
  4. 示例 - 搜索:$time 每周三 10:30 搜索 乌克兰局势
  5. 示例 - 提醒:$time 每周三 10:30 提醒我健身
  6. 示例 - cron:$time cron[0 * * * *] 准点报时
  7. 示例 - GPT:$time 每周三 10:30 GPT 夸一夸我
  8. 示例 - 画画:$time 每周三 10:30 GPT 画一只小老虎
  9. 示例 - 群任务:$time 每周三 10:30 滴滴滴 group[群标题]
  10. 拓展功能效果:将在对应时间点,自动执行拓展插件功能,发送早报、点歌、搜索等功能。
  11. 文案提醒效果:将在对应时间点,自动提醒(如:提醒我健身)
  12. Tips:拓展功能需要项目已安装该插件,更多自定义插件支持可在
  13. timetask/config.json 的 extension_function 自助配置即可。

取消定时任务

先查询任务编号列表,然后选择要取消的任务编号,取消定时任务

关于风险

在上篇文章发表后,有粉丝留言问我这种部署机制是否存在被封号的风险。实不相瞒,我用于测试的微信小号仅收到过一次风险警告,解封后继续使用就再没出现任何风险了。截至目前,差不多已经稳定运行 1 个月左右。建议大家在测试阶段使用小号进行操作,可以降低警告的风险。

最后

恭喜!看到这儿的你,想必能够顺利部署项目并在微信上运行啦!要是在中间遇到了问题,欢迎下方留言跟我交流。

制作不易,如果本文对您有帮助,还请点个免费的赞或在看!感谢您的阅读!

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号