@doufunao123/asset-gateway 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +220 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command9 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/auth.ts
|
|
7
7
|
import { existsSync as existsSync2, unlinkSync } from "fs";
|
|
@@ -70,7 +70,7 @@ function normalizeError(error2) {
|
|
|
70
70
|
|
|
71
71
|
// src/meta.ts
|
|
72
72
|
var CLI_NAME = "asset-gateway";
|
|
73
|
-
var CLI_VERSION = "0.
|
|
73
|
+
var CLI_VERSION = "0.6.0";
|
|
74
74
|
var CLI_DESCRIPTION = "Universal asset generation gateway CLI";
|
|
75
75
|
var DEFAULT_GATEWAY_URL = "https://assets.xiaomao.chat";
|
|
76
76
|
|
|
@@ -527,7 +527,7 @@ async function saveOutput(result, assetType, outputDir) {
|
|
|
527
527
|
function createGenerateCommand() {
|
|
528
528
|
const command = new Command3("generate").description("Generate assets via the gateway");
|
|
529
529
|
command.addCommand(
|
|
530
|
-
new Command3("image").description("Generate an image from a text prompt").requiredOption("--prompt <text>", "Image description prompt").option("--provider <id>", "Provider to use").option("--transparent", "Request transparent background").option("--model <model>", "Model to use").option("--size <size>", "Image size (e.g. 1024x1024)").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
530
|
+
new Command3("image").description("Generate an image from a text prompt").requiredOption("--prompt <text>", "Image description prompt").option("--provider <id>", "Provider to use").option("--transparent", "Request transparent background").option("--model <model>", "Model to use").option("--size <size>", "Image size (e.g. 1024x1024)").option("--input <url>", "Input image URL for editing (Gemini/Grok)").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
531
531
|
try {
|
|
532
532
|
const ctx = createContext(this);
|
|
533
533
|
const body = {
|
|
@@ -538,6 +538,7 @@ function createGenerateCommand() {
|
|
|
538
538
|
if (options.transparent) body.transparent = true;
|
|
539
539
|
if (options.model) body.model = options.model;
|
|
540
540
|
if (options.size) body.size = options.size;
|
|
541
|
+
if (options.input) body.input_file = options.input;
|
|
541
542
|
const data = await ctx.client.post("/api/generate", body);
|
|
542
543
|
const localPath = await saveOutput(data, "image", options.outputDir);
|
|
543
544
|
if (localPath) data.local_path = localPath;
|
|
@@ -610,14 +611,25 @@ function createGenerateCommand() {
|
|
|
610
611
|
})
|
|
611
612
|
);
|
|
612
613
|
command.addCommand(
|
|
613
|
-
new Command3("model").description("Generate a 3D model").option("--image <url>", "Reference image URL").option("--prompt <text>", "Model description prompt").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
614
|
+
new Command3("model").description("Generate a 3D model").option("--image <url>", "Reference image URL").option("--prompt <text>", "Model description prompt").option("--model-version <v>", "Tripo model version (e.g. P1-20260311)").option("--face-limit <n>", "Max face count (48-20000)").option("--pbr", "Enable PBR textures").option("--texture-quality <q>", "Texture quality: standard or detailed").option("--auto-size", "Auto-scale to real-world dimensions").option("--negative-prompt <text>", "Negative prompt").option("--multiview <urls>", "4 image URLs comma-separated: front,left,back,right").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
614
615
|
try {
|
|
615
616
|
const ctx = createContext(this);
|
|
616
617
|
const body = {
|
|
617
618
|
asset_type: "model3d"
|
|
618
619
|
};
|
|
620
|
+
const params = {};
|
|
619
621
|
if (options.image) body.input_file = options.image;
|
|
620
622
|
if (options.prompt) body.prompt = options.prompt;
|
|
623
|
+
if (options.modelVersion) params.model_version = options.modelVersion;
|
|
624
|
+
if (options.faceLimit) params.face_limit = Number(options.faceLimit);
|
|
625
|
+
if (options.pbr) params.pbr = true;
|
|
626
|
+
if (options.textureQuality) params.texture_quality = options.textureQuality;
|
|
627
|
+
if (options.autoSize) params.auto_size = true;
|
|
628
|
+
if (options.negativePrompt) params.negative_prompt = options.negativePrompt;
|
|
629
|
+
if (options.multiview) {
|
|
630
|
+
params.multiview = String(options.multiview).split(",").map((value) => value.trim()).filter(Boolean);
|
|
631
|
+
}
|
|
632
|
+
if (Object.keys(params).length > 0) body.params = params;
|
|
621
633
|
const data = await ctx.client.post("/api/generate", body);
|
|
622
634
|
const localPath = await saveOutput(data, "model3d", options.outputDir);
|
|
623
635
|
if (localPath) data.local_path = localPath;
|
|
@@ -789,12 +801,205 @@ function createProcessCommand() {
|
|
|
789
801
|
return command;
|
|
790
802
|
}
|
|
791
803
|
|
|
792
|
-
// src/commands/
|
|
804
|
+
// src/commands/process3d.ts
|
|
805
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
806
|
+
import { join as join4 } from "path";
|
|
793
807
|
import { Command as Command6 } from "commander";
|
|
808
|
+
function infer3dExtension(format) {
|
|
809
|
+
const map = {
|
|
810
|
+
fbx: "fbx",
|
|
811
|
+
usdz: "usdz",
|
|
812
|
+
obj: "obj",
|
|
813
|
+
stl: "stl",
|
|
814
|
+
gltf: "gltf",
|
|
815
|
+
"3mf": "3mf",
|
|
816
|
+
glb: "glb"
|
|
817
|
+
};
|
|
818
|
+
return map[String(format ?? "glb").toLowerCase()] ?? "glb";
|
|
819
|
+
}
|
|
820
|
+
async function saveProcess3dOutput(data, operation, outputDir, format) {
|
|
821
|
+
if (!data.output_url) {
|
|
822
|
+
return null;
|
|
823
|
+
}
|
|
824
|
+
const ext = infer3dExtension(format);
|
|
825
|
+
const timestamp = Date.now();
|
|
826
|
+
const filePath = join4(outputDir, `${operation}_${timestamp}.${ext}`);
|
|
827
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
828
|
+
const response = await fetch(String(data.output_url));
|
|
829
|
+
if (!response.ok) {
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
833
|
+
writeFileSync4(filePath, buffer);
|
|
834
|
+
return filePath;
|
|
835
|
+
}
|
|
836
|
+
function createProcess3dCommand() {
|
|
837
|
+
const command = new Command6("process3d").description("3D model post-processing via Tripo pipeline");
|
|
838
|
+
command.addCommand(
|
|
839
|
+
new Command6("convert").description("Convert 3D model format (FBX/USDZ/OBJ/STL/GLTF/3MF)").requiredOption("--task-id <id>", "Tripo task ID from generate model").requiredOption("--format <fmt>", "Target format: FBX, USDZ, OBJ, STL, GLTF, 3MF").option("--quad", "Enable quad remeshing").option("--face-limit <n>", "Max face count").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
840
|
+
try {
|
|
841
|
+
const ctx = createContext(this);
|
|
842
|
+
const params = {
|
|
843
|
+
format: options.format
|
|
844
|
+
};
|
|
845
|
+
if (options.quad) params.quad = true;
|
|
846
|
+
if (options.faceLimit) params.face_limit = Number(options.faceLimit);
|
|
847
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
848
|
+
task_id: options.taskId,
|
|
849
|
+
operation: "convert",
|
|
850
|
+
params
|
|
851
|
+
});
|
|
852
|
+
const localPath = await saveProcess3dOutput(data, "convert", options.outputDir, options.format);
|
|
853
|
+
if (localPath) data.local_path = localPath;
|
|
854
|
+
printSuccess("process3d.convert", data, ctx);
|
|
855
|
+
} catch (error2) {
|
|
856
|
+
printError("process3d.convert", error2);
|
|
857
|
+
}
|
|
858
|
+
})
|
|
859
|
+
);
|
|
860
|
+
command.addCommand(
|
|
861
|
+
new Command6("texture").description("Re-texture a 3D model with new materials").requiredOption("--task-id <id>", "Tripo task ID").option("--prompt <text>", "Texture description prompt").option("--pbr", "Enable PBR materials").option("--quality <q>", "Texture quality: standard or detailed").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
862
|
+
try {
|
|
863
|
+
const ctx = createContext(this);
|
|
864
|
+
const params = {};
|
|
865
|
+
if (options.prompt) params.prompt = options.prompt;
|
|
866
|
+
if (options.pbr) params.pbr = true;
|
|
867
|
+
if (options.quality) params.quality = options.quality;
|
|
868
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
869
|
+
task_id: options.taskId,
|
|
870
|
+
operation: "texture",
|
|
871
|
+
params
|
|
872
|
+
});
|
|
873
|
+
const localPath = await saveProcess3dOutput(data, "texture", options.outputDir);
|
|
874
|
+
if (localPath) data.local_path = localPath;
|
|
875
|
+
printSuccess("process3d.texture", data, ctx);
|
|
876
|
+
} catch (error2) {
|
|
877
|
+
printError("process3d.texture", error2);
|
|
878
|
+
}
|
|
879
|
+
})
|
|
880
|
+
);
|
|
881
|
+
command.addCommand(
|
|
882
|
+
new Command6("rig").description("Auto-rig a 3D model (add skeleton for animation)").requiredOption("--task-id <id>", "Tripo task ID").option("--format <fmt>", "Output format: glb or fbx", "glb").option("--spec <spec>", "Rig spec: mixamo or tripo", "mixamo").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
883
|
+
try {
|
|
884
|
+
const ctx = createContext(this);
|
|
885
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
886
|
+
task_id: options.taskId,
|
|
887
|
+
operation: "rig",
|
|
888
|
+
params: {
|
|
889
|
+
format: options.format,
|
|
890
|
+
spec: options.spec
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
const localPath = await saveProcess3dOutput(data, "rig", options.outputDir, options.format);
|
|
894
|
+
if (localPath) data.local_path = localPath;
|
|
895
|
+
printSuccess("process3d.rig", data, ctx);
|
|
896
|
+
} catch (error2) {
|
|
897
|
+
printError("process3d.rig", error2);
|
|
898
|
+
}
|
|
899
|
+
})
|
|
900
|
+
);
|
|
901
|
+
command.addCommand(
|
|
902
|
+
new Command6("animate").description("Apply preset animation to a rigged model").requiredOption("--task-id <id>", "Tripo task ID (from rig step)").requiredOption("--animation <preset>", "Animation preset (e.g. preset:walk, preset:idle, preset:run)").option("--format <fmt>", "Output format: glb or fbx", "glb").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
903
|
+
try {
|
|
904
|
+
const ctx = createContext(this);
|
|
905
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
906
|
+
task_id: options.taskId,
|
|
907
|
+
operation: "animate",
|
|
908
|
+
params: {
|
|
909
|
+
animation: options.animation,
|
|
910
|
+
format: options.format
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
const localPath = await saveProcess3dOutput(data, "animate", options.outputDir, options.format);
|
|
914
|
+
if (localPath) data.local_path = localPath;
|
|
915
|
+
printSuccess("process3d.animate", data, ctx);
|
|
916
|
+
} catch (error2) {
|
|
917
|
+
printError("process3d.animate", error2);
|
|
918
|
+
}
|
|
919
|
+
})
|
|
920
|
+
);
|
|
921
|
+
command.addCommand(
|
|
922
|
+
new Command6("reduce").description("Reduce polygon count (high-poly to low-poly)").requiredOption("--task-id <id>", "Tripo task ID").option("--face-limit <n>", "Target face count").option("--quad", "Use quad topology").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
923
|
+
try {
|
|
924
|
+
const ctx = createContext(this);
|
|
925
|
+
const params = {};
|
|
926
|
+
if (options.faceLimit) params.face_limit = Number(options.faceLimit);
|
|
927
|
+
if (options.quad) params.quad = true;
|
|
928
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
929
|
+
task_id: options.taskId,
|
|
930
|
+
operation: "reduce",
|
|
931
|
+
params
|
|
932
|
+
});
|
|
933
|
+
const localPath = await saveProcess3dOutput(data, "reduce", options.outputDir);
|
|
934
|
+
if (localPath) data.local_path = localPath;
|
|
935
|
+
printSuccess("process3d.reduce", data, ctx);
|
|
936
|
+
} catch (error2) {
|
|
937
|
+
printError("process3d.reduce", error2);
|
|
938
|
+
}
|
|
939
|
+
})
|
|
940
|
+
);
|
|
941
|
+
command.addCommand(
|
|
942
|
+
new Command6("stylize").description("Apply artistic style to a model").requiredOption("--task-id <id>", "Tripo task ID").requiredOption("--style <style>", "Style: lego, voxel, voronoi, minecraft").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
943
|
+
try {
|
|
944
|
+
const ctx = createContext(this);
|
|
945
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
946
|
+
task_id: options.taskId,
|
|
947
|
+
operation: "stylize",
|
|
948
|
+
params: {
|
|
949
|
+
style: options.style
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
const localPath = await saveProcess3dOutput(data, "stylize", options.outputDir);
|
|
953
|
+
if (localPath) data.local_path = localPath;
|
|
954
|
+
printSuccess("process3d.stylize", data, ctx);
|
|
955
|
+
} catch (error2) {
|
|
956
|
+
printError("process3d.stylize", error2);
|
|
957
|
+
}
|
|
958
|
+
})
|
|
959
|
+
);
|
|
960
|
+
command.addCommand(
|
|
961
|
+
new Command6("segment").description("Segment mesh into logical parts").requiredOption("--task-id <id>", "Tripo task ID").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
962
|
+
try {
|
|
963
|
+
const ctx = createContext(this);
|
|
964
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
965
|
+
task_id: options.taskId,
|
|
966
|
+
operation: "segment",
|
|
967
|
+
params: {}
|
|
968
|
+
});
|
|
969
|
+
const localPath = await saveProcess3dOutput(data, "segment", options.outputDir);
|
|
970
|
+
if (localPath) data.local_path = localPath;
|
|
971
|
+
printSuccess("process3d.segment", data, ctx);
|
|
972
|
+
} catch (error2) {
|
|
973
|
+
printError("process3d.segment", error2);
|
|
974
|
+
}
|
|
975
|
+
})
|
|
976
|
+
);
|
|
977
|
+
command.addCommand(
|
|
978
|
+
new Command6("prerigcheck").description("Check if a model can be rigged").requiredOption("--task-id <id>", "Tripo task ID").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
|
|
979
|
+
try {
|
|
980
|
+
const ctx = createContext(this);
|
|
981
|
+
const data = await ctx.client.post("/api/process3d", {
|
|
982
|
+
task_id: options.taskId,
|
|
983
|
+
operation: "prerigcheck",
|
|
984
|
+
params: {}
|
|
985
|
+
});
|
|
986
|
+
const localPath = await saveProcess3dOutput(data, "prerigcheck", options.outputDir);
|
|
987
|
+
if (localPath) data.local_path = localPath;
|
|
988
|
+
printSuccess("process3d.prerigcheck", data, ctx);
|
|
989
|
+
} catch (error2) {
|
|
990
|
+
printError("process3d.prerigcheck", error2);
|
|
991
|
+
}
|
|
992
|
+
})
|
|
993
|
+
);
|
|
994
|
+
return command;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// src/commands/provider.ts
|
|
998
|
+
import { Command as Command7 } from "commander";
|
|
794
999
|
function createProviderCommand() {
|
|
795
|
-
const command = new
|
|
1000
|
+
const command = new Command7("provider").description("Provider management");
|
|
796
1001
|
command.addCommand(
|
|
797
|
-
new
|
|
1002
|
+
new Command7("list").description("List available providers").action(async function() {
|
|
798
1003
|
try {
|
|
799
1004
|
const ctx = createContext(this);
|
|
800
1005
|
const data = await ctx.client.get("/api/providers");
|
|
@@ -805,7 +1010,7 @@ function createProviderCommand() {
|
|
|
805
1010
|
})
|
|
806
1011
|
);
|
|
807
1012
|
command.addCommand(
|
|
808
|
-
new
|
|
1013
|
+
new Command7("health").description("Check provider health").argument("[name]", "Specific provider name").action(async function(name) {
|
|
809
1014
|
try {
|
|
810
1015
|
const ctx = createContext(this);
|
|
811
1016
|
const path = name ? `/api/providers/${encodeURIComponent(name)}/health` : "/api/providers/health";
|
|
@@ -820,11 +1025,11 @@ function createProviderCommand() {
|
|
|
820
1025
|
}
|
|
821
1026
|
|
|
822
1027
|
// src/commands/upload.ts
|
|
823
|
-
import { Command as
|
|
1028
|
+
import { Command as Command8 } from "commander";
|
|
824
1029
|
function createUploadCommand() {
|
|
825
|
-
const command = new
|
|
1030
|
+
const command = new Command8("upload").description("Upload and manage assets");
|
|
826
1031
|
command.addCommand(
|
|
827
|
-
new
|
|
1032
|
+
new Command8("file").description("Upload a file and get a public URL").argument("<path>", "Path to file to upload").action(async function(filePath) {
|
|
828
1033
|
const ctx = createContext(this);
|
|
829
1034
|
try {
|
|
830
1035
|
const data = await ctx.client.uploadFile(filePath);
|
|
@@ -835,7 +1040,7 @@ function createUploadCommand() {
|
|
|
835
1040
|
})
|
|
836
1041
|
);
|
|
837
1042
|
command.addCommand(
|
|
838
|
-
new
|
|
1043
|
+
new Command8("list").description("List uploaded assets").action(async function() {
|
|
839
1044
|
const ctx = createContext(this);
|
|
840
1045
|
try {
|
|
841
1046
|
const data = await ctx.client.get("/api/assets");
|
|
@@ -846,7 +1051,7 @@ function createUploadCommand() {
|
|
|
846
1051
|
})
|
|
847
1052
|
);
|
|
848
1053
|
command.addCommand(
|
|
849
|
-
new
|
|
1054
|
+
new Command8("delete").description("Delete an uploaded asset (admin only)").argument("<filename>", "Filename to delete").action(async function(filename) {
|
|
850
1055
|
const ctx = createContext(this);
|
|
851
1056
|
try {
|
|
852
1057
|
const data = await ctx.client.delete(`/api/assets/${encodeURIComponent(filename)}`);
|
|
@@ -860,13 +1065,14 @@ function createUploadCommand() {
|
|
|
860
1065
|
}
|
|
861
1066
|
|
|
862
1067
|
// src/index.ts
|
|
863
|
-
var program = new
|
|
1068
|
+
var program = new Command9().name("asset-gateway").description("Universal asset generation gateway CLI").version(CLI_VERSION).option(
|
|
864
1069
|
"--gateway-url <url>",
|
|
865
1070
|
`Gateway URL (default: $ASSET_GATEWAY_URL, auth config, or ${DEFAULT_GATEWAY_URL})`
|
|
866
1071
|
).option("--token <token>", "API token for authentication").option("--human", "Human-readable output instead of JSON").option("--fields <fields>", "Comma-separated list of output fields");
|
|
867
1072
|
program.addCommand(createAuthCommand());
|
|
868
1073
|
program.addCommand(createGenerateCommand());
|
|
869
1074
|
program.addCommand(createProcessCommand());
|
|
1075
|
+
program.addCommand(createProcess3dCommand());
|
|
870
1076
|
program.addCommand(createProviderCommand());
|
|
871
1077
|
program.addCommand(createUploadCommand());
|
|
872
1078
|
program.addCommand(createJobCommand());
|