feat(migrations): Harden task audit tracking and optimize article templates

- Added migration to harden task audit tracking by modifying audit_logs and related tables.
- Introduced operator_id to several tables for better tracking of actions.
- Updated article_templates with new prompt templates for various article types, enhancing content generation.
- Created prompt_rules and schedule_tasks tables to manage content generation rules and scheduling.
- Added foreign key constraints to articles for better data integrity.
This commit is contained in:
2026-04-02 00:31:28 +08:00
parent de30497f59
commit b31d8d0096
101 changed files with 16671 additions and 721 deletions
+75 -2
View File
@@ -25,7 +25,10 @@ type arkClient struct {
model string
timeout time.Duration
maxOutputTokens int64
webSearchLimit int64
temperature float64
topP *float64
reasoning *responses.ResponsesReasoning
}
func NewArkClient(cfg config.LLMConfig) Client {
@@ -53,17 +56,30 @@ func NewArkClient(cfg config.LLMConfig) Client {
maxOutputTokens = 4000
}
webSearchLimit := int64(cfg.WebSearchLimit)
if webSearchLimit <= 0 {
webSearchLimit = 3
}
temperature := cfg.Temperature
if temperature <= 0 {
temperature = 0.7
}
var topP *float64
if cfg.TopP > 0 {
topP = &cfg.TopP
}
return &arkClient{
client: arkruntime.NewClientWithApiKey(cfg.APIKey, arkruntime.WithBaseUrl(baseURL)),
model: model,
timeout: timeout,
maxOutputTokens: maxOutputTokens,
webSearchLimit: webSearchLimit,
temperature: temperature,
topP: topP,
reasoning: resolveArkReasoning(cfg.ReasoningEffort),
}
}
@@ -87,10 +103,21 @@ func (c *arkClient) Generate(ctx context.Context, req GenerateRequest, onDelta f
return nil, errors.New("prompt is required")
}
callCtx, cancel := context.WithTimeout(ctx, c.timeout)
timeout := c.timeout
if req.Timeout > 0 {
timeout = req.Timeout
}
maxOutputTokens := c.maxOutputTokens
if req.MaxOutputTokens > 0 {
maxOutputTokens = req.MaxOutputTokens
}
callCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
store := false
streamValue := true
inputMessage := &responses.ItemInputMessage{
Role: responses.MessageRole_user,
Content: []*responses.ContentItem{
@@ -105,11 +132,34 @@ func (c *arkClient) Generate(ctx context.Context, req GenerateRequest, onDelta f
},
}
var tools []*responses.ResponsesTool
if req.WebSearch != nil && req.WebSearch.Enabled {
webSearchLimit := c.webSearchLimit
if req.WebSearch.Limit > 0 {
webSearchLimit = int64(req.WebSearch.Limit)
}
tools = []*responses.ResponsesTool{
{
Union: &responses.ResponsesTool_ToolWebSearch{
ToolWebSearch: &responses.ToolWebSearch{
Type: responses.ToolType_web_search,
Limit: &webSearchLimit,
},
},
},
}
}
stream, err := c.client.CreateResponsesStream(callCtx, &responses.ResponsesRequest{
Model: c.model,
MaxOutputTokens: &c.maxOutputTokens,
MaxOutputTokens: &maxOutputTokens,
Store: &store,
Stream: &streamValue,
Temperature: &c.temperature,
TopP: c.topP,
Tools: tools,
Reasoning: c.reasoning,
Input: &responses.ResponsesInput{
Union: &responses.ResponsesInput_ListValue{
ListValue: &responses.InputItemList{
@@ -125,6 +175,9 @@ func (c *arkClient) Generate(ctx context.Context, req GenerateRequest, onDelta f
},
})
if err != nil {
if errors.Is(err, context.DeadlineExceeded) || errors.Is(callCtx.Err(), context.DeadlineExceeded) {
return nil, fmt.Errorf("ark response stream timeout after %s: %w", timeout, err)
}
return nil, fmt.Errorf("create ark response stream: %w", err)
}
defer stream.Close()
@@ -137,6 +190,9 @@ func (c *arkClient) Generate(ctx context.Context, req GenerateRequest, onDelta f
if errors.Is(err, io.EOF) {
break
}
if errors.Is(err, context.DeadlineExceeded) || errors.Is(callCtx.Err(), context.DeadlineExceeded) {
return nil, fmt.Errorf("ark response stream timeout after %s: %w", timeout, err)
}
return nil, fmt.Errorf("receive ark stream event: %w", err)
}
@@ -176,3 +232,20 @@ func (c *arkClient) Generate(ctx context.Context, req GenerateRequest, onDelta f
Model: c.model,
}, nil
}
func resolveArkReasoning(value string) *responses.ResponsesReasoning {
switch strings.ToLower(strings.TrimSpace(value)) {
case "":
return nil
case "minimal":
return &responses.ResponsesReasoning{Effort: responses.ReasoningEffort_minimal}
case "low":
return &responses.ResponsesReasoning{Effort: responses.ReasoningEffort_low}
case "medium":
return &responses.ResponsesReasoning{Effort: responses.ReasoningEffort_medium}
case "high":
return &responses.ResponsesReasoning{Effort: responses.ReasoningEffort_high}
default:
return nil
}
}
+10 -1
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"github.com/geo-platform/tenant-api/internal/shared/config"
)
@@ -12,7 +13,10 @@ import (
var ErrNotConfigured = errors.New("llm provider is not configured")
type GenerateRequest struct {
Prompt string
Prompt string
Timeout time.Duration
MaxOutputTokens int64
WebSearch *WebSearchOptions
}
type GenerateResult struct {
@@ -20,6 +24,11 @@ type GenerateResult struct {
Model string
}
type WebSearchOptions struct {
Enabled bool
Limit int32
}
type Client interface {
Validate() error
Generate(ctx context.Context, req GenerateRequest, onDelta func(string)) (*GenerateResult, error)