feat(task): 添加任务删除功能,支持通过 API 删除任务并更新前端状态
This commit is contained in:
parent
1430dfc91f
commit
4a0110d1a7
@ -8,16 +8,19 @@
|
|||||||
- 集成 LangFuse (观望) 添加用户日志与用户反馈模块,可以在 AgentView 中查看信息
|
- 集成 LangFuse (观望) 添加用户日志与用户反馈模块,可以在 AgentView 中查看信息
|
||||||
- 集成 neo4j mcp (或者自己构建工具)
|
- 集成 neo4j mcp (或者自己构建工具)
|
||||||
- chat_model 的 call 需要异步
|
- chat_model 的 call 需要异步
|
||||||
- 考虑修改附件的处理逻辑,考虑使用文件系统,将附件解析后放到文件系统中,智能体按需读取,用户可以使用 @ 来引用附件,例如 @file:reports.md 相较于现在的处理逻辑感觉会更加自然一点。在此之前可能还要考虑文件系统的后端支持问题
|
- 优化智能体文件系统:
|
||||||
|
- 使用 CompositeBackend 和 自定义后端系统,链接 minio 中的知识库文件。提供除检索以外的方法
|
||||||
|
- 考虑修改附件的处理逻辑,考虑使用文件系统,将附件解析后放到文件系统中,智能体按需读取(当前是完全解析,放进上下文)
|
||||||
|
- 【后续】用户可以使用 @ 来引用附件,例如 @file:reports.md 相较于现在的处理逻辑感觉会更加自然一点。
|
||||||
- skills 如何实现还需要继续调研
|
- skills 如何实现还需要继续调研
|
||||||
- 增加 paddle-vl 以及 deepseek-ocr 的支持(deepseek-ocr 已支持)
|
- 增加 paddle-vl 以及 deepseek-ocr 的支持(deepseek-ocr 已支持)
|
||||||
- 系统层面添加 apikey,在智能体、知识库调用中支持 apikey 以支持外部调用
|
- 系统层面添加 apikey,在智能体、知识库调用中支持 apikey 以支持外部调用
|
||||||
- 支持更多类型的文档源的导入功能
|
- 支持更多类型的文档源的导入功能(支持后端配置的白名单的 URL 导入)
|
||||||
- Tasker 新增删除任务的接口
|
|
||||||
- 部分场景应该使用默认模型作为默认值而不是空值
|
- 部分场景应该使用默认模型作为默认值而不是空值
|
||||||
- CommonRAG 添加更多检索类型,比如 BM25,关键词,grep 等
|
- CommonRAG 添加更多检索类型,比如 BM25,关键词,grep 等
|
||||||
- 文件上传解析后,如何提示用户需要入库
|
- 文件上传解析后,如何提示用户需要入库
|
||||||
- 检索测试中,添加问答
|
- 检索测试中,添加问答
|
||||||
|
- 丰富当前智能体的 Prompt,最好支持从 markdown 解析
|
||||||
|
|
||||||
|
|
||||||
### Bugs
|
### Bugs
|
||||||
@ -47,6 +50,7 @@
|
|||||||
- 优化后端的依赖,减少镜像体积 [#428](https://github.com/xerrors/Yuxi-Know/issues/428)
|
- 优化后端的依赖,减少镜像体积 [#428](https://github.com/xerrors/Yuxi-Know/issues/428)
|
||||||
- 优化 liaghtrag 的知识库调用结果,提供 content/graph/both 多个选项
|
- 优化 liaghtrag 的知识库调用结果,提供 content/graph/both 多个选项
|
||||||
- 优化数据库查询工具,可通过设计环境变量添加描述,让模型更好的调用
|
- 优化数据库查询工具,可通过设计环境变量添加描述,让模型更好的调用
|
||||||
|
- 优化任务组件,改用 postgresql 存储,并新增删除任务的接口
|
||||||
|
|
||||||
### 修复
|
### 修复
|
||||||
|
|
||||||
|
|||||||
@ -33,3 +33,12 @@ async def cancel_task(task_id: str, current_user: User = Depends(get_admin_user)
|
|||||||
if not success:
|
if not success:
|
||||||
raise HTTPException(status_code=400, detail="Task cannot be cancelled")
|
raise HTTPException(status_code=400, detail="Task cannot be cancelled")
|
||||||
return {"task_id": task_id, "status": "cancelled"}
|
return {"task_id": task_id, "status": "cancelled"}
|
||||||
|
|
||||||
|
|
||||||
|
@tasks.delete("/{task_id}")
|
||||||
|
async def delete_task(task_id: str, current_user: User = Depends(get_admin_user)):
|
||||||
|
"""Delete a task by id."""
|
||||||
|
success = await tasker.delete_task(task_id)
|
||||||
|
if not success:
|
||||||
|
raise HTTPException(status_code=404, detail="Task not found")
|
||||||
|
return {"task_id": task_id, "status": "deleted"}
|
||||||
|
|||||||
@ -40,6 +40,12 @@ class TaskRepository:
|
|||||||
setattr(record, key, value)
|
setattr(record, key, value)
|
||||||
return record
|
return record
|
||||||
|
|
||||||
|
async def delete(self, task_id: str) -> bool:
|
||||||
|
"""Delete a task by id. Returns True if deleted, False if not found."""
|
||||||
|
async with pg_manager.get_async_session_context() as session:
|
||||||
|
result = await session.execute(delete(TaskRecord).where(TaskRecord.id == task_id))
|
||||||
|
return result.rowcount > 0
|
||||||
|
|
||||||
async def delete_all(self) -> None:
|
async def delete_all(self) -> None:
|
||||||
async with pg_manager.get_async_session_context() as session:
|
async with pg_manager.get_async_session_context() as session:
|
||||||
await session.execute(delete(TaskRecord))
|
await session.execute(delete(TaskRecord))
|
||||||
|
|||||||
@ -185,6 +185,16 @@ class Tasker:
|
|||||||
logger.info("Cancellation requested for task {}", task_id)
|
logger.info("Cancellation requested for task {}", task_id)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
async def delete_task(self, task_id: str) -> bool:
|
||||||
|
"""Delete a task by id. Returns True if deleted, False if not found."""
|
||||||
|
async with self._lock:
|
||||||
|
if task_id not in self._tasks:
|
||||||
|
return False
|
||||||
|
del self._tasks[task_id]
|
||||||
|
await self._repo.delete(task_id)
|
||||||
|
logger.info("Deleted task {}", task_id)
|
||||||
|
return True
|
||||||
|
|
||||||
async def _worker_loop(self) -> None:
|
async def _worker_loop(self) -> None:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { apiAdminGet, apiAdminPost } from './base'
|
import { apiAdminDelete, apiAdminGet, apiAdminPost } from './base'
|
||||||
|
|
||||||
const BASE_URL = '/api/tasks'
|
const BASE_URL = '/api/tasks'
|
||||||
|
|
||||||
@ -15,5 +15,9 @@ export const taskerApi = {
|
|||||||
|
|
||||||
cancelTask: async (taskId) => {
|
cancelTask: async (taskId) => {
|
||||||
return apiAdminPost(`${BASE_URL}/${taskId}/cancel`, {})
|
return apiAdminPost(`${BASE_URL}/${taskId}/cancel`, {})
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteTask: async (taskId) => {
|
||||||
|
return apiAdminDelete(`${BASE_URL}/${taskId}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,6 +84,15 @@
|
|||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</a-button>
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
danger
|
||||||
|
v-if="isTaskCompleted(task)"
|
||||||
|
@click.stop="handleDelete(task.id, task.name)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -258,6 +267,19 @@ function handleCancel(taskId) {
|
|||||||
taskerStore.cancelTask(taskId)
|
taskerStore.cancelTask(taskId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleDelete(taskId, taskName) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '确认删除',
|
||||||
|
content: `确定要删除任务"${taskName}"吗?此操作不可恢复。`,
|
||||||
|
okText: '删除',
|
||||||
|
okType: 'danger',
|
||||||
|
cancelText: '取消',
|
||||||
|
onOk: () => {
|
||||||
|
taskerStore.deleteTask(taskId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function formatTime(value, mode = 'full') {
|
function formatTime(value, mode = 'full') {
|
||||||
if (!value) return '-'
|
if (!value) return '-'
|
||||||
if (mode === 'short') {
|
if (mode === 'short') {
|
||||||
|
|||||||
@ -124,6 +124,22 @@ export const useTaskerStore = defineStore('tasker', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteTask(taskId) {
|
||||||
|
if (!taskId) return
|
||||||
|
try {
|
||||||
|
await taskerApi.deleteTask(taskId)
|
||||||
|
message.success('删除任务成功')
|
||||||
|
// 从本地列表中移除
|
||||||
|
const index = tasks.value.findIndex((item) => item.id === taskId)
|
||||||
|
if (index >= 0) {
|
||||||
|
tasks.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`删除任务 ${taskId} 失败`, error)
|
||||||
|
message.error(error?.message || '删除任务失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function registerQueuedTask({ task_id, name, task_type, message: msg, payload } = {}) {
|
function registerQueuedTask({ task_id, name, task_type, message: msg, payload } = {}) {
|
||||||
if (!task_id) return
|
if (!task_id) return
|
||||||
const now = new Date().toISOString()
|
const now = new Date().toISOString()
|
||||||
@ -192,6 +208,7 @@ export const useTaskerStore = defineStore('tasker', () => {
|
|||||||
loadTasks,
|
loadTasks,
|
||||||
refreshTask,
|
refreshTask,
|
||||||
cancelTask,
|
cancelTask,
|
||||||
|
deleteTask,
|
||||||
registerQueuedTask,
|
registerQueuedTask,
|
||||||
startPolling,
|
startPolling,
|
||||||
stopPolling,
|
stopPolling,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user