process_request.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. package process
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/eryajf/chatgpt-dingtalk/pkg/db"
  6. "github.com/eryajf/chatgpt-dingtalk/pkg/dingbot"
  7. "github.com/eryajf/chatgpt-dingtalk/pkg/logger"
  8. "github.com/eryajf/chatgpt-dingtalk/public"
  9. "github.com/solywsh/chatgpt"
  10. )
  11. // ProcessRequest 分析处理请求逻辑
  12. func ProcessRequest(rmsg *dingbot.ReceiveMsg) error {
  13. if CheckRequestTimes(rmsg) {
  14. content := strings.TrimSpace(rmsg.Text.Content)
  15. switch content {
  16. case "单聊":
  17. public.UserService.SetUserMode(rmsg.GetSenderIdentifier(), content)
  18. _, err := rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("=====现在进入与👉%s👈单聊的模式 =====", rmsg.SenderNick))
  19. if err != nil {
  20. logger.Warning(fmt.Errorf("send message error: %v", err))
  21. }
  22. case "串聊":
  23. public.UserService.SetUserMode(rmsg.GetSenderIdentifier(), content)
  24. _, err := rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("=====现在进入与👉%s👈串聊的模式 =====", rmsg.SenderNick))
  25. if err != nil {
  26. logger.Warning(fmt.Errorf("send message error: %v", err))
  27. }
  28. case "重置":
  29. // 重置用户对话模式
  30. public.UserService.ClearUserMode(rmsg.GetSenderIdentifier())
  31. // 清空用户对话上下文
  32. public.UserService.ClearUserSessionContext(rmsg.GetSenderIdentifier())
  33. // 清空用户对话的答案ID
  34. public.UserService.ClearAnswerID(rmsg.SenderNick, rmsg.GetChatTitle())
  35. _, err := rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("=====已重置与👉%s👈的对话模式,可以开始新的对话=====", rmsg.SenderNick))
  36. if err != nil {
  37. logger.Warning(fmt.Errorf("send message error: %v", err))
  38. }
  39. case "模板":
  40. var title string
  41. for _, v := range *public.Prompt {
  42. title = title + v.Title + " | "
  43. }
  44. _, err := rmsg.ReplyToDingtalk(string(dingbot.MARKDOWN), fmt.Sprintf("%s 您好,当前程序内置集成了这些提示词:\n\n-----\n\n| %s \n\n-----\n\n您可以选择某个提示词作为对话内容的开头。\n\n以周报为例,可发送\"#周报 我本周用Go写了一个钉钉集成ChatGPT的聊天应用\",可将工作内容填充为一篇完整的周报。\n\n-----\n\n若您不清楚某个提示词的所代表的含义,您可以直接发送提示词,例如直接发送\"#周报\"", rmsg.SenderNick, title))
  45. if err != nil {
  46. logger.Warning(fmt.Errorf("send message error: %v", err))
  47. }
  48. case "图片":
  49. if public.Config.AzureOn {
  50. _, err := rmsg.ReplyToDingtalk(string(dingbot.
  51. MARKDOWN), "azure 模式下暂不支持图片创作功能")
  52. if err != nil {
  53. logger.Warning(fmt.Errorf("send message error: %v", err))
  54. }
  55. return err
  56. }
  57. _, err := rmsg.ReplyToDingtalk(string(dingbot.MARKDOWN), "发送以 **#图片** 开头的内容,将会触发绘画能力,图片生成之后,将会保存在程序根目录下的 **images目录** \n 如果你绘图没有思路,可以在这两个网站寻找灵感。\n - [https://lexica.art/](https://lexica.art/)\n- [https://www.clickprompt.org/zh-CN/](https://www.clickprompt.org/zh-CN/)")
  58. if err != nil {
  59. logger.Warning(fmt.Errorf("send message error: %v", err))
  60. }
  61. case "余额":
  62. cacheMsg := public.UserService.GetUserMode("system_balance")
  63. if cacheMsg == "" {
  64. rst, err := public.GetBalance()
  65. if err != nil {
  66. logger.Warning(fmt.Errorf("get balance error: %v", err))
  67. return err
  68. }
  69. cacheMsg = rst
  70. }
  71. // cacheMsg := "官方暂时改写了余额接口,因此暂不提供查询余额功能!2023-04-03"
  72. _, err := rmsg.ReplyToDingtalk(string(dingbot.TEXT), cacheMsg)
  73. if err != nil {
  74. logger.Warning(fmt.Errorf("send message error: %v", err))
  75. }
  76. case "查对话":
  77. msg := "使用如下指令进行查询:\n\n---\n\n**#查对话 username:张三**\n\n---\n\n需要注意格式必须严格与上边一致,否则将会查询失败\n\n只有程序系统管理员有权限查询,即config.yml中的admin_users指定的人员。"
  78. _, err := rmsg.ReplyToDingtalk(string(dingbot.MARKDOWN), msg)
  79. if err != nil {
  80. logger.Warning(fmt.Errorf("send message error: %v", err))
  81. }
  82. default:
  83. if public.FirstCheck(rmsg) {
  84. return Do("串聊", rmsg)
  85. } else {
  86. return Do("单聊", rmsg)
  87. }
  88. }
  89. }
  90. return nil
  91. }
  92. // 执行处理请求
  93. func Do(mode string, rmsg *dingbot.ReceiveMsg) error {
  94. // 先把模式注入
  95. public.UserService.SetUserMode(rmsg.GetSenderIdentifier(), mode)
  96. switch mode {
  97. case "单聊":
  98. qObj := db.Chat{
  99. Username: rmsg.SenderNick,
  100. Source: rmsg.GetChatTitle(),
  101. ChatType: db.Q,
  102. ParentContent: 0,
  103. Content: rmsg.Text.Content,
  104. }
  105. qid, err := qObj.Add()
  106. if err != nil {
  107. logger.Error("往MySQL新增数据失败,错误信息:", err)
  108. }
  109. reply, err := chatgpt.SingleQa(rmsg.Text.Content, rmsg.GetSenderIdentifier())
  110. if err != nil {
  111. logger.Info(fmt.Errorf("gpt request error: %v", err))
  112. if strings.Contains(fmt.Sprintf("%v", err), "maximum text length exceeded") {
  113. public.UserService.ClearUserSessionContext(rmsg.GetSenderIdentifier())
  114. _, err = rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("请求openai失败了,错误信息:%v,看起来是超过最大对话限制了,已自动重置您的对话,现在您可以继续提问了。", err))
  115. if err != nil {
  116. logger.Warning(fmt.Errorf("send message error: %v", err))
  117. return err
  118. }
  119. } else {
  120. _, err = rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("请求openai失败了,错误信息:%v", err))
  121. if err != nil {
  122. logger.Warning(fmt.Errorf("send message error: %v", err))
  123. return err
  124. }
  125. }
  126. }
  127. if reply == "" {
  128. logger.Warning(fmt.Errorf("get gpt result falied: %v", err))
  129. return nil
  130. } else {
  131. reply = strings.TrimSpace(reply)
  132. reply = strings.Trim(reply, "\n")
  133. aObj := db.Chat{
  134. Username: rmsg.SenderNick,
  135. Source: rmsg.GetChatTitle(),
  136. ChatType: db.A,
  137. ParentContent: qid,
  138. Content: reply,
  139. }
  140. _, err := aObj.Add()
  141. if err != nil {
  142. logger.Error("往MySQL新增数据失败,错误信息:", err)
  143. }
  144. logger.Info(fmt.Sprintf("🤖 %s得到的答案: %#v", rmsg.SenderNick, reply))
  145. // 回复@我的用户
  146. _, err = rmsg.ReplyToDingtalk(string(dingbot.TEXT), reply)
  147. if err != nil {
  148. logger.Warning(fmt.Errorf("send message error: %v", err))
  149. return err
  150. }
  151. }
  152. case "串聊":
  153. lastAid := public.UserService.GetAnswerID(rmsg.SenderNick, rmsg.GetChatTitle())
  154. qObj := db.Chat{
  155. Username: rmsg.SenderNick,
  156. Source: rmsg.GetChatTitle(),
  157. ChatType: db.Q,
  158. ParentContent: lastAid,
  159. Content: rmsg.Text.Content,
  160. }
  161. qid, err := qObj.Add()
  162. if err != nil {
  163. logger.Error("往MySQL新增数据失败,错误信息:", err)
  164. }
  165. cli, reply, err := chatgpt.ContextQa(rmsg.Text.Content, rmsg.GetSenderIdentifier())
  166. if err != nil {
  167. logger.Info(fmt.Sprintf("gpt request error: %v", err))
  168. if strings.Contains(fmt.Sprintf("%v", err), "maximum text length exceeded") {
  169. public.UserService.ClearUserSessionContext(rmsg.GetSenderIdentifier())
  170. _, err = rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("请求openai失败了,错误信息:%v,看起来是超过最大对话限制了,已自动重置您的对话,现在您可以继续提问了。", err))
  171. if err != nil {
  172. logger.Warning(fmt.Errorf("send message error: %v", err))
  173. return err
  174. }
  175. } else {
  176. _, err = rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("请求openai失败了,错误信息:%v", err))
  177. if err != nil {
  178. logger.Warning(fmt.Errorf("send message error: %v", err))
  179. return err
  180. }
  181. }
  182. }
  183. if reply == "" {
  184. logger.Warning(fmt.Errorf("get gpt result falied: %v", err))
  185. return nil
  186. } else {
  187. reply = strings.TrimSpace(reply)
  188. reply = strings.Trim(reply, "\n")
  189. aObj := db.Chat{
  190. Username: rmsg.SenderNick,
  191. Source: rmsg.GetChatTitle(),
  192. ChatType: db.A,
  193. ParentContent: qid,
  194. Content: reply,
  195. }
  196. aid, err := aObj.Add()
  197. if err != nil {
  198. logger.Error("往MySQL新增数据失败,错误信息:", err)
  199. }
  200. // 将当前回答的ID放入缓存
  201. public.UserService.SetAnswerID(rmsg.SenderNick, rmsg.GetChatTitle(), aid)
  202. logger.Info(fmt.Sprintf("🤖 %s得到的答案: %#v", rmsg.SenderNick, reply))
  203. // 回复@我的用户
  204. _, err = rmsg.ReplyToDingtalk(string(dingbot.TEXT), reply)
  205. if err != nil {
  206. logger.Warning(fmt.Errorf("send message error: %v", err))
  207. return err
  208. }
  209. _ = cli.ChatContext.SaveConversation(rmsg.GetSenderIdentifier())
  210. }
  211. default:
  212. }
  213. return nil
  214. }
  215. // CheckRequestTimes 分析处理请求逻辑
  216. // 主要提供单日请求限额的功能
  217. func CheckRequestTimes(rmsg *dingbot.ReceiveMsg) bool {
  218. if public.Config.MaxRequest == 0 {
  219. return true
  220. }
  221. count := public.UserService.GetUseRequestCount(rmsg.GetSenderIdentifier())
  222. // 判断访问次数是否超过限制
  223. if count >= public.Config.MaxRequest {
  224. logger.Info(fmt.Sprintf("亲爱的: %s,您今日请求次数已达上限,请明天再来,交互发问资源有限,请务必斟酌您的问题,给您带来不便,敬请谅解!", rmsg.SenderNick))
  225. _, err := rmsg.ReplyToDingtalk(string(dingbot.TEXT), fmt.Sprintf("一个好的问题,胜过十个好的答案!\n亲爱的: %s,您今日请求次数已达上限,请明天再来,交互发问资源有限,请务必斟酌您的问题,给您带来不便,敬请谅解!", rmsg.SenderNick))
  226. if err != nil {
  227. logger.Warning(fmt.Errorf("send message error: %v", err))
  228. }
  229. return false
  230. }
  231. // 访问次数未超过限制,将计数加1
  232. public.UserService.SetUseRequestCount(rmsg.GetSenderIdentifier(), count+1)
  233. return true
  234. }