feat: 实现自建情景功能
## 功能概述 - 用户可创建、编辑、删除自定义情景 - 支持自定义情景名称、图标、描述、Prompt、首句引导 - 完整的权限隔离,用户只能管理自己的情景 - 深度集成 Eino 框架,动态加载自建情景 Prompt ## 后端实现 ### 数据库 - 新增 user_scenarios 表 - 支持用户配额(最多 20 个) - 字段验证:description 可选,prompt 最小 10 字符 ### API - GET /api/scenarios - 获取用户情景列表 - POST /api/scenarios - 创建情景 - GET /api/scenarios/:id - 获取详情 - PATCH /api/scenarios/:id - 更新情景 - DELETE /api/scenarios/:id - 删除情景 ### Eino 集成 - PipelineState 添加 UserID 字段 - nodes_history 动态加载用户自建情景 - GetScenarioPrompt 支持自建情景优先级 ## 前端实现 ### 组件 - CreateScenarioModal - 创建情景对话框 - EditScenarioModal - 编辑情景对话框 - ConfigPanel 改造 - 分组显示系统预置和自建情景 ### Hook - useScenarios - 合并系统和自建情景,提供 CRUD 接口 ### 国际化 - 中文、英文、日文翻译支持 ## 问题修复 - 修复 CORS 问题:使用 Vite 代理 - 统一验证规则:description 可选,prompt 最小 10 字符 - 修复数据库约束:使用 NULLIF 处理空字符串 ## 文件变更 新增文件: 13 个 修改文件: 14 个 详见文档: docs/自建情景功能完整文档.md
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/redis/go-redis/v9"
|
||||
|
||||
"github.com/hhs/camtalk/internal/api"
|
||||
@@ -54,6 +55,7 @@ func main() {
|
||||
var userRepo store.UserRepository
|
||||
var msgRepo store.MessageRepository
|
||||
var sessRepo store.SessionRepository
|
||||
var pool *pgxpool.Pool // 数据库连接池
|
||||
|
||||
// L3: PostgreSQL(冷数据持久化层)
|
||||
dsn := cfg.Storage.Persistence.DSN
|
||||
@@ -65,7 +67,8 @@ func main() {
|
||||
logger.Log.Fatalw("storage.persistence.dsn is required when persistence is enabled",
|
||||
"hint", "set CAMTALK_STORAGE_DSN environment variable")
|
||||
}
|
||||
pool, err := store.NewPostgresPool(ctx, dsn)
|
||||
var err error
|
||||
pool, err = store.NewPostgresPool(ctx, dsn)
|
||||
if err != nil {
|
||||
logger.Log.Fatalw("failed to connect to postgres", "error", err)
|
||||
}
|
||||
@@ -181,7 +184,11 @@ func main() {
|
||||
}
|
||||
|
||||
// 初始化 Eino Graph + Orchestrator
|
||||
pipelineGraph, err := eino.NewPipelineGraph(ctx, cfg, sttService, ttsService, sessionMgr)
|
||||
var userScenarioRepo store.UserScenarioRepository
|
||||
if pool != nil {
|
||||
userScenarioRepo = store.NewPostgresUserScenarioRepo(pool)
|
||||
}
|
||||
pipelineGraph, err := eino.NewPipelineGraph(ctx, cfg, sttService, ttsService, sessionMgr, userScenarioRepo)
|
||||
if err != nil {
|
||||
logger.Log.Fatalw("failed to create eino pipeline graph", "error", err)
|
||||
}
|
||||
@@ -221,8 +228,23 @@ func main() {
|
||||
convHandler := api.NewConversationHandler(sessionMgr, tokenMgr, msgRepo)
|
||||
convHandler.RegisterRoutes(apiGroup)
|
||||
|
||||
// UserScenario REST 端点
|
||||
if pool != nil {
|
||||
userScenarioRepo := store.NewPostgresUserScenarioRepo(pool)
|
||||
userScenarioHandler := api.NewUserScenarioHandler(userScenarioRepo)
|
||||
scenarioGroup := apiGroup.Group("/scenarios")
|
||||
scenarioGroup.Use(auth.AuthMiddleware(tokenMgr))
|
||||
{
|
||||
scenarioGroup.GET("", userScenarioHandler.List)
|
||||
scenarioGroup.POST("", userScenarioHandler.Create)
|
||||
scenarioGroup.GET("/:id", userScenarioHandler.Get)
|
||||
scenarioGroup.PATCH("/:id", userScenarioHandler.Update)
|
||||
scenarioGroup.DELETE("/:id", userScenarioHandler.Delete)
|
||||
}
|
||||
}
|
||||
|
||||
// WebSocket
|
||||
r.GET("/ws", ws.ServeWS(sessionMgr, orch, cfg, tokenMgr))
|
||||
r.GET("/ws", ws.ServeWS(sessionMgr, orch, cfg, tokenMgr, userScenarioRepo))
|
||||
|
||||
// HTTP Server
|
||||
srv := &http.Server{
|
||||
|
||||
Reference in New Issue
Block a user