coze_bot_api.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. -----------------File Info-----------------------
  5. Name: web.py
  6. Description: web api support
  7. Author: GentleCP
  8. Email: me@gentlecp.com
  9. Create Date: 2021/6/19
  10. -----------------End-----------------------------
  11. """
  12. import re
  13. import time
  14. import sys
  15. from fastapi import FastAPI, Response, Request, BackgroundTasks, Body
  16. from WXBizMsgCrypt3 import WXBizMsgCrypt
  17. from xml.etree.ElementTree import fromstring
  18. import uvicorn
  19. import requests
  20. import json
  21. from commom import get_logger
  22. logger = get_logger()
  23. # 加载配置文件
  24. with open('cqrcb_config.json', 'r') as f:
  25. config = json.load(f)
  26. # 从配置文件中提取参数
  27. token = config['token']
  28. aeskey = config['aeskey']
  29. corpid = config['corpid']
  30. corpsecret = config['corpsecret']
  31. coze_access_token = config['coze_access_token']
  32. bot_id = config['bot_id']
  33. #port = config['port']
  34. # token = "EcSp"#企业微信应用api信息
  35. # aeskey = "OTZoY8N67kOnGosEpS3jw4Rsjea0Gu6D7X4IWxoYKtY"#企业微信应用api信息
  36. # corpid = "ww5541cfeea51e3188"#企业id
  37. # corpsecret = "SbyG25s1LsMsW0nAMiaNprrQIHYrWKQP4f2mNLLDnwE"##api成功后的secret
  38. # coze_access_token = "pat_HNBYQOWE5h4r1tzXi8S2PuY4ddoVRH3DpTbE3NsYBjtcWHTYw5ffrVmKPh26hSLW"#豆包access_token
  39. # bot_id="7397619068440182793"#豆包机器人id
  40. # port = 18090#服务器端口
  41. wxcpt = WXBizMsgCrypt(token, aeskey, corpid)
  42. app = FastAPI()
  43. # def call_llm(prompt: str, bot_id: str,coze_access_token:str):
  44. # req_head = {
  45. # "Authorization":f"Bearer {coze_access_token}",
  46. # "Content-Type": "application/json",
  47. # }
  48. # req_data = {
  49. # "conversation_id": "123",
  50. # "bot_id": bot_id,
  51. # "user": "test",
  52. # "query": prompt,
  53. # "stream": False
  54. # }
  55. # res = requests.post("https://api.coze.cn/open_api/v2/chat", headers=req_head, json=req_data)
  56. # res.raise_for_status() # 检查响应状态码是否为200
  57. # return res.json()
  58. def call_llm(prompt: str, bot_id: str,coze_access_token:str):
  59. req_head = {
  60. "Authorization":f"Bearer {coze_access_token}",
  61. "Content-Type": "application/json",
  62. }
  63. req_data ={
  64. "bot_id": bot_id,
  65. "user_id": "123456789",
  66. "stream": False,
  67. "auto_save_history": True,
  68. "additional_messages": [
  69. {
  70. "role": "user",
  71. "content": prompt,
  72. "content_type": "text"
  73. }
  74. ]
  75. }
  76. res_create = requests.post(" https://api.coze.cn/v1/conversation/create", headers=req_head)
  77. conversation_id = res_create.json()["data"]["id"]
  78. res_chat = requests.post(f" https://api.coze.cn/v3/chat?conversation_id={conversation_id}", headers=req_head,json=req_data)
  79. chat_id = res_chat.json()["data"]["id"]
  80. while True:
  81. res_retrieve = requests.get(f" https://api.coze.cn/v3/chat/retrieve?chat_id={chat_id}&conversation_id={conversation_id}", headers=req_head)
  82. res_json = res_retrieve.json()
  83. # 首先判断网络状态是否为200
  84. if res_retrieve.status_code != 200:
  85. logger.error(f"网络状态码失败,错误码:{res_retrieve.status_code }")
  86. coze_response = f"网络状态码失败,错误码:{res_retrieve.status_code }"
  87. return coze_response
  88. # 判断状态码是否为0
  89. if res_json["code"] != 0 :
  90. logger.error(f"API调用失败,错误码:{res_json['code']}")
  91. coze_response = f"API调用失败,错误码:{res_json['code']}"
  92. return coze_response
  93. # 打印并记录状态
  94. logger.info(res_json["data"]["status"])
  95. status = res_json["data"]["status"]
  96. # 检查是否为错误状态
  97. error_statuses = {"failed", "requires_action", "canceled"}
  98. if status in error_statuses:
  99. error_message = res_json["data"]["last_error"]
  100. logger.error(f"对话错误,状态:{status},错误信息:{error_message}")
  101. coze_response = f"对话错误,状态:{status},错误信息:{error_message}"
  102. return coze_response
  103. # 如果状态为completed,则获取消息
  104. if status == "completed":
  105. res_message = requests.get(f"https://api.coze.cn/v3/chat/message/list?chat_id={chat_id}&conversation_id={conversation_id}", headers=req_head)
  106. coze_response = res_message.json()['data'][1]['content'].replace(" ", "") # v3 删除图片url中的空格
  107. # coze_response = coze_response['data'][1]['content'].replace(" ", "") # v3 删除图片url中的空格
  108. return coze_response
  109. time.sleep(1)
  110. def qiwei_get():
  111. res = requests.get(f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={corpsecret}")
  112. qw_access_token = res.json()["access_token"]
  113. return qw_access_token
  114. def qiwei_post(username: str, answer: str,agentid:str):
  115. req_data = {
  116. "touser": username,
  117. "toparty": "",
  118. "totag": "",
  119. "msgtype": "text",
  120. "agentid": agentid,
  121. "text": {"content": answer},
  122. "image": {
  123. "media_id": "MEDIA_ID"
  124. },
  125. "safe": 0,
  126. "enable_id_trans": 0,
  127. "enable_duplicate_check": 0,
  128. "duplicate_check_interval": 1800
  129. }
  130. res = requests.post(f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={qiwei_get()}", json=req_data)
  131. # print(res.json())
  132. logger.info(res.json())
  133. #return res.json()
  134. def qiwei_post_loading(username: str, answer: str,agentid:str):
  135. req_data = {
  136. "touser": username,
  137. "toparty": "",
  138. "totag": "",
  139. "msgtype": "text",
  140. "agentid": agentid,
  141. "text": {"content": answer},
  142. "image": {
  143. "media_id": "MEDIA_ID"
  144. },
  145. "safe": 0,
  146. "enable_id_trans": 0,
  147. "enable_duplicate_check": 0,
  148. "duplicate_check_interval": 1800
  149. }
  150. res = requests.post(f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={qiwei_get()}", json=req_data)
  151. # print(res.json())
  152. logger.info(res.json())
  153. #return res.json()
  154. #问题传入字节服务器进行回答后发送给企业微信,行内服务器只进行接收然后发给字节,防止网络延迟
  155. def post_consumer_api(user_query, decrypt_data):
  156. data = {
  157. "user_query": user_query,
  158. "decrypt_data": decrypt_data
  159. }
  160. url = "https://101.126.81.2:18088/consumer"
  161. try:
  162. response = requests.post(url, json=data, verify=False) # 忽略SSL证书验证
  163. response.raise_for_status() # 检查响应状态码是否为200
  164. logger.info(f"post_consumer_api 请求成功: {response.json()}")
  165. except requests.exceptions.RequestException as e:
  166. logger.error(f"post_consumer_api 请求失败: {e}")
  167. @app.post("/consumer")
  168. async def consumer(
  169. request: Request
  170. ):
  171. # print(f"请求:{user_query}")
  172. body = await request.body()
  173. body = body.decode()
  174. body = json.loads(body)
  175. user_query = body["user_query"]
  176. decrypt_data = body["decrypt_data"]
  177. username = decrypt_data.get('FromUserName', '')
  178. agentid = decrypt_data.get('AgentID', '')
  179. qiwei_post(username, "正在加载,请稍后...", agentid)
  180. logger.info("正在加载,请稍后...")
  181. logger.info(f"consumer 请求:{user_query}")
  182. # 返回coze结果
  183. coze_response = call_llm(prompt=user_query,bot_id=bot_id,coze_access_token = coze_access_token)
  184. # answer = coze_response['messages'][1]['content']#v2
  185. # answer = coze_response['data'][1]['content'].replace(" ","") #v3 删除图片url中的空格
  186. ##处理图片链接
  187. image_counter = 1
  188. # 定义一个替换函数,用于在替换时添加序号
  189. def replace_with_counter(match):
  190. nonlocal image_counter
  191. alt_text = match.group(1) or f"示例图片{image_counter}"
  192. url = match.group(2)
  193. replacement = f'<a href="{url}">{alt_text}</a>'
  194. image_counter += 1
  195. return replacement
  196. # 将Markdown格式的图片链接转换为HTML格式的文字链接,并添加序号
  197. answer = re.sub(r'!\[(.*?)\]\((https?://[^)]+)\)', replace_with_counter, coze_response)
  198. # print(f"结果:{answer}")
  199. logger.info(f"结果:{answer}")
  200. # 主动发结果给qiwei
  201. qiwei_post(username, answer, agentid)
  202. @app.get("/ok")
  203. async def ok():
  204. return "ok"
  205. @app.get("/bot")
  206. async def verify(msg_signature: str, timestamp: str, nonce: str, echostr: str):
  207. ret, sEchoStr = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr)
  208. if ret == 0:
  209. return Response(content=sEchoStr.decode('utf-8'))
  210. else:
  211. # print(sEchoStr)
  212. logger.info(sEchoStr)
  213. @app.post("/bot")
  214. async def recv(msg_signature: str, timestamp: str, nonce: str, request: Request, background_tasks: BackgroundTasks):
  215. #start_time = time.time()
  216. body = await request.body()
  217. ret, sMsg = wxcpt.DecryptMsg(body.decode('utf-8'), msg_signature, timestamp, nonce)
  218. decrypt_data = {}
  219. for node in list(fromstring(sMsg.decode('utf-8'))):
  220. decrypt_data[node.tag] = node.text
  221. user_query = decrypt_data.get('Content', '')
  222. logger.info(f"start: {user_query}")
  223. background_tasks.add_task(post_consumer_api, user_query, decrypt_data)
  224. # data = {
  225. # "user_query":user_query,
  226. # "decrypt_data":decrypt_data
  227. # }
  228. # requests.post(
  229. # f"https://101.126.81.2:18066/consumer",
  230. # data=data)
  231. return Response(content="")
  232. if __name__ == "__main__":
  233. # coze_response = call_llm(prompt="房快贷是什么",bot_id=bot_id,coze_access_token = coze_access_token)
  234. # print(coze_response)
  235. try:
  236. port = sys.argv[1]
  237. int(port)
  238. except:
  239. port = 18088
  240. logger.info(f'{port=}')
  241. uvicorn.run("coze_bot_api:app", port=port, host='0.0.0.0', reload=False,ssl_keyfile="./key.pem", ssl_certfile="./cert.pem")