44406b72db
Moteva-style AI design workbench replica. Home prompt creates a project; the project page provides an infinite canvas with node drag, zoom/pan, a design chat panel, history replay, image asset upload, and project save/regenerate. - Backend: go-zero, DDD layering, sqlc/pgx, optional PostgreSQL; memory or Redis cache; asynq job queue; MinIO/S3/R2/OSS object storage; sky-valley/pi agent runtime adapter. - Frontend: Next.js App Router + Vite artifact build, TypeScript, i18n, shadcn/ui components, auth (OTP/Turnstile/Google/WeChat). - Deploy: Docker Compose and k3s manifests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
273 lines
6.1 KiB
Go
273 lines
6.1 KiB
Go
package design
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
ErrInvalidInput = errors.New("invalid input")
|
|
ErrNotFound = errors.New("project not found")
|
|
ErrConflict = errors.New("project version conflict")
|
|
)
|
|
|
|
type ProjectStatus string
|
|
|
|
const (
|
|
StatusDraft ProjectStatus = "draft"
|
|
StatusExploring ProjectStatus = "exploring"
|
|
StatusReady ProjectStatus = "ready"
|
|
StatusFailed ProjectStatus = "failed"
|
|
)
|
|
|
|
type NodeType string
|
|
|
|
const (
|
|
NodeTypeBrief NodeType = "brief"
|
|
NodeTypeReference NodeType = "reference"
|
|
NodeTypeImage NodeType = "image"
|
|
NodeTypeText NodeType = "text"
|
|
NodeTypeFrame NodeType = "frame"
|
|
)
|
|
|
|
type Viewport struct {
|
|
X float64
|
|
Y float64
|
|
K float64
|
|
}
|
|
|
|
type MockupPoint struct {
|
|
X float64 `json:"x"`
|
|
Y float64 `json:"y"`
|
|
}
|
|
|
|
type MockupMesh struct {
|
|
Columns int `json:"columns"`
|
|
Rows int `json:"rows"`
|
|
Points []MockupPoint `json:"points"`
|
|
}
|
|
|
|
type MockupPlacement struct {
|
|
X float64 `json:"x"`
|
|
Y float64 `json:"y"`
|
|
Width float64 `json:"width"`
|
|
Height float64 `json:"height"`
|
|
}
|
|
|
|
type MockupSurface struct {
|
|
TargetID string `json:"targetId"`
|
|
Polygon []MockupPoint `json:"polygon"`
|
|
Mesh MockupMesh `json:"mesh"`
|
|
}
|
|
|
|
type MockupSurfaceResult struct {
|
|
Placement MockupPlacement
|
|
Surface MockupSurface
|
|
}
|
|
|
|
type MockupModelMap struct {
|
|
DataID string `json:"dataId"`
|
|
Width int `json:"width"`
|
|
Height int `json:"height"`
|
|
URL string `json:"url,omitempty"`
|
|
Data []float64 `json:"data,omitempty"`
|
|
}
|
|
|
|
type MockupCameraIntrinsics struct {
|
|
Matrix []float64 `json:"matrix"`
|
|
}
|
|
|
|
type MockupModel struct {
|
|
Version int `json:"version"`
|
|
DepthMap MockupModelMap `json:"depthMap"`
|
|
DepthScaleMin float64 `json:"depthScaleMin"`
|
|
DepthScaleMax float64 `json:"depthScaleMax"`
|
|
ShadeMap MockupModelMap `json:"shadeMap"`
|
|
SegmentationMap MockupModelMap `json:"segmentationMap"`
|
|
XOffsetMap MockupModelMap `json:"xOffsetMap"`
|
|
YOffsetMap MockupModelMap `json:"yOffsetMap"`
|
|
CameraIntrinsics MockupCameraIntrinsics `json:"cameraIntrinsics"`
|
|
ColorCorrection string `json:"colorCorrection"`
|
|
ForegroundImage string `json:"foregroundImage"`
|
|
}
|
|
|
|
type MockupModelResult struct {
|
|
Placement MockupPlacement
|
|
Model MockupModel
|
|
}
|
|
|
|
type MockupModelAnalysisRequest struct {
|
|
Project Project
|
|
Node Node
|
|
ImageDataURL string
|
|
ImageWidth int
|
|
ImageHeight int
|
|
}
|
|
|
|
type MockupModelAnalysis struct {
|
|
Placement MockupPlacement
|
|
Surface MockupSurface
|
|
Model MockupModel
|
|
}
|
|
|
|
type MockupBlobData struct {
|
|
DataID string
|
|
Width int
|
|
Height int
|
|
Data []byte
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type Node struct {
|
|
ID string
|
|
Type NodeType
|
|
Title string
|
|
X float64
|
|
Y float64
|
|
Width float64
|
|
Height float64
|
|
Content string
|
|
Tone string
|
|
Status string
|
|
ParentID string
|
|
LayerRole string
|
|
FontSize float64
|
|
FontFamily string
|
|
FontWeight string
|
|
Color string
|
|
TextAlign string
|
|
LineHeight float64
|
|
LetterSpacing float64
|
|
TextDecoration string
|
|
TextTransform string
|
|
Opacity float64
|
|
FillColor string
|
|
StrokeColor string
|
|
StrokeWidth float64
|
|
StrokeStyle string
|
|
FlipX bool
|
|
FlipY bool
|
|
Rotation float64
|
|
ImageAdjustments string
|
|
MockupSurface MockupSurface
|
|
MockupModel MockupModel
|
|
MockupSourceContent string
|
|
}
|
|
|
|
type NodeActionRequest struct {
|
|
Action string
|
|
Prompt string
|
|
ImageModel string
|
|
ImageSize string
|
|
Mask string
|
|
Selection string
|
|
Options map[string]string
|
|
}
|
|
|
|
type Connection struct {
|
|
ID string
|
|
FromNodeID string
|
|
ToNodeID string
|
|
}
|
|
|
|
type Message struct {
|
|
ID string
|
|
Role string
|
|
Type string
|
|
Title string
|
|
Content string
|
|
ThreadID string
|
|
ActionID string
|
|
StepID string
|
|
ToolCallID string
|
|
Name string
|
|
ToolHint string
|
|
Status string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type Project struct {
|
|
ID string
|
|
UserID string
|
|
Title string
|
|
Brief string
|
|
Status ProjectStatus
|
|
Thumbnail string
|
|
UpdatedAt time.Time
|
|
Version string
|
|
SnapshotID string
|
|
Canvas string
|
|
LastThreadID string
|
|
Viewport Viewport
|
|
Nodes []Node
|
|
Connections []Connection
|
|
Messages []Message
|
|
}
|
|
|
|
type ProjectSummary struct {
|
|
ID string
|
|
UserID string
|
|
Title string
|
|
Brief string
|
|
Status ProjectStatus
|
|
Thumbnail string
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
type QuickAction struct {
|
|
ID string
|
|
Label string
|
|
Prompt string
|
|
Icon string
|
|
}
|
|
|
|
type InspirationItem struct {
|
|
ID string
|
|
Title string
|
|
Category string
|
|
Description string
|
|
Accent string
|
|
}
|
|
|
|
type Repository interface {
|
|
List(ctx context.Context) ([]ProjectSummary, error)
|
|
ListPage(ctx context.Context, limit int64, offset int64) ([]ProjectSummary, error)
|
|
Get(ctx context.Context, id string) (Project, error)
|
|
Save(ctx context.Context, project Project) error
|
|
Delete(ctx context.Context, id string) error
|
|
}
|
|
|
|
type CanvasRepository interface {
|
|
SaveCanvas(ctx context.Context, project Project, baseVersion string) error
|
|
}
|
|
|
|
type MockupBlobRepository interface {
|
|
SaveMockupBlob(ctx context.Context, blob MockupBlobData) error
|
|
GetMockupBlob(ctx context.Context, dataID string) (MockupBlobData, error)
|
|
}
|
|
|
|
type MockupModelAnalyzer interface {
|
|
AnalyzeMockupModel(ctx context.Context, req MockupModelAnalysisRequest) (MockupModelAnalysis, error)
|
|
}
|
|
|
|
func NormalizeTitle(title string, fallback string) string {
|
|
title = strings.TrimSpace(title)
|
|
if title == "" {
|
|
return fallback
|
|
}
|
|
return title
|
|
}
|
|
|
|
func NormalizePrompt(prompt string) string {
|
|
return strings.TrimSpace(prompt)
|
|
}
|
|
|
|
func SortSummaries(items []ProjectSummary) {
|
|
sort.SliceStable(items, func(i, j int) bool {
|
|
return items[i].UpdatedAt.After(items[j].UpdatedAt)
|
|
})
|
|
}
|