feat(tasks): add templates findings workflows and batch controls
This commit is contained in:
1 parent
b7e0b93023
commit
d3183dbbd2
65 files changed
+11603
-2198
No files matched your search
+58
-12
@@ -2,6 +2,7 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
@@ -10,12 +11,33 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Autumn-27/artex/agent"
|
||||
"github.com/Autumn-27/artex/db"
|
||||
"github.com/Autumn-27/artex/intercept"
|
||||
)
|
||||
|
||||
const (
|
||||
maxConversationRequestBytes = 64 << 10
|
||||
maxConversationAgentKeyRunes = 120
|
||||
maxConversationTitleRunes = 200
|
||||
)
|
||||
|
||||
func decodeConversationRequest(w http.ResponseWriter, r *http.Request, value any) bool {
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxConversationRequestBytes)
|
||||
if err := decode(r, value); err != nil {
|
||||
var tooLarge *http.MaxBytesError
|
||||
if errors.As(err, &tooLarge) {
|
||||
writeErr(w, http.StatusRequestEntityTooLarge, "请求正文过大")
|
||||
} else {
|
||||
writeErr(w, http.StatusBadRequest, err.Error())
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ---------- conversations (chat page) ----------
|
||||
//
|
||||
// A conversation is a ChatGPT-style thread bound to an agent key, independent of
|
||||
@@ -46,8 +68,7 @@ func (s *Server) pgCreateConversation(w http.ResponseWriter, r *http.Request) {
|
||||
Title string `json:"title"`
|
||||
LLMProfileID *int64 `json:"llm_profile_id"`
|
||||
}
|
||||
if err := decode(r, &req); err != nil {
|
||||
writeErr(w, 400, err.Error())
|
||||
if !decodeConversationRequest(w, r, &req) {
|
||||
return
|
||||
}
|
||||
req.AgentKey = strings.TrimSpace(req.AgentKey)
|
||||
@@ -55,6 +76,10 @@ func (s *Server) pgCreateConversation(w http.ResponseWriter, r *http.Request) {
|
||||
writeErr(w, 400, "agent_key 不能为空")
|
||||
return
|
||||
}
|
||||
if utf8.RuneCountInString(req.AgentKey) > maxConversationAgentKeyRunes {
|
||||
writeErr(w, 400, fmt.Sprintf("agent_key 最多 %d 个字符", maxConversationAgentKeyRunes))
|
||||
return
|
||||
}
|
||||
a, err := pg.GetAgentByKey(req.AgentKey)
|
||||
if err != nil {
|
||||
writeErr(w, 500, err.Error())
|
||||
@@ -74,6 +99,10 @@ func (s *Server) pgCreateConversation(w http.ResponseWriter, r *http.Request) {
|
||||
if title == "" {
|
||||
title = "新对话"
|
||||
}
|
||||
if utf8.RuneCountInString(title) > maxConversationTitleRunes {
|
||||
writeErr(w, 400, fmt.Sprintf("标题最多 %d 个字符", maxConversationTitleRunes))
|
||||
return
|
||||
}
|
||||
c, err := pg.CreateConversation(req.AgentKey, title, req.LLMProfileID)
|
||||
if err != nil {
|
||||
writeErr(w, 500, err.Error())
|
||||
@@ -90,8 +119,7 @@ func (s *Server) pgUpdateConversation(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
LLMProfileID *int64 `json:"llm_profile_id"` // null clears the override
|
||||
}
|
||||
if err := decode(r, &req); err != nil {
|
||||
writeErr(w, 400, err.Error())
|
||||
if !decodeConversationRequest(w, r, &req) {
|
||||
return
|
||||
}
|
||||
if req.LLMProfileID != nil {
|
||||
@@ -135,21 +163,39 @@ func (s *Server) pgRenameConversation(w http.ResponseWriter, r *http.Request) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var req struct{ Title string }
|
||||
if err := decode(r, &req); err != nil {
|
||||
writeErr(w, 400, err.Error())
|
||||
var req struct {
|
||||
Title *string `json:"title"`
|
||||
Pinned *bool `json:"pinned"`
|
||||
}
|
||||
if !decodeConversationRequest(w, r, &req) {
|
||||
return
|
||||
}
|
||||
title := strings.TrimSpace(req.Title)
|
||||
if title == "" {
|
||||
writeErr(w, 400, "标题不能为空")
|
||||
if req.Title == nil && req.Pinned == nil {
|
||||
writeErr(w, 400, "至少需要提供 title 或 pinned")
|
||||
return
|
||||
}
|
||||
if err := pg.RenameConversation(c.ID, title); err != nil {
|
||||
if req.Title != nil {
|
||||
title := strings.TrimSpace(*req.Title)
|
||||
if title == "" {
|
||||
writeErr(w, 400, "标题不能为空")
|
||||
return
|
||||
}
|
||||
if utf8.RuneCountInString(title) > maxConversationTitleRunes {
|
||||
writeErr(w, 400, fmt.Sprintf("标题最多 %d 个字符", maxConversationTitleRunes))
|
||||
return
|
||||
}
|
||||
req.Title = &title
|
||||
}
|
||||
updated, err := pg.UpdateConversation(c.ID, db.ConversationPatch{Title: req.Title, Pinned: req.Pinned})
|
||||
if err != nil {
|
||||
writeErr(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"ok": true})
|
||||
if updated == nil {
|
||||
writeErr(w, 404, "conversation not found")
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, updated)
|
||||
}
|
||||
|
||||
func (s *Server) pgDeleteConversation(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in new issue
Block a user