feat(SynthDataDetail): add chunk/synthesis data management with edit/delete & UI enhancements (#139)

* feat(synthesis): add evaluation task creation functionality and UI enhancements

* feat(synthesis): implement synthesis data management features including loading, editing, and deleting

* feat(synthesis): add endpoints for deleting and updating synthesis data and chunks

* fix: Correctly extract file values from selectedFilesMap in AddDataDialog
This commit is contained in:
Dallas98
2025-12-09 09:59:40 +08:00
committed by GitHub
parent cf20299af4
commit 015e738a7f
6 changed files with 659 additions and 90 deletions

View File

@@ -25,6 +25,8 @@ from app.module.generation.schema.generation import (
DataSynthesisChunkItem,
PagedDataSynthesisChunkResponse,
SynthesisDataItem,
SynthesisDataUpdateRequest,
BatchDeleteSynthesisDataRequest,
)
from app.module.generation.service.generation_service import GenerationService
from app.module.generation.service.prompt import get_prompt
@@ -118,7 +120,7 @@ async def list_synthesis_tasks(
name: str | None = None,
db: AsyncSession = Depends(get_db)
):
"""分页列出所有数据合成任务"""
"""分页列出所有数据合成任务,默认按创建时间倒序"""
query = select(DataSynthesisInstance)
if synthesis_type:
query = query.filter(DataSynthesisInstance.synthesis_type == synthesis_type)
@@ -127,6 +129,9 @@ async def list_synthesis_tasks(
if name:
query = query.filter(DataSynthesisInstance.name.like(f"%{name}%"))
# 默认按创建时间倒序排列
query = query.order_by(DataSynthesisInstance.created_at.desc())
count_q = select(func.count()).select_from(query.subquery())
total = (await db.execute(count_q)).scalar_one()
@@ -179,7 +184,7 @@ async def list_synthesis_tasks(
)
@router.delete("/task/{task_id}", response_model=StandardResponse[None])
@router.delete("/task/{task_id}", response_model=StandardResponse)
async def delete_synthesis_task(
task_id: str,
db: AsyncSession = Depends(get_db)
@@ -228,7 +233,7 @@ async def delete_synthesis_task(
)
@router.delete("/task/{task_id}/{file_id}", response_model=StandardResponse[None])
@router.delete("/task/{task_id}/{file_id}", response_model=StandardResponse)
async def delete_synthesis_file_task(
task_id: str,
file_id: str,
@@ -476,3 +481,100 @@ async def export_synthesis_task_to_dataset(
message="success",
data=dataset.id,
)
@router.delete("/chunk/{chunk_id}", response_model=StandardResponse)
async def delete_chunk_with_data(
chunk_id: str,
db: AsyncSession = Depends(get_db),
):
"""删除单条 t_data_synthesis_chunk_instances 记录及其关联的所有 t_data_synthesis_data"""
chunk = await db.get(DataSynthesisChunkInstance, chunk_id)
if not chunk:
raise HTTPException(status_code=404, detail="Chunk not found")
# 先删除与该 chunk 关联的合成数据
await db.execute(
delete(SynthesisData).where(SynthesisData.chunk_instance_id == chunk_id)
)
# 再删除 chunk 本身
await db.execute(
delete(DataSynthesisChunkInstance).where(
DataSynthesisChunkInstance.id == chunk_id
)
)
await db.commit()
return StandardResponse(code=200, message="success", data=None)
@router.delete("/chunk/{chunk_id}/data", response_model=StandardResponse)
async def delete_synthesis_data_by_chunk(
chunk_id: str,
db: AsyncSession = Depends(get_db),
):
"""仅删除指定 chunk 下的全部 t_data_synthesis_data 记录,返回删除条数"""
chunk = await db.get(DataSynthesisChunkInstance, chunk_id)
if not chunk:
raise HTTPException(status_code=404, detail="Chunk not found")
result = await db.execute(
delete(SynthesisData).where(SynthesisData.chunk_instance_id == chunk_id)
)
deleted = result.rowcount or 0
await db.commit()
return StandardResponse(code=200, message="success", data=deleted)
@router.delete("/data/batch", response_model=StandardResponse)
async def batch_delete_synthesis_data(
request: BatchDeleteSynthesisDataRequest,
db: AsyncSession = Depends(get_db),
):
"""批量删除 t_data_synthesis_data 记录"""
if not request.ids:
return StandardResponse(code=200, message="success", data=0)
result = await db.execute(
delete(SynthesisData).where(SynthesisData.id.in_(request.ids))
)
deleted = result.rowcount or 0
await db.commit()
return StandardResponse(code=200, message="success", data=deleted)
@router.patch("/data/{data_id}", response_model=StandardResponse)
async def update_synthesis_data_field(
data_id: str,
body: SynthesisDataUpdateRequest,
db: AsyncSession = Depends(get_db),
):
"""修改单条 t_data_synthesis_data.data 的完整 JSON
前端传入完整 JSON,后端直接覆盖原有 data 字段,不做局部 merge。
"""
record = await db.get(SynthesisData, data_id)
if not record:
raise HTTPException(status_code=404, detail="Synthesis data not found")
# 直接整体覆盖 data 字段
record.data = body.data
await db.commit()
await db.refresh(record)
return StandardResponse(
code=200,
message="success",
data=SynthesisDataItem(
id=record.id,
data=record.data,
synthesis_file_instance_id=record.synthesis_file_instance_id,
chunk_instance_id=record.chunk_instance_id,
),
)

View File

@@ -135,3 +135,39 @@ class ChatRequest(BaseModel):
"""聊天请求参数"""
model_id: str
prompt: str
class SynthesisDataUpdateRequest(BaseModel):
"""单条合成数据 data 字段整体更新请求(前端传入完整 JSON,后端直接覆盖)"""
data: Dict[str, Any] = Field(..., description="新的完整 JSON 对象,将覆盖原有 data 字段")
class BatchDeleteSynthesisDataRequest(BaseModel):
"""批量删除合成数据请求"""
ids: List[str] = Field(..., description="需要删除的合成数据 ID 列表")
class BatchDeleteChunkInstancesRequest(BaseModel):
"""批量删除分块及其关联合成数据请求"""
chunk_ids: List[str] = Field(..., description="需要删除的 chunk 实例 ID 列表")
class BatchDeleteChunkInstancesByFileRequest(BaseModel):
"""按文件任务维度删除 chunk 及其合成数据的请求"""
file_id: str = Field(..., description="数据合成文件任务 ID")
class BatchDeleteChunkInstancesByTaskRequest(BaseModel):
"""按任务维度删除 chunk 及其合成数据的请求"""
task_id: str = Field(..., description="数据合成任务 ID")
class SynthesisDataPatchItem(BaseModel):
"""用于前端展示/编辑的合成数据项(包含 chunk 与文件信息,可按需扩展)"""
id: str
data: Optional[Dict[str, Any]] = None
chunk_instance_id: str
synthesis_file_instance_id: str
class Config:
orm_mode = True