feat: add prompt history management

This commit is contained in:
2026-07-13 14:06:45 +08:00
parent cb3b91b101
commit 44ab895149
9 changed files with 876 additions and 230 deletions

View File

@@ -1,9 +1,10 @@
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import func, select
from sqlalchemy.orm import Session
from app.api.pagination import page_result
from app.core.database import get_db
from app.core.dependencies import get_current_admin
from app.core.responses import api_success
@@ -32,8 +33,13 @@ DEFAULT_PROMPT = "你是大本营答疑助手。你只能基于提供的知识
@router.get("/prompt")
def get_prompt(db: Session = Depends(get_db), current_admin: Admin = Depends(get_current_admin)) -> dict:
prompt = db.scalar(select(Prompt).order_by(Prompt.updated_at.desc(), Prompt.id.desc()).limit(1))
return api_success({"promptContent": prompt.prompt_content if prompt else DEFAULT_PROMPT})
row = db.execute(
select(Prompt, Admin)
.outerjoin(Admin, Admin.id == Prompt.updated_by)
.order_by(Prompt.updated_at.desc(), Prompt.id.desc())
.limit(1)
).first()
return api_success(_prompt_detail(row[0], row[1]) if row else _default_prompt_detail())
@router.put("/prompt")
@@ -42,22 +48,91 @@ def save_prompt(
db: Session = Depends(get_db),
current_admin: Admin = Depends(get_current_admin),
) -> dict:
prompt = Prompt(prompt_content=payload.promptContent, updated_by=current_admin.id)
prompt = Prompt(prompt_content=payload.promptContent, change_type="save", updated_by=current_admin.id)
db.add(prompt)
db.flush()
OperationLogService.write(db, admin_id=current_admin.id, module="prompt", action="save", target_id=prompt.id)
db.commit()
return api_success({"promptContent": prompt.prompt_content})
db.refresh(prompt)
return api_success(_prompt_detail(prompt, current_admin))
@router.post("/prompt/reset")
def reset_prompt(db: Session = Depends(get_db), current_admin: Admin = Depends(get_current_admin)) -> dict:
prompt = Prompt(prompt_content=DEFAULT_PROMPT, updated_by=current_admin.id)
prompt = Prompt(prompt_content=DEFAULT_PROMPT, change_type="reset", updated_by=current_admin.id)
db.add(prompt)
db.flush()
OperationLogService.write(db, admin_id=current_admin.id, module="prompt", action="reset", target_id=prompt.id)
db.commit()
return api_success({"promptContent": prompt.prompt_content})
db.refresh(prompt)
return api_success(_prompt_detail(prompt, current_admin))
@router.get("/prompt/history")
def prompt_history(
page: int = Query(default=1, ge=1),
pageSize: int = Query(default=10, ge=10, le=100),
db: Session = Depends(get_db),
current_admin: Admin = Depends(get_current_admin),
) -> dict:
total = db.scalar(select(func.count(Prompt.id))) or 0
rows = db.execute(
select(Prompt, Admin)
.outerjoin(Admin, Admin.id == Prompt.updated_by)
.order_by(Prompt.updated_at.desc(), Prompt.id.desc())
.offset((page - 1) * pageSize)
.limit(pageSize)
).all()
items = [
_prompt_summary(prompt, admin, is_current=index == 0 and page == 1)
for index, (prompt, admin) in enumerate(rows)
]
return api_success(page_result(items, total=total, page=page, page_size=pageSize))
@router.get("/prompt/history/{prompt_id}")
def prompt_history_detail(
prompt_id: int,
db: Session = Depends(get_db),
current_admin: Admin = Depends(get_current_admin),
) -> dict:
row = db.execute(
select(Prompt, Admin)
.outerjoin(Admin, Admin.id == Prompt.updated_by)
.where(Prompt.id == prompt_id)
).first()
if row is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="提示词版本不存在")
return api_success(_prompt_detail(row[0], row[1]))
@router.post("/prompt/history/{prompt_id}/restore")
def restore_prompt(
prompt_id: int,
db: Session = Depends(get_db),
current_admin: Admin = Depends(get_current_admin),
) -> dict:
source = db.get(Prompt, prompt_id)
if source is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="提示词版本不存在")
restored = Prompt(
prompt_content=source.prompt_content,
change_type="restore",
source_prompt_id=source.id,
updated_by=current_admin.id,
)
db.add(restored)
db.flush()
OperationLogService.write(
db,
admin_id=current_admin.id,
module="prompt",
action="restore",
target_id=restored.id,
)
db.commit()
db.refresh(restored)
return api_success(_prompt_detail(restored, current_admin))
@router.post("/agent/debug")
@@ -296,6 +371,44 @@ def _model_dict(model: ModelConfig) -> dict:
}
def _default_prompt_detail() -> dict:
return {
"id": None,
"promptContent": DEFAULT_PROMPT,
"changeType": "default",
"sourcePromptId": None,
"updatedByName": "系统默认",
"updatedAt": None,
"charCount": len(DEFAULT_PROMPT),
}
def _prompt_summary(prompt: Prompt, admin: Admin | None, *, is_current: bool) -> dict:
compact = " ".join(prompt.prompt_content.split())
return {
"id": prompt.id,
"preview": compact[:140],
"charCount": len(prompt.prompt_content),
"changeType": prompt.change_type,
"sourcePromptId": prompt.source_prompt_id,
"updatedByName": admin.name if admin else "未知管理员",
"updatedAt": prompt.updated_at,
"isCurrent": is_current,
}
def _prompt_detail(prompt: Prompt, admin: Admin | None = None) -> dict:
return {
"id": prompt.id,
"promptContent": prompt.prompt_content,
"changeType": prompt.change_type,
"sourcePromptId": prompt.source_prompt_id,
"updatedByName": admin.name if admin else None,
"updatedAt": prompt.updated_at,
"charCount": len(prompt.prompt_content),
}
def _agent_knowledge_scopes(db: Session, knowledge_ids: list[int]) -> list[KnowledgeScope]:
query = select(Knowledge).where(Knowledge.status == 1)
if knowledge_ids: