Refine knownledge compilation REST APIs (#17624)

This commit is contained in:
Wang Qi
2026-07-31 17:05:57 +08:00
committed by GitHub
parent 03b7b04e2c
commit 9db2e2314a
8 changed files with 76 additions and 93 deletions

View File

@@ -25,7 +25,7 @@ from api.utils.api_utils import get_json_result, server_error_response
_validate_template_payload = validate_template_payload
@manager.route("/compilation_templates/builtins", methods=["GET"]) # noqa: F821
@manager.route("/compilation-templates/builtins", methods=["GET"]) # noqa: F821
@login_required
def list_builtin_templates() -> Response:
"""Built-in template palette — used as the per-child pre-fill in the
@@ -54,7 +54,7 @@ def list_builtin_templates() -> Response:
return server_error_response(exc)
@manager.route("/compilation_templates/wiki_presets", methods=["GET"]) # noqa: F821
@manager.route("/compilation-templates/wiki-presets", methods=["GET"]) # noqa: F821
@login_required
def list_wiki_presets() -> Response:
"""Wiki page-structure presets loaded from

View File

@@ -66,7 +66,7 @@ def _validate_group_payload(req: dict, require_all: bool = True) -> str:
return ""
@manager.route("/compilation_template_groups", methods=["GET"]) # noqa: F821
@manager.route("/compilation-template-groups", methods=["GET"]) # noqa: F821
@login_required
def list_groups() -> Response:
keywords = request.args.get("keywords", "")
@@ -86,7 +86,7 @@ def list_groups() -> Response:
return server_error_response(exc)
@manager.route("/compilation_template_groups/<group_id>", methods=["GET"]) # noqa: F821
@manager.route("/compilation-template-groups/<group_id>", methods=["GET"]) # noqa: F821
@login_required
def detail(group_id: str) -> Response:
try:
@@ -98,7 +98,7 @@ def detail(group_id: str) -> Response:
return server_error_response(exc)
@manager.route("/compilation_template_groups", methods=["POST"]) # noqa: F821
@manager.route("/compilation-template-groups", methods=["POST"]) # noqa: F821
@login_required
@validate_request("name", "templates")
async def create() -> Response:
@@ -125,7 +125,7 @@ async def create() -> Response:
return server_error_response(exc)
@manager.route("/compilation_template_groups/<group_id>", methods=["PUT"]) # noqa: F821
@manager.route("/compilation-template-groups/<group_id>", methods=["PUT"]) # noqa: F821
@login_required
async def update(group_id: str) -> Response:
req = await get_request_json()
@@ -160,7 +160,7 @@ async def update(group_id: str) -> Response:
return server_error_response(exc)
@manager.route("/compilation_template_groups/<group_id>", methods=["DELETE"]) # noqa: F821
@manager.route("/compilation-template-groups/<group_id>", methods=["DELETE"]) # noqa: F821
@login_required
def delete(group_id: str) -> Response:
try:

View File

@@ -16,7 +16,7 @@
import logging
from peewee import OperationalError
from quart import request
from quart import request, make_response
from common.constants import RetCode
from api.apps import login_required, current_user
from api.utils.api_utils import get_error_argument_result, get_error_data_result, get_json_result, get_result, add_tenant_id_to_kwargs
@@ -578,22 +578,19 @@ async def get_knowledge_graph(tenant_id, dataset_id):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/any_artifact", methods=["GET"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/artifacts", methods=["HEAD"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def has_any_wiki(tenant_id, dataset_id):
"""Probe whether this dataset has any compiled artifact pages.
GET /api/v1/datasets/<dataset_id>/any_artifact
Success: {"code": 0, "data": {"has": bool}}
The frontend uses this to decide whether to surface the Artifact tab
in the dataset sidebar.
"""
try:
success, result = await dataset_api_service.has_any_wiki(dataset_id, tenant_id)
if success:
return get_result(data=result)
return get_result(data=False, message=result, code=RetCode.AUTHENTICATION_ERROR)
response = await make_response("", 200 if success and result["has"] else 404)
return response
except Exception as e:
logging.exception(e)
return get_error_data_result(message="Internal server error")
@@ -633,13 +630,13 @@ async def list_wiki_pages(tenant_id, dataset_id):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/artifacts_topics", methods=["GET"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/artifacts/topics", methods=["GET"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def list_wiki_topics(tenant_id, dataset_id):
"""List wiki topics for the dataset Artifact tab.
GET /api/v1/datasets/<dataset_id>/artifacts_topics?page=1&page_size=200
GET /api/v1/datasets/<dataset_id>/artifacts/topics?page=1&page_size=200
Success: {"code": 0, "data": {"total": int, "items": [{topic, title, slug}]}}
"""
try:
@@ -708,13 +705,13 @@ async def get_wiki_graph(tenant_id, dataset_id):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/artifacts_structure", methods=["GET"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/artifacts/structure", methods=["GET"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def get_dataset_structure(tenant_id, dataset_id):
"""Return the dataset-scope (KB-wide) structure graph for one kind.
GET /api/v1/datasets/<dataset_id>/artifacts_structure?kind=<kind>
GET /api/v1/datasets/<dataset_id>/artifacts/structure?kind=<kind>
where ``kind`` is one of:
graph | mindmap | timeline | session_essence | session_graph
@@ -755,13 +752,13 @@ async def get_dataset_structure(tenant_id, dataset_id):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/artifacts_structure", methods=["DELETE"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/artifacts/structure", methods=["DELETE"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
def delete_dataset_structure(tenant_id, dataset_id):
"""Delete the dataset-scope (KB-wide) structure graph for one kind.
DELETE /api/v1/datasets/<dataset_id>/artifacts_structure?kind=<kind>
DELETE /api/v1/datasets/<dataset_id>/artifacts/structure?kind=<kind>
Optional query param: wipe=false cancels the task without deleting stored rows.
"""
kind = request.args.get("kind", "")
@@ -874,20 +871,15 @@ async def get_wiki_page(tenant_id, dataset_id, page_type, slug):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/any_skill", methods=["GET"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/skills", methods=["HEAD"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def has_any_skill(tenant_id, dataset_id):
"""Probe whether this dataset has a compiled Corpus2Skill tree.
GET /api/v1/datasets/<dataset_id>/any_skill
Success: {"code": 0, "data": {"has": bool}}
"""
"""Probe whether this dataset has a compiled Corpus2Skill tree."""
try:
success, result = await dataset_api_service.has_any_skill(dataset_id, tenant_id)
if success:
return get_result(data=result)
return get_result(data=False, message=result, code=RetCode.AUTHENTICATION_ERROR)
response = await make_response("", 200 if success and result["has"] else 404)
return response
except Exception as e:
logging.exception(e)
return get_error_data_result(message="Internal server error")
@@ -960,13 +952,13 @@ async def get_skill_page(tenant_id, dataset_id, skill_kwd):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/nav", methods=["GET"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/navigation", methods=["GET"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def list_dataset_nav(tenant_id, dataset_id):
"""First level of the dataset navigation tree — the top-level clusters.
GET /api/v1/datasets/<dataset_id>/nav
GET /api/v1/datasets/<dataset_id>/navigation
Success: {"code": 0, "data": {"total": <n>, "items": [{name, description, doc_count, type, has_children}, ...]}}
"""
try:
@@ -982,13 +974,13 @@ async def list_dataset_nav(tenant_id, dataset_id):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/nav/<path:name>/children", methods=["GET"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/navigation/<path:name>/children", methods=["GET"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def list_dataset_nav_children(tenant_id, dataset_id, name):
"""Direct children of a navigation node (hierarchical, one level per call).
GET /api/v1/datasets/<dataset_id>/nav/<name>/children
GET /api/v1/datasets/<dataset_id>/navigation/<name>/children
Success: {"code": 0, "data": {"total": <n>, "items": [{name, description, doc_count, type, doc_id, has_children}, ...]}}
"""
try:
@@ -1005,13 +997,13 @@ async def list_dataset_nav_children(tenant_id, dataset_id, name):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/nav", methods=["DELETE"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/navigation", methods=["DELETE"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def delete_dataset_nav(tenant_id, dataset_id):
"""Delete the entire dataset navigation tree.
DELETE /api/v1/datasets/<dataset_id>/nav
DELETE /api/v1/datasets/<dataset_id>/navigation
Success: {"code": 0, "data": {"deleted": <n>}}
"""
try:
@@ -1027,13 +1019,13 @@ async def delete_dataset_nav(tenant_id, dataset_id):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/nav/<path:name>", methods=["DELETE"]) # noqa: F821
@manager.route("/datasets/<dataset_id>/navigation/<path:name>", methods=["DELETE"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
async def delete_dataset_nav_node(tenant_id, dataset_id, name):
"""Delete one navigation node and its whole subtree.
DELETE /api/v1/datasets/<dataset_id>/nav/<name>
DELETE /api/v1/datasets/<dataset_id>/navigation/<name>
Success: {"code": 0, "data": {"deleted": <n>}}
"""
try:

View File

@@ -362,13 +362,12 @@ def _register_commit_routes(prefix, param_name, resolver_type=None):
# Register datasets first, workspace second, folders last —
# the last call's handlers overwrite module-level names for test access.
_register_commit_routes("/datasets/<entity_id>", "entity_id", resolver_type="datasets")
_register_commit_routes("/workspace/<entity_id>", "entity_id") # alias — workspace_id == folder_id
_register_commit_routes("/folders/<entity_id>", "entity_id") # direct — entity_id == folder_id (wins)
_register_commit_routes("/workspaces/<entity_id>", "entity_id")
# /memories and /skills routes are not mounted until resolvers are implemented.
# ── File version history (shared across all entity types) ─────────────────
@manager.route("/files/<file_id>/versions", methods=["GET"]) # noqa: F821
@manager.route("/workspace-files/<file_id>/versions", methods=["GET"]) # noqa: F821
@login_required
async def get_file_version_history(file_id):
try:

View File

@@ -17,7 +17,7 @@
"""Shared structure-graph subgraph sampling.
Both the per-document (``/datasets/<id>/documents/<doc>/structure/graph``) and
the dataset-wide (``/datasets/<id>/artifacts_structure``) endpoints render
the dataset-wide (``/datasets/<id>/artifacts/structure``) endpoints render
per-template structure graphs. For large graphs we don't return every
entity/relation — we fetch a representative subgraph from the raw
``knowledge_graph_kwd`` rows (which carry ``mention_count_int`` / ``name_kwd`` /