Files
ttstd-infinite-canvas/backend/internal/app/workbench_bridge.go

194 lines
6.8 KiB
Go

package app
import (
"strings"
"yingce/backend/internal/assets"
"yingce/backend/internal/model"
"yingce/backend/internal/workbench"
)
const (
WorkbenchKindImage = workbench.KindImage
WorkbenchKindVideo = workbench.KindVideo
)
type (
WorkbenchToolInput = workbench.ToolInput
WorkbenchPresetInput = workbench.PresetInput
WorkbenchToolView = workbench.ToolView
WorkbenchPresetView = workbench.PresetView
WorkbenchTaskInput = workbench.TaskInput
)
type workbenchAdminGate struct{ svc *Service }
func (g workbenchAdminGate) RequireAdmin(user *model.User) error {
if g.svc == nil {
return Unauthorized("请先登录")
}
return g.svc.RequireAdmin(user)
}
func (g workbenchAdminGate) AppendAudit(actor *model.User, action, targetType, targetID, summary string, metadata any) error {
if g.svc == nil {
return Unauthorized("请先登录")
}
return g.svc.appendAdminAudit(actor, action, targetType, targetID, summary, metadata)
}
func (g workbenchAdminGate) WorkbenchResourceAccess(resourceID string) (string, error) {
if g.svc == nil {
return "", Unauthorized("请先登录")
}
resource, err := g.svc.repo.Resource(strings.TrimSpace(resourceID))
if err != nil {
return "", NotFound("工具展示资源不存在")
}
if resource.Kind != "image" && resource.Kind != "video" && resource.Kind != "audio" || resource.Status != model.ResourceStatusReady {
return "", BadAuthRequest("工具展示资源不可用")
}
access, err := g.svc.resolveResourceAccess(resource, ResourceAccessOptions{Purpose: assets.PurposeDisplay})
if err != nil {
return "", err
}
return access.URL, nil
}
func (s *Service) workbenchDomain() *workbench.Service {
if s == nil {
return workbench.New(nil, nil, nil)
}
if s.workbench != nil {
return s.workbench
}
return workbench.New(s.repo, workbenchAdminGate{svc: s}, workbenchAdminGate{svc: s})
}
func (s *Service) EnsureBuiltinWorkbenchCatalog() error {
return s.workbenchDomain().EnsureBuiltinCatalog()
}
func (s *Service) PublicWorkbenchTools(kind string) ([]WorkbenchToolView, error) {
if kind == workbench.KindImage {
if err := s.RequireFeature(FeatureImageWorkbench); err != nil {
return nil, err
}
} else if kind == workbench.KindVideo {
if err := s.RequireFeature(FeatureVideoWorkbench); err != nil {
return nil, err
}
} else {
return nil, BadAuthRequest("工作台类型无效")
}
return s.workbenchDomain().PublicTools(kind)
}
func (s *Service) AdminWorkbenchTools(actor *model.User, kind string) ([]WorkbenchToolView, error) {
return s.workbenchDomain().AdminTools(actor, kind)
}
func (s *Service) CreateWorkbenchTool(actor *model.User, req WorkbenchToolInput) (*WorkbenchToolView, error) {
return s.workbenchDomain().CreateTool(actor, req)
}
func (s *Service) UpdateWorkbenchTool(actor *model.User, id string, req WorkbenchToolInput) (*WorkbenchToolView, error) {
return s.workbenchDomain().UpdateTool(actor, id, req)
}
func (s *Service) SetWorkbenchToolEnabled(actor *model.User, id string, enabled bool) error {
return s.workbenchDomain().SetToolEnabled(actor, id, enabled)
}
func (s *Service) CreateWorkbenchPreset(actor *model.User, req WorkbenchPresetInput) (*WorkbenchPresetView, error) {
return s.workbenchDomain().CreatePreset(actor, req)
}
func (s *Service) UpdateWorkbenchPreset(actor *model.User, id string, req WorkbenchPresetInput) (*WorkbenchPresetView, error) {
return s.workbenchDomain().UpdatePreset(actor, id, req)
}
func (s *Service) SetWorkbenchPresetEnabled(actor *model.User, id string, enabled bool) error {
return s.workbenchDomain().SetPresetEnabled(actor, id, enabled)
}
func (s *Service) CreateWorkbenchTask(userID string, req WorkbenchTaskInput, traceID, requestID string) (*model.Task, error) {
if req.Kind == WorkbenchKindImage {
if err := s.RequireFeature(FeatureImageWorkbench); err != nil {
return nil, err
}
} else if req.Kind == WorkbenchKindVideo {
if err := s.RequireFeature(FeatureVideoWorkbench); err != nil {
return nil, err
}
} else {
return nil, BadAuthRequest("工作台类型无效")
}
resolved, err := s.workbenchDomain().ResolveTask(userID, req)
if err != nil {
return nil, err
}
providerConfig, err := s.resolveWorkbenchProviderConfig(req.Kind, resolved.Model, resolved.LogicalModelID, resolved.ChannelID, resolved.Parameters, resolved.Input)
if err != nil {
return nil, err
}
resolved.Input["config"] = providerConfig
modelName, ok := providerConfig["model"].(string)
if !ok || strings.TrimSpace(modelName) == "" {
return nil, BadAuthRequest("所选系统模型不可用")
}
resolved.Model = modelName
return s.CreateTask(userID, CreateTaskRequest{Type: resolved.TaskType, Operation: resolved.Operation, Prompt: resolved.Prompt, Model: resolved.Model, LogicalModelID: resolved.LogicalModelID, Input: resolved.Input, TraceID: traceID, RequestID: requestID, workbenchKind: req.Kind})
}
func (s *Service) WorkbenchTasks(userID, kind string, activeOnly bool, limit int) ([]TaskSummary, error) {
if kind == WorkbenchKindImage {
if err := s.RequireFeature(FeatureImageWorkbench); err != nil {
return nil, err
}
} else if kind == WorkbenchKindVideo {
if err := s.RequireFeature(FeatureVideoWorkbench); err != nil {
return nil, err
}
} else {
return nil, BadAuthRequest("工作台类型无效")
}
return s.TasksWithOptions(userID, TaskListOptions{Limit: limit, ActiveOnly: activeOnly, WorkbenchKind: kind})
}
func (s *Service) resolveWorkbenchProviderConfig(kind, modelName, logicalModelID, channelID string, parameters map[string]any, input map[string]any) (map[string]any, error) {
config := map[string]any{"mode": kind}
if kind == WorkbenchKindImage {
for _, key := range []string{"size", "quality", "imageResolution", "count"} {
if value, exists := parameters[key]; exists {
config[key] = providerConfigOptionValue(value)
}
}
} else if kind == WorkbenchKindVideo {
for inputKey, configKey := range map[string]string{
"seconds": "videoSeconds", "ratio": "size", "resolution": "vquality",
"generateAudio": "videoGenerateAudio", "watermark": "videoWatermark",
} {
if value, exists := parameters[inputKey]; exists {
config[configKey] = providerConfigOptionValue(value)
}
}
} else {
return nil, BadAuthRequest("工作台类型无效")
}
if logicalModelID != "" {
config["model"] = modelName
return config, nil
}
channelID = strings.TrimSpace(channelID)
modelName = strings.TrimSpace(modelName)
if channelID == "" || modelName == "" {
return nil, BadAuthRequest("所选系统模型不可用")
}
config["channelId"] = channelID
config["model"] = modelName
input["config"] = config
resolved, err := s.resolveSystemChannelModelSelection(input, "canvas_"+kind, "")
if err != nil {
return nil, err
}
providerConfig, _ := resolved["config"].(map[string]any)
if len(providerConfig) == 0 {
return nil, BadAuthRequest("所选系统模型不可用")
}
return providerConfig, nil
}