feat(asr): 本地语音转写接入为一级路由 + 并行工作流合并提交
按用户指示做**一包提交**,不按工作流拆分。本提交刻意混合了多条并行线:
· 本地 ASR 接管:audio 成为与 chat/embed/image/video 同等的路由类别
(IsLocalRoute 单一判据、audio 健康探测、default_audio_route、
auto 占位、GET /api/ai/routes/audio、回退云端时界面明示「音频已出网」)
· LLM 调用层:ctx 贯穿、ToolCall/ToolSchema、EmptyCompletionError /
TransientUpstreamError(按错误类型而非文案判重试)
· 编排 Agent:general_assistant orchestrate/persistence/spec_driver
· 联网搜索:internal/search(playwright)
· 网盘:backend + 前端
· 前端 UI:导航/路由/工作台若干页
· 交付文档:DELIVERY.md / AR04 / 部署文档的「无 Python」表述据实改写,
新增 eai_agentplatform-asr.service、asr.env、clonezilla-cleanup 清 ~/asr-poc
不分拆的原因:dev 早期,粒度不该打断工作节奏。且实测过——这些改动
**在编译上是同一个单元**(llm.go 的 ctx 签名变更牵动 12 个调用点,
chat_message.go 的 ctx 改动又与编排重写同处一个 hunk),拆出来的中间态编不过。
详见 TOP_CODING_RULES.md G14.5 与 bugs_and_errors.md E09。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,11 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
|
||||
if err := os.MkdirAll(filepath.Join(cfg.KBDataDir, "approved"), 0o755); err == nil {
|
||||
r.Static("/media", filepath.Join(cfg.KBDataDir, "approved"))
|
||||
}
|
||||
// 网盘物理文件静态预览(只读):仅 approved 文件通过 Preview 接口取 URL,
|
||||
// 未审批文件不对外暴露,落实「审批前置」。
|
||||
if err := os.MkdirAll(cfg.NetdiskDataDir, 0o755); err == nil {
|
||||
r.Static("/netdisk-file", cfg.NetdiskDataDir)
|
||||
}
|
||||
|
||||
r.GET("/api/health", func(c *gin.Context) {
|
||||
ver := "1.1.0"
|
||||
@@ -117,6 +122,21 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
|
||||
r.GET("/api/media/preview/:media_id", middleware.Auth(cfg), Preview)
|
||||
r.GET("/api/media/status/:media_id", middleware.Auth(cfg), MediaStatus)
|
||||
|
||||
// ── 团队共享网盘(目录 / 文件 / 预览 / 下载)──
|
||||
r.GET("/api/netdisk/folders", middleware.Auth(cfg), netdiskListFolders)
|
||||
r.POST("/api/netdisk/folders", middleware.Auth(cfg), netdiskCreateFolder)
|
||||
r.PATCH("/api/netdisk/folders/:id", middleware.Auth(cfg), netdiskPatchFolder)
|
||||
r.GET("/api/netdisk/files", middleware.Auth(cfg), netdiskListFiles)
|
||||
r.POST("/api/netdisk/upload", middleware.Auth(cfg), netdiskUpload)
|
||||
r.GET("/api/netdisk/files/:id/download", middleware.Auth(cfg), netdiskDownload)
|
||||
r.GET("/api/netdisk/files/:id/preview", middleware.Auth(cfg), netdiskPreview)
|
||||
r.PUT("/api/netdisk/files/:id/rename", middleware.Auth(cfg), netdiskRenameFile)
|
||||
r.PUT("/api/netdisk/files/:id/move", middleware.Auth(cfg), netdiskMoveFile)
|
||||
r.DELETE("/api/netdisk/files/:id", middleware.Auth(cfg), netdiskRecycleFile)
|
||||
// 回收站
|
||||
r.GET("/api/netdisk/recycle", middleware.Auth(cfg), netdiskRecycleList)
|
||||
r.POST("/api/netdisk/recycle/:id/restore", middleware.Auth(cfg), netdiskRestoreFile)
|
||||
|
||||
r.GET("/api/knowledge/spaces", middleware.Auth(cfg), ListKnowledgeSpaces)
|
||||
r.GET("/api/knowledge/search", middleware.Auth(cfg), SearchKnowledge)
|
||||
r.GET("/api/knowledge/status/:source_id", middleware.Auth(cfg), KnowledgeStatus)
|
||||
@@ -130,6 +150,8 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
|
||||
r.GET("/api/ai/usage", middleware.Auth(cfg), AIUsage)
|
||||
r.GET("/api/ai/routes/chat", ListChatRoutes)
|
||||
r.GET("/api/ai/routes/embed", ListEmbedRoutes)
|
||||
r.GET("/api/ai/routes/audio", ListAudioRoutes)
|
||||
r.GET("/api/assistant/opening", middleware.Auth(cfg), GetAssistantOpening)
|
||||
|
||||
// 学习进度(员工上报 + 本人查询)
|
||||
r.POST("/api/learning/progress", middleware.Auth(cfg), RecordLearningProgress)
|
||||
@@ -159,6 +181,19 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
|
||||
r.POST("/api/skills/office/execute", middleware.Auth(cfg), skillapi.ExecuteOfficeSkill)
|
||||
r.POST("/api/skills/office/ocr", middleware.Auth(cfg), skillapi.ExecuteOfficeSkillOCR)
|
||||
r.POST("/api/skills/office/tts", middleware.Auth(cfg), skillapi.ExecuteOfficeSkillTTS)
|
||||
|
||||
// 语音转写技能的四步。**不复用 /api/skills/office/execute**:office 的运行时
|
||||
// 是纯产物构造器(不发网络请求),转写必须真的调 ASR 与 LLM。
|
||||
// 每步一条路由 = 每步一条 task_run,右栏「工作流 x/4」据此推进。
|
||||
// 语音转写:一步一个端点、一步一条 task_run,右栏的「工作流 x/6」靠这个推进。
|
||||
// speakers 与 speakers/confirm 是**两步**:前者只推断(产物落 ready、任务落待确认),
|
||||
// 后者是用户拍板。中间停多久由用户决定,后端不设超时。
|
||||
r.POST("/api/skills/audio/scope", middleware.Auth(cfg), skillapi.ExecuteAudioScope)
|
||||
r.POST("/api/skills/audio/transcribe", middleware.Auth(cfg), skillapi.ExecuteAudioTranscribe)
|
||||
r.POST("/api/skills/audio/speakers", middleware.Auth(cfg), skillapi.ExecuteAudioSpeakers)
|
||||
r.POST("/api/skills/audio/speakers/confirm", middleware.Auth(cfg), skillapi.ExecuteAudioSpeakersConfirm)
|
||||
r.POST("/api/skills/audio/structure", middleware.Auth(cfg), skillapi.ExecuteAudioStructure)
|
||||
r.POST("/api/skills/audio/minutes", middleware.Auth(cfg), skillapi.ExecuteAudioMinutes)
|
||||
r.GET("/api/tts/audio/:filename", middleware.Auth(cfg), skillapi.ServeTTSAudio)
|
||||
r.POST("/api/chat/message", middleware.Auth(cfg), HandleChatMessage)
|
||||
|
||||
@@ -189,6 +224,12 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
|
||||
admin.GET("/media/audit-list", AuditList)
|
||||
admin.POST("/media/audit/:media_id", AuditMedia)
|
||||
|
||||
// 网盘管理:删目录、审批、回收站彻底删除
|
||||
admin.DELETE("/netdisk/folders/:id", netdiskDeleteFolder)
|
||||
admin.GET("/netdisk/audit-list", netdiskAuditList)
|
||||
admin.POST("/netdisk/audit/:id", netdiskAuditFile)
|
||||
admin.DELETE("/netdisk/recycle/:id", netdiskPurgeFile)
|
||||
|
||||
admin.POST("/knowledge/scan", KnowledgeScan)
|
||||
admin.POST("/knowledge/index/rebuild", RebuildKnowledgeIndex)
|
||||
admin.POST("/knowledge/spaces", CreateKnowledgeSpace)
|
||||
|
||||
Reference in New Issue
Block a user