Track bundled vendor runtime sources
This commit is contained in:
31
vendor/aigcpanel/cli/cmd/model_list.go
vendored
Normal file
31
vendor/aigcpanel/cli/cmd/model_list.go
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"aigcpanel-cli/internal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var modelListCmd = &cobra.Command{
|
||||
Use: "model_list",
|
||||
Short: "List installed AI models",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := internal.LoadAuthConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := internal.DoRequest(cfg, "/api/model/list", map[string]any{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 只保留 name/title/version/functions,去掉 id
|
||||
if data, ok := result["data"].([]any); ok {
|
||||
for _, item := range data {
|
||||
if model, ok := item.(map[string]any); ok {
|
||||
delete(model, "id")
|
||||
}
|
||||
}
|
||||
}
|
||||
return internal.PrintJSON(result)
|
||||
},
|
||||
}
|
||||
29
vendor/aigcpanel/cli/cmd/root.go
vendored
Normal file
29
vendor/aigcpanel/cli/cmd/root.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var appVersion string
|
||||
|
||||
// Execute sets the version and runs the root command.
|
||||
func Execute(version string) {
|
||||
appVersion = version
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "aigcpanel",
|
||||
Short: "AIGCPanel CLI",
|
||||
Long: "AIGCPanel command-line tool for interacting with the local AigcPanel service.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
rootCmd.AddCommand(modelListCmd)
|
||||
rootCmd.AddCommand(taskCmd)
|
||||
}
|
||||
217
vendor/aigcpanel/cli/cmd/task.go
vendored
Normal file
217
vendor/aigcpanel/cli/cmd/task.go
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"aigcpanel-cli/internal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var taskCmd = &cobra.Command{
|
||||
Use: "task",
|
||||
Short: "Submit a task and wait for result",
|
||||
Long: `Submit a task to AigcPanel and poll until completion.
|
||||
|
||||
Usage:
|
||||
aigcpanel task --biz <biz> [--key value ...]
|
||||
aigcpanel task --biz <biz> --task-id <id> --stage <stage> [--key value ...]
|
||||
|
||||
Flags:
|
||||
--biz Required. Task type (e.g. VideoCompress, SoundGenerate)
|
||||
--task-id Task ID of a paused task to continue (used with --stage)
|
||||
--stage Stage name to continue (e.g. Config, Confirm)
|
||||
|
||||
For long parameter values, use --key-json /path/to/file.json to read from a JSON file.
|
||||
|
||||
Examples:
|
||||
aigcpanel task --biz VideoCompress --file /path/to/video.mp4
|
||||
aigcpanel task --biz SoundGenerate --text "Hello world"
|
||||
aigcpanel task --biz VideoZoom --video /path/to/video.mp4
|
||||
aigcpanel task --biz VideoZoom --task-id 123 --stage Config --times-json ./_temp/times.json`,
|
||||
DisableFlagParsing: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
biz, taskId, stage, stageData, modelConfig, helpRequested, err := parseTaskArgs(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if helpRequested {
|
||||
return cmd.Help()
|
||||
}
|
||||
if biz == "" {
|
||||
return fmt.Errorf("--biz is required")
|
||||
}
|
||||
|
||||
cfg, err := internal.LoadAuthConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Continue a paused task
|
||||
if taskId != "" && stage != "" {
|
||||
continueResult, err := internal.DoRequest(cfg, "/api/task/continue", map[string]any{
|
||||
"taskId": taskId,
|
||||
"stage": stage,
|
||||
"data": stageData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cCode, _ := continueResult["code"].(float64)
|
||||
if cCode != 0 {
|
||||
return internal.PrintJSON(continueResult)
|
||||
}
|
||||
// Poll for result after continue
|
||||
return pollTask(cfg, taskId)
|
||||
}
|
||||
|
||||
// Submit new task
|
||||
submitResult, err := internal.DoRequest(cfg, "/api/task/submit", map[string]any{
|
||||
"biz": biz,
|
||||
"modelConfig": modelConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
code, _ := submitResult["code"].(float64)
|
||||
if code != 0 {
|
||||
return internal.PrintJSON(submitResult)
|
||||
}
|
||||
|
||||
dataMap, _ := submitResult["data"].(map[string]any)
|
||||
newTaskId, _ := dataMap["taskId"].(string)
|
||||
if newTaskId == "" {
|
||||
return fmt.Errorf("no taskId returned from task submit")
|
||||
}
|
||||
|
||||
return pollTask(cfg, newTaskId)
|
||||
},
|
||||
}
|
||||
|
||||
// pollTask polls /api/model/query until the task reaches a terminal state.
|
||||
func pollTask(cfg *internal.AuthConfig, taskId string) error {
|
||||
deadline := time.Now().Add(120 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
queryResult, err := internal.DoRequest(cfg, "/api/model/query", map[string]any{
|
||||
"taskId": taskId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
qCode, _ := queryResult["code"].(float64)
|
||||
if qCode != 0 {
|
||||
return internal.PrintJSON(queryResult)
|
||||
}
|
||||
qData, _ := queryResult["data"].(map[string]any)
|
||||
status, _ := qData["status"].(string)
|
||||
switch status {
|
||||
case "success", "pause":
|
||||
return internal.PrintJSON(queryResult)
|
||||
case "error", "fail":
|
||||
return internal.PrintJSON(queryResult)
|
||||
default:
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return internal.PrintJSON(map[string]any{
|
||||
"code": -1,
|
||||
"msg": "timeout waiting for task result",
|
||||
})
|
||||
}
|
||||
|
||||
// parseTaskArgs manually parses --key value style arguments.
|
||||
// Reserved flags: --biz, --task-id, --stage.
|
||||
// Flags ending in -json are treated as JSON file paths.
|
||||
// All other --key value pairs become either modelConfig or stageData entries
|
||||
// depending on whether --stage is provided.
|
||||
func parseTaskArgs(args []string) (biz, taskId, stage string, stageData map[string]any, modelConfig map[string]any, helpRequested bool, err error) {
|
||||
modelConfig = map[string]any{}
|
||||
stageData = map[string]any{}
|
||||
|
||||
// First pass: extract reserved flags
|
||||
type kv struct{ key, value string }
|
||||
var pairs []kv
|
||||
i := 0
|
||||
for i < len(args) {
|
||||
arg := args[i]
|
||||
if arg == "--help" || arg == "-h" {
|
||||
return "", "", "", nil, nil, true, nil
|
||||
}
|
||||
if !strings.HasPrefix(arg, "--") {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
key := strings.TrimPrefix(arg, "--")
|
||||
if i+1 >= len(args) || strings.HasPrefix(args[i+1], "--") {
|
||||
fmt.Fprintf(os.Stderr, "warning: flag --%s has no value, ignoring\n", key)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
value := args[i+1]
|
||||
i += 2
|
||||
switch key {
|
||||
case "biz":
|
||||
biz = value
|
||||
case "task-id":
|
||||
taskId = value
|
||||
case "stage":
|
||||
stage = value
|
||||
default:
|
||||
pairs = append(pairs, kv{key, value})
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: distribute remaining flags to modelConfig or stageData
|
||||
for _, p := range pairs {
|
||||
key, value := p.key, p.value
|
||||
|
||||
// JSON file flag: --key-json /path/to/file.json
|
||||
if strings.HasSuffix(key, "-json") {
|
||||
realKey := strings.TrimSuffix(key, "-json")
|
||||
fileBytes, readErr := os.ReadFile(value)
|
||||
if readErr != nil {
|
||||
err = fmt.Errorf("cannot read JSON file for --%s: %w", key, readErr)
|
||||
return
|
||||
}
|
||||
var parsed any
|
||||
if jsonErr := json.Unmarshal(fileBytes, &parsed); jsonErr != nil {
|
||||
err = fmt.Errorf("invalid JSON in file for --%s: %w", key, jsonErr)
|
||||
return
|
||||
}
|
||||
if stage != "" {
|
||||
stageData[realKey] = parsed
|
||||
} else {
|
||||
modelConfig[realKey] = parsed
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Regular flag: auto-parse JSON arrays/objects
|
||||
trimmed := strings.TrimSpace(value)
|
||||
var parsedValue any
|
||||
if (strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]")) ||
|
||||
(strings.HasPrefix(trimmed, "{") && strings.HasSuffix(trimmed, "}")) {
|
||||
var parsed any
|
||||
if jsonErr := json.Unmarshal([]byte(trimmed), &parsed); jsonErr == nil {
|
||||
parsedValue = parsed
|
||||
} else {
|
||||
parsedValue = value
|
||||
}
|
||||
} else {
|
||||
parsedValue = value
|
||||
}
|
||||
|
||||
if stage != "" {
|
||||
stageData[key] = parsedValue
|
||||
} else {
|
||||
modelConfig[key] = parsedValue
|
||||
}
|
||||
}
|
||||
return biz, taskId, stage, stageData, modelConfig, false, nil
|
||||
}
|
||||
17
vendor/aigcpanel/cli/cmd/version.go
vendored
Normal file
17
vendor/aigcpanel/cli/cmd/version.go
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"aigcpanel-cli/internal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print version information",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return internal.PrintJSON(map[string]string{
|
||||
"version": appVersion,
|
||||
})
|
||||
},
|
||||
}
|
||||
10
vendor/aigcpanel/cli/go.mod
vendored
Normal file
10
vendor/aigcpanel/cli/go.mod
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
module aigcpanel-cli
|
||||
|
||||
go 1.21
|
||||
|
||||
require github.com/spf13/cobra v1.8.0
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
)
|
||||
10
vendor/aigcpanel/cli/go.sum
vendored
Normal file
10
vendor/aigcpanel/cli/go.sum
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
60
vendor/aigcpanel/cli/internal/client.go
vendored
Normal file
60
vendor/aigcpanel/cli/internal/client.go
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// DoRequest sends a POST request to the local AigcPanel HTTP server.
|
||||
func DoRequest(cfg *AuthConfig, urlPath string, body any) (map[string]any, error) {
|
||||
var reqBody io.Reader
|
||||
if body != nil {
|
||||
b, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshal request body: %w", err)
|
||||
}
|
||||
reqBody = bytes.NewReader(b)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d%s", cfg.Port, urlPath)
|
||||
req, err := http.NewRequest(http.MethodPost, url, reqBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+cfg.Token)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("request failed: %w (is AigcPanel running?)", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read response: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, fmt.Errorf("unauthorized: token mismatch, restart AigcPanel and try again")
|
||||
}
|
||||
|
||||
var result map[string]any
|
||||
if err := json.Unmarshal(respBytes, &result); err != nil {
|
||||
return nil, fmt.Errorf("parse response: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PrintJSON outputs a value as indented JSON to stdout.
|
||||
func PrintJSON(v any) error {
|
||||
b, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
return nil
|
||||
}
|
||||
66
vendor/aigcpanel/cli/internal/config.go
vendored
Normal file
66
vendor/aigcpanel/cli/internal/config.go
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// AuthConfig holds the port and token read from cli-auth.json
|
||||
type AuthConfig struct {
|
||||
Port int `json:"port"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// userDataDir returns the Electron userData directory path matching app.getPath('userData')
|
||||
// which uses the app name "aigcpanel".
|
||||
func userDataDir() (string, error) {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, "Library", "Application Support", "aigcpanel"), nil
|
||||
case "windows":
|
||||
appData := os.Getenv("APPDATA")
|
||||
if appData == "" {
|
||||
return "", fmt.Errorf("APPDATA environment variable not set")
|
||||
}
|
||||
return filepath.Join(appData, "aigcpanel"), nil
|
||||
default:
|
||||
// Linux: XDG_CONFIG_HOME or ~/.config
|
||||
configDir := os.Getenv("XDG_CONFIG_HOME")
|
||||
if configDir == "" {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
configDir = filepath.Join(home, ".config")
|
||||
}
|
||||
return filepath.Join(configDir, "aigcpanel"), nil
|
||||
}
|
||||
}
|
||||
|
||||
// LoadAuthConfig reads cli-auth.json from the aigcpanel userData directory.
|
||||
func LoadAuthConfig() (*AuthConfig, error) {
|
||||
dir, err := userDataDir()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot determine userData directory: %w", err)
|
||||
}
|
||||
filePath := filepath.Join(dir, "cli-auth.json")
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot read %s: %w (is AigcPanel running?)", filePath, err)
|
||||
}
|
||||
var cfg AuthConfig
|
||||
if err := json.Unmarshal(data, &cfg); err != nil {
|
||||
return nil, fmt.Errorf("invalid cli-auth.json: %w", err)
|
||||
}
|
||||
if cfg.Port == 0 || cfg.Token == "" {
|
||||
return nil, fmt.Errorf("cli-auth.json is incomplete (port=%d, token empty=%v)", cfg.Port, cfg.Token == "")
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
10
vendor/aigcpanel/cli/main.go
vendored
Normal file
10
vendor/aigcpanel/cli/main.go
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "aigcpanel-cli/cmd"
|
||||
|
||||
// Version is injected at build time via ldflags: -X main.Version=x.x.x
|
||||
var Version = "dev"
|
||||
|
||||
func main() {
|
||||
cmd.Execute(Version)
|
||||
}
|
||||
Reference in New Issue
Block a user