Initial commit: img-infinite-canvas AI design workbench MVP
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>
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
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)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user