Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. #
  2. # Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. import json
  17. import traceback
  18. from flask import request, Response
  19. from flask_login import login_required, current_user
  20. from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService
  21. from api.settings import RetCode
  22. from api.utils import get_uuid
  23. from api.utils.api_utils import get_json_result, server_error_response, validate_request, get_data_error_result
  24. from agent.canvas import Canvas
  25. from peewee import MySQLDatabase, PostgresqlDatabase
  26. from api.db.db_models import APIToken
  27. @manager.route('/templates', methods=['GET']) # noqa: F821
  28. @login_required
  29. def templates():
  30. return get_json_result(data=[c.to_dict() for c in CanvasTemplateService.get_all()])
  31. @manager.route('/list', methods=['GET']) # noqa: F821
  32. @login_required
  33. def canvas_list():
  34. return get_json_result(data=sorted([c.to_dict() for c in \
  35. UserCanvasService.query(user_id=current_user.id)], key=lambda x: x["update_time"]*-1)
  36. )
  37. @manager.route('/rm', methods=['POST']) # noqa: F821
  38. @validate_request("canvas_ids")
  39. @login_required
  40. def rm():
  41. for i in request.json["canvas_ids"]:
  42. if not UserCanvasService.query(user_id=current_user.id,id=i):
  43. return get_json_result(
  44. data=False, message='Only owner of canvas authorized for this operation.',
  45. code=RetCode.OPERATING_ERROR)
  46. UserCanvasService.delete_by_id(i)
  47. return get_json_result(data=True)
  48. @manager.route('/set', methods=['POST']) # noqa: F821
  49. @validate_request("dsl", "title")
  50. @login_required
  51. def save():
  52. req = request.json
  53. req["user_id"] = current_user.id
  54. if not isinstance(req["dsl"], str):
  55. req["dsl"] = json.dumps(req["dsl"], ensure_ascii=False)
  56. req["dsl"] = json.loads(req["dsl"])
  57. if "id" not in req:
  58. if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip()):
  59. return get_data_error_result(f"{req['title'].strip()} already exists.")
  60. req["id"] = get_uuid()
  61. if not UserCanvasService.save(**req):
  62. return get_data_error_result(message="Fail to save canvas.")
  63. else:
  64. if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
  65. return get_json_result(
  66. data=False, message='Only owner of canvas authorized for this operation.',
  67. code=RetCode.OPERATING_ERROR)
  68. UserCanvasService.update_by_id(req["id"], req)
  69. return get_json_result(data=req)
  70. @manager.route('/get/<canvas_id>', methods=['GET']) # noqa: F821
  71. @login_required
  72. def get(canvas_id):
  73. e, c = UserCanvasService.get_by_id(canvas_id)
  74. if not e:
  75. return get_data_error_result(message="canvas not found.")
  76. return get_json_result(data=c.to_dict())
  77. @manager.route('/getsse/<canvas_id>', methods=['GET']) # type: ignore # noqa: F821
  78. def getsse(canvas_id):
  79. token = request.headers.get('Authorization').split()
  80. if len(token) != 2:
  81. return get_data_error_result(message='Authorization is not valid!"')
  82. token = token[1]
  83. objs = APIToken.query(beta=token)
  84. if not objs:
  85. return get_data_error_result(message='Authentication error: API key is invalid!"')
  86. e, c = UserCanvasService.get_by_id(canvas_id)
  87. if not e:
  88. return get_data_error_result(message="canvas not found.")
  89. return get_json_result(data=c.to_dict())
  90. @manager.route('/completion', methods=['POST']) # noqa: F821
  91. @validate_request("id")
  92. @login_required
  93. def run():
  94. req = request.json
  95. stream = req.get("stream", True)
  96. e, cvs = UserCanvasService.get_by_id(req["id"])
  97. if not e:
  98. return get_data_error_result(message="canvas not found.")
  99. if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
  100. return get_json_result(
  101. data=False, message='Only owner of canvas authorized for this operation.',
  102. code=RetCode.OPERATING_ERROR)
  103. if not isinstance(cvs.dsl, str):
  104. cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False)
  105. final_ans = {"reference": [], "content": ""}
  106. message_id = req.get("message_id", get_uuid())
  107. try:
  108. canvas = Canvas(cvs.dsl, current_user.id)
  109. if "message" in req:
  110. canvas.messages.append({"role": "user", "content": req["message"], "id": message_id})
  111. canvas.add_user_input(req["message"])
  112. except Exception as e:
  113. return server_error_response(e)
  114. if stream:
  115. def sse():
  116. nonlocal answer, cvs
  117. try:
  118. for ans in canvas.run(stream=True):
  119. if ans.get("running_status"):
  120. yield "data:" + json.dumps({"code": 0, "message": "",
  121. "data": {"answer": ans["content"],
  122. "running_status": True}},
  123. ensure_ascii=False) + "\n\n"
  124. continue
  125. for k in ans.keys():
  126. final_ans[k] = ans[k]
  127. ans = {"answer": ans["content"], "reference": ans.get("reference", [])}
  128. yield "data:" + json.dumps({"code": 0, "message": "", "data": ans}, ensure_ascii=False) + "\n\n"
  129. canvas.messages.append({"role": "assistant", "content": final_ans["content"], "id": message_id})
  130. canvas.history.append(("assistant", final_ans["content"]))
  131. if not canvas.path[-1]:
  132. canvas.path.pop(-1)
  133. if final_ans.get("reference"):
  134. canvas.reference.append(final_ans["reference"])
  135. cvs.dsl = json.loads(str(canvas))
  136. UserCanvasService.update_by_id(req["id"], cvs.to_dict())
  137. except Exception as e:
  138. cvs.dsl = json.loads(str(canvas))
  139. if not canvas.path[-1]:
  140. canvas.path.pop(-1)
  141. UserCanvasService.update_by_id(req["id"], cvs.to_dict())
  142. traceback.print_exc()
  143. yield "data:" + json.dumps({"code": 500, "message": str(e),
  144. "data": {"answer": "**ERROR**: " + str(e), "reference": []}},
  145. ensure_ascii=False) + "\n\n"
  146. yield "data:" + json.dumps({"code": 0, "message": "", "data": True}, ensure_ascii=False) + "\n\n"
  147. resp = Response(sse(), mimetype="text/event-stream")
  148. resp.headers.add_header("Cache-control", "no-cache")
  149. resp.headers.add_header("Connection", "keep-alive")
  150. resp.headers.add_header("X-Accel-Buffering", "no")
  151. resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")
  152. return resp
  153. for answer in canvas.run(stream=False):
  154. if answer.get("running_status"):
  155. continue
  156. final_ans["content"] = "\n".join(answer["content"]) if "content" in answer else ""
  157. canvas.messages.append({"role": "assistant", "content": final_ans["content"], "id": message_id})
  158. if final_ans.get("reference"):
  159. canvas.reference.append(final_ans["reference"])
  160. cvs.dsl = json.loads(str(canvas))
  161. UserCanvasService.update_by_id(req["id"], cvs.to_dict())
  162. return get_json_result(data={"answer": final_ans["content"], "reference": final_ans.get("reference", [])})
  163. @manager.route('/reset', methods=['POST']) # noqa: F821
  164. @validate_request("id")
  165. @login_required
  166. def reset():
  167. req = request.json
  168. try:
  169. e, user_canvas = UserCanvasService.get_by_id(req["id"])
  170. if not e:
  171. return get_data_error_result(message="canvas not found.")
  172. if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
  173. return get_json_result(
  174. data=False, message='Only owner of canvas authorized for this operation.',
  175. code=RetCode.OPERATING_ERROR)
  176. canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
  177. canvas.reset()
  178. req["dsl"] = json.loads(str(canvas))
  179. UserCanvasService.update_by_id(req["id"], {"dsl": req["dsl"]})
  180. return get_json_result(data=req["dsl"])
  181. except Exception as e:
  182. return server_error_response(e)
  183. @manager.route('/input_elements', methods=['GET']) # noqa: F821
  184. @login_required
  185. def input_elements():
  186. cvs_id = request.args.get("id")
  187. cpn_id = request.args.get("component_id")
  188. try:
  189. e, user_canvas = UserCanvasService.get_by_id(cvs_id)
  190. if not e:
  191. return get_data_error_result(message="canvas not found.")
  192. if not UserCanvasService.query(user_id=current_user.id, id=cvs_id):
  193. return get_json_result(
  194. data=False, message='Only owner of canvas authorized for this operation.',
  195. code=RetCode.OPERATING_ERROR)
  196. canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
  197. return get_json_result(data=canvas.get_component_input_elements(cpn_id))
  198. except Exception as e:
  199. return server_error_response(e)
  200. @manager.route('/debug', methods=['POST']) # noqa: F821
  201. @validate_request("id", "component_id", "params")
  202. @login_required
  203. def debug():
  204. req = request.json
  205. for p in req["params"]:
  206. assert p.get("key")
  207. try:
  208. e, user_canvas = UserCanvasService.get_by_id(req["id"])
  209. if not e:
  210. return get_data_error_result(message="canvas not found.")
  211. if not UserCanvasService.query(user_id=current_user.id, id=req["id"]):
  212. return get_json_result(
  213. data=False, message='Only owner of canvas authorized for this operation.',
  214. code=RetCode.OPERATING_ERROR)
  215. canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
  216. canvas.get_component(req["component_id"])["obj"]._param.debug_inputs = req["params"]
  217. df = canvas.get_component(req["component_id"])["obj"].debug()
  218. return get_json_result(data=df.to_dict(orient="records"))
  219. except Exception as e:
  220. return server_error_response(e)
  221. @manager.route('/test_db_connect', methods=['POST']) # noqa: F821
  222. @validate_request("db_type", "database", "username", "host", "port", "password")
  223. @login_required
  224. def test_db_connect():
  225. req = request.json
  226. try:
  227. if req["db_type"] in ["mysql", "mariadb"]:
  228. db = MySQLDatabase(req["database"], user=req["username"], host=req["host"], port=req["port"],
  229. password=req["password"])
  230. elif req["db_type"] == 'postgresql':
  231. db = PostgresqlDatabase(req["database"], user=req["username"], host=req["host"], port=req["port"],
  232. password=req["password"])
  233. elif req["db_type"] == 'mssql':
  234. import pyodbc
  235. connection_string = (
  236. f"DRIVER={{ODBC Driver 17 for SQL Server}};"
  237. f"SERVER={req['host']},{req['port']};"
  238. f"DATABASE={req['database']};"
  239. f"UID={req['username']};"
  240. f"PWD={req['password']};"
  241. )
  242. db = pyodbc.connect(connection_string)
  243. cursor = db.cursor()
  244. cursor.execute("SELECT 1")
  245. cursor.close()
  246. else:
  247. return server_error_response("Unsupported database type.")
  248. if req["db_type"] != 'mssql':
  249. db.connect()
  250. db.close()
  251. return get_json_result(data="Database Connection Successful!")
  252. except Exception as e:
  253. return server_error_response(e)