From 465f7e036aa0c62a64230912fb2622aeabbeb3df Mon Sep 17 00:00:00 2001 From: Yongteng Lei Date: Wed, 6 Aug 2025 10:33:52 +0800 Subject: [PATCH] Feat: advanced list dialogs (#9256) ### What problem does this PR solve? Advanced list dialogs ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- api/apps/dialog_app.py | 57 ++++++++++++++++++++++++----- api/db/services/dialog_service.py | 61 +++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 9 deletions(-) diff --git a/api/apps/dialog_app.py b/api/apps/dialog_app.py index add9f595e..4f55381a1 100644 --- a/api/apps/dialog_app.py +++ b/api/apps/dialog_app.py @@ -32,7 +32,8 @@ from api.utils.api_utils import get_json_result @login_required def set_dialog(): req = request.json - dialog_id = req.get("dialog_id") + dialog_id = req.get("dialog_id", "") + is_create = not dialog_id name = req.get("name", "New Dialog") if not isinstance(name, str): return get_data_error_result(message="Dialog name must be string.") @@ -52,15 +53,16 @@ def set_dialog(): llm_setting = req.get("llm_setting", {}) prompt_config = req["prompt_config"] - if not req.get("kb_ids", []) and not prompt_config.get("tavily_api_key") and "{knowledge}" in prompt_config['system']: - return get_data_error_result(message="Please remove `{knowledge}` in system prompt since no knowledge base/Tavily used here.") + if not is_create: + if not req.get("kb_ids", []) and not prompt_config.get("tavily_api_key") and "{knowledge}" in prompt_config['system']: + return get_data_error_result(message="Please remove `{knowledge}` in system prompt since no knowledge base/Tavily used here.") - for p in prompt_config["parameters"]: - if p["optional"]: - continue - if prompt_config["system"].find("{%s}" % p["key"]) < 0: - return get_data_error_result( - message="Parameter '{}' is not used".format(p["key"])) + for p in prompt_config["parameters"]: + if p["optional"]: + continue + if prompt_config["system"].find("{%s}" % p["key"]) < 0: + return get_data_error_result( + message="Parameter '{}' is not used".format(p["key"])) try: e, tenant = TenantService.get_by_id(current_user.id) @@ -153,6 +155,43 @@ def list_dialogs(): return server_error_response(e) +@manager.route('/next', methods=['POST']) # noqa: F821 +@login_required +def list_dialogs_next(): + keywords = request.args.get("keywords", "") + page_number = int(request.args.get("page", 0)) + items_per_page = int(request.args.get("page_size", 0)) + parser_id = request.args.get("parser_id") + orderby = request.args.get("orderby", "create_time") + if request.args.get("desc", "true").lower() == "false": + desc = False + else: + desc = True + + req = request.get_json() + owner_ids = req.get("owner_ids", []) + try: + if not owner_ids: + # tenants = TenantService.get_joined_tenants_by_user_id(current_user.id) + # tenants = [tenant["tenant_id"] for tenant in tenants] + tenants = [] # keep it here + dialogs, total = DialogService.get_by_tenant_ids( + tenants, current_user.id, page_number, + items_per_page, orderby, desc, keywords, parser_id) + else: + tenants = owner_ids + dialogs, total = DialogService.get_by_tenant_ids( + tenants, current_user.id, 0, + 0, orderby, desc, keywords, parser_id) + dialogs = [dialog for dialog in dialogs if dialog["tenant_id"] in tenants] + total = len(dialogs) + if page_number and items_per_page: + dialogs = dialogs[(page_number-1)*items_per_page:page_number*items_per_page] + return get_json_result(data={"dialogs": dialogs, "total": total}) + except Exception as e: + return server_error_response(e) + + @manager.route('/rm', methods=['POST']) # noqa: F821 @login_required @validate_request("dialog_ids") diff --git a/api/db/services/dialog_service.py b/api/db/services/dialog_service.py index faa966c00..5f9371e11 100644 --- a/api/db/services/dialog_service.py +++ b/api/db/services/dialog_service.py @@ -23,6 +23,7 @@ from functools import partial from timeit import default_timer as timer from langfuse import Langfuse +from peewee import fn from agentic_reasoning import DeepResearcher from api import settings @@ -96,6 +97,66 @@ class DialogService(CommonService): return list(chats.dicts()) + @classmethod + @DB.connection_context() + def get_by_tenant_ids(cls, joined_tenant_ids, user_id, page_number, items_per_page, orderby, desc, keywords, parser_id=None): + from api.db.db_models import User + + fields = [ + cls.model.id, + cls.model.tenant_id, + cls.model.name, + cls.model.description, + cls.model.language, + cls.model.llm_id, + cls.model.llm_setting, + cls.model.prompt_type, + cls.model.prompt_config, + cls.model.similarity_threshold, + cls.model.vector_similarity_weight, + cls.model.top_n, + cls.model.top_k, + cls.model.do_refer, + cls.model.rerank_id, + cls.model.kb_ids, + cls.model.status, + User.nickname, + User.avatar.alias("tenant_avatar"), + cls.model.update_time, + cls.model.create_time, + ] + if keywords: + dialogs = ( + cls.model.select(*fields) + .join(User, on=(cls.model.tenant_id == User.id)) + .where( + (cls.model.tenant_id.in_(joined_tenant_ids) | (cls.model.tenant_id == user_id)) & (cls.model.status == StatusEnum.VALID.value), + (fn.LOWER(cls.model.name).contains(keywords.lower())), + ) + ) + else: + dialogs = ( + cls.model.select(*fields) + .join(User, on=(cls.model.tenant_id == User.id)) + .where( + (cls.model.tenant_id.in_(joined_tenant_ids) | (cls.model.tenant_id == user_id)) & (cls.model.status == StatusEnum.VALID.value), + ) + ) + if parser_id: + dialogs = dialogs.where(cls.model.parser_id == parser_id) + if desc: + dialogs = dialogs.order_by(cls.model.getter_by(orderby).desc()) + else: + dialogs = dialogs.order_by(cls.model.getter_by(orderby).asc()) + + count = dialogs.count() + + if page_number and items_per_page: + dialogs = dialogs.paginate(page_number, items_per_page) + + return list(dialogs.dicts()), count + + def chat_solo(dialog, messages, stream=True): if TenantLLMService.llm_id2llm_type(dialog.llm_id) == "image2text": chat_mdl = LLMBundle(dialog.tenant_id, LLMType.IMAGE2TEXT, dialog.llm_id)