package handlers import ( "encoding/json" "fmt" "net/http" "strconv" "strings" "prompt-generator/internal/db" "prompt-generator/internal/models" ) func GetBuilderSessions(w http.ResponseWriter, r *http.Request) { rows, err := db.DB.Query("SELECT id, title, project_name, final_prompt, claude_session_id, created_at, updated_at FROM builder_sessions ORDER BY updated_at DESC") if err != nil { fail(w, 500, "查询会话列表失败") return } defer rows.Close() var sessions []models.BuilderSession for rows.Next() { var s models.BuilderSession if err := rows.Scan(&s.ID, &s.Title, &s.ProjectName, &s.FinalPrompt, &s.ClaudeSessionID, &s.CreatedAt, &s.UpdatedAt); err != nil { continue } sessions = append(sessions, s) } if sessions == nil { sessions = []models.BuilderSession{} } success(w, sessions) } func CreateBuilderSession(w http.ResponseWriter, r *http.Request) { var req struct { Title string `json:"title"` ProjectName string `json:"project_name"` FinalPrompt string `json:"final_prompt"` ClaudeSessionID string `json:"claude_session_id"` TagOptionIDs []struct { TagID int64 `json:"tag_id"` TagOptionID int64 `json:"tag_option_id"` } `json:"tag_option_ids"` SnippetIDs []struct { SnippetID int64 `json:"snippet_id"` SortOrder int `json:"sort_order"` } `json:"snippet_ids"` Materials []struct { Title string `json:"title"` Content string `json:"content"` SortOrder int `json:"sort_order"` } `json:"materials"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { fail(w, 400, "请求格式错误") return } var claudeID *string if req.ClaudeSessionID != "" { claudeID = &req.ClaudeSessionID } res, err := db.DB.Exec("INSERT INTO builder_sessions (title, project_name, final_prompt, claude_session_id) VALUES (?, ?, ?, ?)", req.Title, req.ProjectName, req.FinalPrompt, claudeID) if err != nil { fail(w, 500, "创建会话失败") return } sessionID, _ := res.LastInsertId() // Insert tag associations for _, t := range req.TagOptionIDs { db.DB.Exec("INSERT INTO builder_session_tags (builder_session_id, tag_id, tag_option_id) VALUES (?, ?, ?)", sessionID, t.TagID, t.TagOptionID) } // Insert snippet associations for _, s := range req.SnippetIDs { db.DB.Exec("INSERT INTO builder_session_snippets (builder_session_id, snippet_id, sort_order) VALUES (?, ?, ?)", sessionID, s.SnippetID, s.SortOrder) } // Insert materials for _, m := range req.Materials { db.DB.Exec("INSERT INTO builder_session_materials (builder_session_id, title, content, sort_order) VALUES (?, ?, ?, ?)", sessionID, m.Title, m.Content, m.SortOrder) } success(w, map[string]int64{"id": sessionID}) } func GetBuilderSession(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { fail(w, 400, "无效的 ID") return } var s models.BuilderSession err = db.DB.QueryRow("SELECT id, title, project_name, final_prompt, claude_session_id, created_at, updated_at FROM builder_sessions WHERE id=?", id). Scan(&s.ID, &s.Title, &s.ProjectName, &s.FinalPrompt, &s.ClaudeSessionID, &s.CreatedAt, &s.UpdatedAt) if err != nil { fail(w, 404, "会话不存在") return } // Load tags tagRows, err := db.DB.Query("SELECT id, builder_session_id, tag_id, tag_option_id FROM builder_session_tags WHERE builder_session_id=?", id) if err == nil { for tagRows.Next() { var t models.SessionTag if err := tagRows.Scan(&t.ID, &t.BuilderSessionID, &t.TagID, &t.TagOptionID); err == nil { s.Tags = append(s.Tags, t) } } tagRows.Close() } // Load snippets snippetRows, err := db.DB.Query("SELECT id, builder_session_id, snippet_id, sort_order FROM builder_session_snippets WHERE builder_session_id=? ORDER BY sort_order", id) if err == nil { for snippetRows.Next() { var sn models.SessionSnippet if err := snippetRows.Scan(&sn.ID, &sn.BuilderSessionID, &sn.SnippetID, &sn.SortOrder); err == nil { s.Snippets = append(s.Snippets, sn) } } snippetRows.Close() } // Load materials materialRows, err := db.DB.Query("SELECT id, builder_session_id, title, content, sort_order FROM builder_session_materials WHERE builder_session_id=? ORDER BY sort_order", id) if err == nil { for materialRows.Next() { var m models.SessionMaterial if err := materialRows.Scan(&m.ID, &m.BuilderSessionID, &m.Title, &m.Content, &m.SortOrder); err == nil { s.Materials = append(s.Materials, m) } } materialRows.Close() } if s.Tags == nil { s.Tags = []models.SessionTag{} } if s.Snippets == nil { s.Snippets = []models.SessionSnippet{} } if s.Materials == nil { s.Materials = []models.SessionMaterial{} } success(w, s) } func UpdateBuilderSession(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { fail(w, 400, "无效的 ID") return } var req struct { Title string `json:"title"` ProjectName string `json:"project_name"` FinalPrompt string `json:"final_prompt"` ClaudeSessionID string `json:"claude_session_id"` TagOptionIDs []struct { TagID int64 `json:"tag_id"` TagOptionID int64 `json:"tag_option_id"` } `json:"tag_option_ids"` SnippetIDs []struct { SnippetID int64 `json:"snippet_id"` SortOrder int `json:"sort_order"` } `json:"snippet_ids"` Materials []struct { Title string `json:"title"` Content string `json:"content"` SortOrder int `json:"sort_order"` } `json:"materials"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { fail(w, 400, "请求格式错误") return } var claudeID *string if req.ClaudeSessionID != "" { claudeID = &req.ClaudeSessionID } _, err = db.DB.Exec("UPDATE builder_sessions SET title=?, project_name=?, final_prompt=?, claude_session_id=? WHERE id=?", req.Title, req.ProjectName, req.FinalPrompt, claudeID, id) if err != nil { fail(w, 500, "更新会话失败") return } // Replace tags db.DB.Exec("DELETE FROM builder_session_tags WHERE builder_session_id=?", id) for _, t := range req.TagOptionIDs { db.DB.Exec("INSERT INTO builder_session_tags (builder_session_id, tag_id, tag_option_id) VALUES (?, ?, ?)", id, t.TagID, t.TagOptionID) } // Replace snippets db.DB.Exec("DELETE FROM builder_session_snippets WHERE builder_session_id=?", id) for _, s := range req.SnippetIDs { db.DB.Exec("INSERT INTO builder_session_snippets (builder_session_id, snippet_id, sort_order) VALUES (?, ?, ?)", id, s.SnippetID, s.SortOrder) } // Replace materials db.DB.Exec("DELETE FROM builder_session_materials WHERE builder_session_id=?", id) for _, m := range req.Materials { db.DB.Exec("INSERT INTO builder_session_materials (builder_session_id, title, content, sort_order) VALUES (?, ?, ?, ?)", id, m.Title, m.Content, m.SortOrder) } success(w, nil) } func DeleteBuilderSession(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { fail(w, 400, "无效的 ID") return } db.DB.Exec("DELETE FROM builder_session_tags WHERE builder_session_id=?", id) db.DB.Exec("DELETE FROM builder_session_snippets WHERE builder_session_id=?", id) db.DB.Exec("DELETE FROM builder_session_materials WHERE builder_session_id=?", id) db.DB.Exec("DELETE FROM builder_sessions WHERE id=?", id) success(w, nil) } // AssemblePrompt 组装最终 Prompt func AssemblePrompt(projectName string, customContent string, tagOptions []models.TagOption, snippets []models.Snippet, suggestions []string, materials []models.SessionMaterial) string { var parts []string // Project context if projectName != "" { parts = append(parts, fmt.Sprintf("## 项目上下文\n\n项目名称: %s", projectName)) } // Custom content if customContent != "" { parts = append(parts, fmt.Sprintf("## 用户输入\n\n%s", customContent)) } // Tag constraints if len(tagOptions) > 0 { var constraints []string for _, opt := range tagOptions { constraints = append(constraints, fmt.Sprintf("- %s", opt.ConstraintText)) } parts = append(parts, fmt.Sprintf("## 约束\n\n%s", strings.Join(constraints, "\n"))) } // Snippets if len(snippets) > 0 { var snippetParts []string for _, s := range snippets { snippetParts = append(snippetParts, fmt.Sprintf("--- %s ---\n%s", s.Name, s.Content)) } parts = append(parts, fmt.Sprintf("## 参考片段\n\n%s", strings.Join(snippetParts, "\n\n"))) } // Materials if len(materials) > 0 { var materialParts []string for i, m := range materials { title := m.Title if title == "" { title = fmt.Sprintf("参考材料%d", i+1) } materialParts = append(materialParts, fmt.Sprintf("--- %s ---\n%s", title, m.Content)) } parts = append(parts, fmt.Sprintf("## 参考材料\n\n%s", strings.Join(materialParts, "\n\n"))) } // Suggestions if len(suggestions) > 0 { parts = append(parts, fmt.Sprintf("## 补充建议\n\n%s", strings.Join(suggestions, "\n"))) } return strings.Join(parts, "\n\n") }