| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 | 
							- #
 - #  Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
 - #
 - #  Licensed under the Apache License, Version 2.0 (the "License");
 - #  you may not use this file except in compliance with the License.
 - #  You may obtain a copy of the License at
 - #
 - #      http://www.apache.org/licenses/LICENSE-2.0
 - #
 - #  Unless required by applicable law or agreed to in writing, software
 - #  distributed under the License is distributed on an "AS IS" BASIS,
 - #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 - #  See the License for the specific language governing permissions and
 - #  limitations under the License.
 - #
 - import json
 - import logging
 - import re
 - import sys
 - from functools import partial
 - 
 - import trio
 - from flask import request, Response
 - from flask_login import login_required, current_user
 - 
 - from agent.component import LLM
 - from api.db import FileType
 - from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService, API4ConversationService
 - from api.db.services.document_service import DocumentService
 - from api.db.services.file_service import FileService
 - from api.db.services.user_service import TenantService
 - from api.db.services.user_canvas_version import UserCanvasVersionService
 - from api.settings import RetCode
 - from api.utils import get_uuid
 - from api.utils.api_utils import get_json_result, server_error_response, validate_request, get_data_error_result
 - from agent.canvas import Canvas
 - from peewee import MySQLDatabase, PostgresqlDatabase
 - from api.db.db_models import APIToken
 - import time
 - 
 - from api.utils.file_utils import filename_type, read_potential_broken_pdf
 - from rag.utils.redis_conn import REDIS_CONN
 - 
 - 
 - @manager.route('/templates', methods=['GET'])  # noqa: F821
 - @login_required
 - def templates():
 -     return get_json_result(data=[c.to_dict() for c in CanvasTemplateService.get_all()])
 - 
 - 
 - @manager.route('/list', methods=['GET'])  # noqa: F821
 - @login_required
 - def canvas_list():
 -     return get_json_result(data=sorted([c.to_dict() for c in \
 -                                  UserCanvasService.query(user_id=current_user.id)], key=lambda x: x["update_time"]*-1)
 -                            )
 - 
 - 
 - @manager.route('/rm', methods=['POST'])  # noqa: F821
 - @validate_request("canvas_ids")
 - @login_required
 - def rm():
 -     for i in request.json["canvas_ids"]:
 -         if not UserCanvasService.accessible(i, current_user.id):
 -             return get_json_result(
 -                 data=False, message='Only owner of canvas authorized for this operation.',
 -                 code=RetCode.OPERATING_ERROR)
 -         UserCanvasService.delete_by_id(i)
 -     return get_json_result(data=True)
 - 
 - 
 - @manager.route('/set', methods=['POST'])  # noqa: F821
 - @validate_request("dsl", "title")
 - @login_required
 - def save():
 -     req = request.json
 -     req["user_id"] = current_user.id
 -     if not isinstance(req["dsl"], str):
 -         req["dsl"] = json.dumps(req["dsl"], ensure_ascii=False)
 -     req["dsl"] = json.loads(req["dsl"])
 -     if "id" not in req:
 -         if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip()):
 -             return get_data_error_result(message=f"{req['title'].strip()} already exists.")
 -         req["id"] = get_uuid()
 -         if not UserCanvasService.save(**req):
 -             return get_data_error_result(message="Fail to save canvas.")
 -     else:
 -         if not UserCanvasService.accessible(req["id"], current_user.id):
 -             return get_json_result(
 -                 data=False, message='Only owner of canvas authorized for this operation.',
 -                 code=RetCode.OPERATING_ERROR)
 -         UserCanvasService.update_by_id(req["id"], req)
 -     # save version
 -     UserCanvasVersionService.insert( user_canvas_id=req["id"], dsl=req["dsl"], title="{0}_{1}".format(req["title"], time.strftime("%Y_%m_%d_%H_%M_%S")))
 -     UserCanvasVersionService.delete_all_versions(req["id"])
 -     return get_json_result(data=req)
 - 
 - 
 - @manager.route('/get/<canvas_id>', methods=['GET'])  # noqa: F821
 - @login_required
 - def get(canvas_id):
 -     if not UserCanvasService.accessible(canvas_id, current_user.id):
 -         return get_data_error_result(message="canvas not found.")
 -     e, c = UserCanvasService.get_by_tenant_id(canvas_id)
 -     return get_json_result(data=c)
 - 
 - 
 - @manager.route('/getsse/<canvas_id>', methods=['GET'])  # type: ignore # noqa: F821
 - def getsse(canvas_id):
 -     token = request.headers.get('Authorization').split()
 -     if len(token) != 2:
 -         return get_data_error_result(message='Authorization is not valid!"')
 -     token = token[1]
 -     objs = APIToken.query(beta=token)
 -     if not objs:
 -         return get_data_error_result(message='Authentication error: API key is invalid!"')
 -     tenant_id = objs[0].tenant_id
 -     e, c = UserCanvasService.get_by_id(canvas_id)
 -     if not e or c.user_id != tenant_id:
 -         return get_data_error_result(message="canvas not found.")
 -     return get_json_result(data=c.to_dict())
 - 
 - 
 - @manager.route('/completion', methods=['POST'])  # noqa: F821
 - @validate_request("id")
 - @login_required
 - def run():
 -     req = request.json
 -     query = req.get("query", "")
 -     files = req.get("files", [])
 -     inputs = req.get("inputs", {})
 -     user_id = req.get("user_id", current_user.id)
 -     if not UserCanvasService.accessible(req["id"], current_user.id):
 -         return get_json_result(
 -             data=False, message='Only owner of canvas authorized for this operation.',
 -             code=RetCode.OPERATING_ERROR)
 - 
 -     e, cvs = UserCanvasService.get_by_id(req["id"])
 -     if not e:
 -         return get_data_error_result(message="canvas not found.")
 - 
 -     if not isinstance(cvs.dsl, str):
 -         cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False)
 - 
 -     try:
 -         canvas = Canvas(cvs.dsl, current_user.id, req["id"])
 -     except Exception as e:
 -         return server_error_response(e)
 - 
 -     def sse():
 -         nonlocal canvas, user_id
 -         try:
 -             for ans in canvas.run(query=query, files=files, user_id=user_id, inputs=inputs):
 -                 yield "data:" + json.dumps(ans, ensure_ascii=False) + "\n\n"
 - 
 -             cvs.dsl = json.loads(str(canvas))
 -             UserCanvasService.update_by_id(req["id"], cvs.to_dict())
 -         except Exception as e:
 -             logging.exception(e)
 -             yield "data:" + json.dumps({"code": 500, "message": str(e), "data": False}, ensure_ascii=False) + "\n\n"
 - 
 -     resp = Response(sse(), mimetype="text/event-stream")
 -     resp.headers.add_header("Cache-control", "no-cache")
 -     resp.headers.add_header("Connection", "keep-alive")
 -     resp.headers.add_header("X-Accel-Buffering", "no")
 -     resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")
 -     return resp
 - 
 - 
 - @manager.route('/reset', methods=['POST'])  # noqa: F821
 - @validate_request("id")
 - @login_required
 - def reset():
 -     req = request.json
 -     if not UserCanvasService.accessible(req["id"], current_user.id):
 -         return get_json_result(
 -             data=False, message='Only owner of canvas authorized for this operation.',
 -             code=RetCode.OPERATING_ERROR)
 -     try:
 -         e, user_canvas = UserCanvasService.get_by_id(req["id"])
 -         if not e:
 -             return get_data_error_result(message="canvas not found.")
 - 
 -         canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
 -         canvas.reset()
 -         req["dsl"] = json.loads(str(canvas))
 -         UserCanvasService.update_by_id(req["id"], {"dsl": req["dsl"]})
 -         return get_json_result(data=req["dsl"])
 -     except Exception as e:
 -         return server_error_response(e)
 - 
 - 
 - @manager.route("/upload/<canvas_id>", methods=["POST"])  # noqa: F821
 - def upload(canvas_id):
 -     e, cvs = UserCanvasService.get_by_tenant_id(canvas_id)
 -     if not e:
 -         return get_data_error_result(message="canvas not found.")
 - 
 -     user_id = cvs["user_id"]
 -     def structured(filename, filetype, blob, content_type):
 -         nonlocal user_id
 -         if filetype == FileType.PDF.value:
 -             blob = read_potential_broken_pdf(blob)
 - 
 -         location = get_uuid()
 -         FileService.put_blob(user_id, location, blob)
 - 
 -         return {
 -             "id": location,
 -             "name": filename,
 -             "size": sys.getsizeof(blob),
 -             "extension": filename.split(".")[-1].lower(),
 -             "mime_type": content_type,
 -             "created_by": user_id,
 -             "created_at": time.time(),
 -             "preview_url": None
 -         }
 - 
 -     if request.args.get("url"):
 -         from crawl4ai import (
 -             AsyncWebCrawler,
 -             BrowserConfig,
 -             CrawlerRunConfig,
 -             DefaultMarkdownGenerator,
 -             PruningContentFilter,
 -             CrawlResult
 -         )
 -         try:
 -             url = request.args.get("url")
 -             filename = re.sub(r"\?.*", "", url.split("/")[-1])
 -             async def adownload():
 -                 browser_config = BrowserConfig(
 -                     headless=True,
 -                     verbose=False,
 -                 )
 -                 async with AsyncWebCrawler(config=browser_config) as crawler:
 -                     crawler_config = CrawlerRunConfig(
 -                         markdown_generator=DefaultMarkdownGenerator(
 -                             content_filter=PruningContentFilter()
 -                         ),
 -                         pdf=True,
 -                         screenshot=False
 -                     )
 -                     result: CrawlResult = await crawler.arun(
 -                         url=url,
 -                         config=crawler_config
 -                     )
 -                     return result
 -             page = trio.run(adownload())
 -             if page.pdf:
 -                 if filename.split(".")[-1].lower() != "pdf":
 -                     filename += ".pdf"
 -                 return get_json_result(data=structured(filename, "pdf", page.pdf, page.response_headers["content-type"]))
 - 
 -             return get_json_result(data=structured(filename, "html", str(page.markdown).encode("utf-8"), page.response_headers["content-type"], user_id))
 - 
 -         except Exception as e:
 -             return  server_error_response(e)
 - 
 -     file = request.files['file']
 -     try:
 -         DocumentService.check_doc_health(user_id, file.filename)
 -         return get_json_result(data=structured(file.filename, filename_type(file.filename), file.read(), file.content_type))
 -     except Exception as e:
 -         return  server_error_response(e)
 - 
 - 
 - @manager.route('/input_form', methods=['GET'])  # noqa: F821
 - @login_required
 - def input_form():
 -     cvs_id = request.args.get("id")
 -     cpn_id = request.args.get("component_id")
 -     try:
 -         e, user_canvas = UserCanvasService.get_by_id(cvs_id)
 -         if not e:
 -             return get_data_error_result(message="canvas not found.")
 -         if not UserCanvasService.query(user_id=current_user.id, id=cvs_id):
 -             return get_json_result(
 -                 data=False, message='Only owner of canvas authorized for this operation.',
 -                 code=RetCode.OPERATING_ERROR)
 - 
 -         canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
 -         return get_json_result(data=canvas.get_component_input_form(cpn_id))
 -     except Exception as e:
 -         return server_error_response(e)
 - 
 - 
 - @manager.route('/debug', methods=['POST'])  # noqa: F821
 - @validate_request("id", "component_id", "params")
 - @login_required
 - def debug():
 -     req = request.json
 -     if not UserCanvasService.accessible(req["id"], current_user.id):
 -         return get_json_result(
 -             data=False, message='Only owner of canvas authorized for this operation.',
 -             code=RetCode.OPERATING_ERROR)
 -     try:
 -         e, user_canvas = UserCanvasService.get_by_id(req["id"])
 -         canvas = Canvas(json.dumps(user_canvas.dsl), current_user.id)
 -         canvas.reset()
 -         canvas.message_id = get_uuid()
 -         component = canvas.get_component(req["component_id"])["obj"]
 -         component.reset()
 - 
 -         if isinstance(component, LLM):
 -             component.set_debug_inputs(req["params"])
 -         component.invoke(**{k: o["value"] for k,o in req["params"].items()})
 -         outputs = component.output()
 -         for k in outputs.keys():
 -             if isinstance(outputs[k], partial):
 -                 txt = ""
 -                 for c in outputs[k]():
 -                     txt += c
 -                 outputs[k] = txt
 -         return get_json_result(data=outputs)
 -     except Exception as e:
 -         return server_error_response(e)
 - 
 - 
 - @manager.route('/test_db_connect', methods=['POST'])  # noqa: F821
 - @validate_request("db_type", "database", "username", "host", "port", "password")
 - @login_required
 - def test_db_connect():
 -     req = request.json
 -     try:
 -         if req["db_type"] in ["mysql", "mariadb"]:
 -             db = MySQLDatabase(req["database"], user=req["username"], host=req["host"], port=req["port"],
 -                                password=req["password"])
 -         elif req["db_type"] == 'postgresql':
 -             db = PostgresqlDatabase(req["database"], user=req["username"], host=req["host"], port=req["port"],
 -                                     password=req["password"])
 -         elif req["db_type"] == 'mssql':
 -             import pyodbc
 -             connection_string = (
 -                 f"DRIVER={{ODBC Driver 17 for SQL Server}};"
 -                 f"SERVER={req['host']},{req['port']};"
 -                 f"DATABASE={req['database']};"
 -                 f"UID={req['username']};"
 -                 f"PWD={req['password']};"
 -             )
 -             db = pyodbc.connect(connection_string)
 -             cursor = db.cursor()
 -             cursor.execute("SELECT 1")
 -             cursor.close()
 -         else:
 -             return server_error_response("Unsupported database type.")
 -         if req["db_type"] != 'mssql':
 -             db.connect()
 -         db.close()
 - 
 -         return get_json_result(data="Database Connection Successful!")
 -     except Exception as e:
 -         return server_error_response(e)
 - 
 - 
 - #api get list version dsl of canvas
 - @manager.route('/getlistversion/<canvas_id>', methods=['GET'])  # noqa: F821
 - @login_required
 - def getlistversion(canvas_id):
 -     try:
 -         list =sorted([c.to_dict() for c in UserCanvasVersionService.list_by_canvas_id(canvas_id)], key=lambda x: x["update_time"]*-1)
 -         return get_json_result(data=list)
 -     except Exception as e:
 -         return get_data_error_result(message=f"Error getting history files: {e}")
 - 
 - 
 - #api get version dsl of canvas
 - @manager.route('/getversion/<version_id>', methods=['GET'])  # noqa: F821
 - @login_required
 - def getversion( version_id):
 -     try:
 - 
 -         e, version = UserCanvasVersionService.get_by_id(version_id)
 -         if version:
 -             return get_json_result(data=version.to_dict())
 -     except Exception as e:
 -         return get_json_result(data=f"Error getting history file: {e}")
 - 
 - 
 - @manager.route('/listteam', methods=['GET'])  # noqa: F821
 - @login_required
 - def list_canvas():
 -     keywords = request.args.get("keywords", "")
 -     page_number = int(request.args.get("page", 1))
 -     items_per_page = int(request.args.get("page_size", 150))
 -     orderby = request.args.get("orderby", "create_time")
 -     desc = request.args.get("desc", True)
 -     try:
 -         tenants = TenantService.get_joined_tenants_by_user_id(current_user.id)
 -         canvas, total = UserCanvasService.get_by_tenant_ids(
 -             [m["tenant_id"] for m in tenants], current_user.id, page_number,
 -             items_per_page, orderby, desc, keywords)
 -         return get_json_result(data={"canvas": canvas, "total": total})
 -     except Exception as e:
 -         return server_error_response(e)
 - 
 - 
 - @manager.route('/setting', methods=['POST'])  # noqa: F821
 - @validate_request("id", "title", "permission")
 - @login_required
 - def setting():
 -     req = request.json
 -     req["user_id"] = current_user.id
 - 
 -     if not UserCanvasService.accessible(req["id"], current_user.id):
 -         return get_json_result(
 -             data=False, message='Only owner of canvas authorized for this operation.',
 -             code=RetCode.OPERATING_ERROR)
 - 
 -     e,flow = UserCanvasService.get_by_id(req["id"])
 -     if not e:
 -         return get_data_error_result(message="canvas not found.")
 -     flow = flow.to_dict()
 -     flow["title"] = req["title"]
 -     if req["description"]:
 -         flow["description"] = req["description"]
 -     if req["permission"]:
 -         flow["permission"] = req["permission"]
 -     if req["avatar"]:
 -         flow["avatar"] = req["avatar"]
 - 
 -     num= UserCanvasService.update_by_id(req["id"], flow)
 -     return get_json_result(data=num)
 - 
 - 
 - @manager.route('/trace', methods=['GET'])  # noqa: F821
 - def trace():
 -     cvs_id = request.args.get("canvas_id")
 -     msg_id = request.args.get("message_id")
 -     try:
 -         bin = REDIS_CONN.get(f"{cvs_id}-{msg_id}-logs")
 -         if not bin:
 -             return get_json_result(data={})
 - 
 -         return get_json_result(data=json.loads(bin.encode("utf-8")))
 -     except Exception as e:
 -         logging.exception(e)
 - 
 - 
 - @manager.route('/<canvas_id>/sessions', methods=['GET'])  # noqa: F821
 - @login_required
 - def sessions(canvas_id):
 -     tenant_id = current_user.id
 -     if not UserCanvasService.accessible(canvas_id, tenant_id):
 -         return get_json_result(
 -             data=False, message='Only owner of canvas authorized for this operation.',
 -             code=RetCode.OPERATING_ERROR)
 - 
 -     user_id = request.args.get("user_id")
 -     page_number = int(request.args.get("page", 1))
 -     items_per_page = int(request.args.get("page_size", 30))
 -     keywords = request.args.get("keywords")
 -     from_date = request.args.get("from_date")
 -     to_date = request.args.get("to_date")
 -     orderby = request.args.get("orderby", "update_time")
 -     if request.args.get("desc") == "False" or request.args.get("desc") == "false":
 -         desc = False
 -     else:
 -         desc = True
 -     # dsl defaults to True in all cases except for False and false
 -     include_dsl = request.args.get("dsl") != "False" and request.args.get("dsl") != "false"
 -     total, sess = API4ConversationService.get_list(canvas_id, tenant_id, page_number, items_per_page, orderby, desc,
 -                                              None, user_id, include_dsl, keywords, from_date, to_date)
 -     try:
 -         return get_json_result(data={"total": total, "sessions": sess})
 -     except Exception as e:
 -         return server_error_response(e)
 
 
  |