@optima-chat/comfy-cli 0.9.8 → 0.9.9
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/.claude/settings.local.json +19 -1
- package/dist/commands/tryon.d.ts +3 -0
- package/dist/commands/tryon.d.ts.map +1 -0
- package/dist/commands/tryon.js +170 -0
- package/dist/commands/tryon.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/services/config.d.ts +4 -0
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +2 -0
- package/dist/services/config.js.map +1 -1
- package/dist/services/fashn-api.d.ts +57 -0
- package/dist/services/fashn-api.d.ts.map +1 -0
- package/dist/services/fashn-api.js +84 -0
- package/dist/services/fashn-api.js.map +1 -0
- package/package.json +1 -1
|
@@ -72,7 +72,25 @@
|
|
|
72
72
|
"Bash(infisical secrets:*)",
|
|
73
73
|
"Bash(git status:*)",
|
|
74
74
|
"Bash(gh pr:*)",
|
|
75
|
-
"Bash(git merge:*)"
|
|
75
|
+
"Bash(git merge:*)",
|
|
76
|
+
"WebFetch(domain:docs.fashn.ai)",
|
|
77
|
+
"WebFetch(domain:fashn.ai)",
|
|
78
|
+
"Bash(head -50 /Users/verypro/comfy-cli/tests/*.test.ts)",
|
|
79
|
+
"Bash(curl -s https://raw.githubusercontent.com/fashn-AI/tryon-nextjs-app/main/README.md)",
|
|
80
|
+
"Bash(curl -s https://raw.githubusercontent.com/fashn-AI/tryon-gradio-app/main/README.md)",
|
|
81
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-nextjs-app/contents/)",
|
|
82
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-gradio-app/contents/)",
|
|
83
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-nextjs-app/contents/public)",
|
|
84
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-nextjs-app/contents/src)",
|
|
85
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-gradio-app/contents/assets)",
|
|
86
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-nextjs-app/contents/public/models)",
|
|
87
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-nextjs-app/contents/public/garments)",
|
|
88
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-gradio-app/contents/assets/models)",
|
|
89
|
+
"Bash(curl -s https://api.github.com/repos/fashn-AI/tryon-gradio-app/contents/assets/garments)",
|
|
90
|
+
"Bash(curl -sL \"https://raw.githubusercontent.com/fashn-AI/tryon-gradio-app/master/assets/models/fashn-ai-model.jpeg\" -o /tmp/tryon_model.jpeg)",
|
|
91
|
+
"Bash(curl -sL \"https://raw.githubusercontent.com/fashn-AI/tryon-gradio-app/master/assets/garments/fashn-ai-t.png\" -o /tmp/tryon_garment.png)",
|
|
92
|
+
"Bash(magick /tmp/tryon_model.jpeg /tmp/tryon_garment.png /Users/verypro/comfy-cli/comfy-output/tryon_1773922873475_0.png -resize x800 +append /tmp/tryon_comparison.png)",
|
|
93
|
+
"Bash(open /tmp/tryon_comparison.png)"
|
|
76
94
|
],
|
|
77
95
|
"deny": [],
|
|
78
96
|
"ask": []
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tryon.d.ts","sourceRoot":"","sources":["../../src/commands/tryon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QA6KpD"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { success, info } from '../utils/logger.js';
|
|
4
|
+
import { outputSuccess, outputError, isPrettyMode } from '../utils/output.js';
|
|
5
|
+
import { addEnhancedHelp } from '../utils/helpText.js';
|
|
6
|
+
import { getConfigValue } from '../services/config.js';
|
|
7
|
+
import { FashnClient } from '../services/fashn-api.js';
|
|
8
|
+
export function registerTryonCommand(program) {
|
|
9
|
+
const cmd = program
|
|
10
|
+
.command('tryon')
|
|
11
|
+
.description('虚拟试穿 (Virtual Try-On) - 使用 FASHN AI tryon-v1.6')
|
|
12
|
+
.argument('<model_image>', '人物照片路径或 URL')
|
|
13
|
+
.argument('<garment_image>', '服装照片路径或 URL')
|
|
14
|
+
.option('-o, --output <path>', '输出文件路径', '')
|
|
15
|
+
.option('-c, --category <type>', '服装类别: auto, tops, bottoms, one-pieces', 'auto')
|
|
16
|
+
.option('-m, --mode <mode>', '生成模式: performance (~7s), balanced (~9s), quality (~13s)', 'quality')
|
|
17
|
+
.option('--garment-type <type>', '服装照片类型: auto, flat-lay, model', 'auto')
|
|
18
|
+
.option('-n, --num-samples <n>', '生成数量 (1-4)', '1')
|
|
19
|
+
.option('--format <fmt>', '输出格式: png, jpeg', 'png')
|
|
20
|
+
.option('--seed <n>', '随机种子(用于复现)')
|
|
21
|
+
.action(async (modelImage, garmentImage, options) => {
|
|
22
|
+
const pretty = isPrettyMode(options);
|
|
23
|
+
try {
|
|
24
|
+
// 获取 API Key
|
|
25
|
+
const apiKey = process.env.FASHN_API_KEY || getConfigValue('fashn.apiKey');
|
|
26
|
+
if (!apiKey) {
|
|
27
|
+
outputError('API_KEY_MISSING', '请设置 FASHN_API_KEY 环境变量或运行: comfy config set fashn.apiKey <key>', options);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const client = new FashnClient(apiKey);
|
|
31
|
+
// 处理图像输入:本地文件转 base64,URL 直接使用
|
|
32
|
+
const resolveImage = async (input) => {
|
|
33
|
+
if (input.startsWith('http://') || input.startsWith('https://')) {
|
|
34
|
+
return input;
|
|
35
|
+
}
|
|
36
|
+
return client.imageToBase64(input);
|
|
37
|
+
};
|
|
38
|
+
const [modelImg, garmentImg] = await Promise.all([
|
|
39
|
+
resolveImage(modelImage),
|
|
40
|
+
resolveImage(garmentImage),
|
|
41
|
+
]);
|
|
42
|
+
const numSamples = parseInt(options.numSamples, 10);
|
|
43
|
+
const outputDir = getConfigValue('outputDir') || './comfy-output';
|
|
44
|
+
const startTime = Date.now();
|
|
45
|
+
if (pretty) {
|
|
46
|
+
const spinner = ora(`正在提交虚拟试穿任务 (${options.mode} 模式)...`).start();
|
|
47
|
+
try {
|
|
48
|
+
const runResult = await client.run({
|
|
49
|
+
model_image: modelImg,
|
|
50
|
+
garment_image: garmentImg,
|
|
51
|
+
category: options.category,
|
|
52
|
+
mode: options.mode,
|
|
53
|
+
garment_photo_type: options.garmentType,
|
|
54
|
+
num_samples: numSamples,
|
|
55
|
+
output_format: options.format,
|
|
56
|
+
seed: options.seed ? parseInt(options.seed, 10) : undefined,
|
|
57
|
+
});
|
|
58
|
+
spinner.text = `任务已提交 (${runResult.id}),等待生成...`;
|
|
59
|
+
const result = await client.poll(runResult.id, {
|
|
60
|
+
onProgress: (status) => {
|
|
61
|
+
spinner.text = `状态: ${status}...`;
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
// 下载输出图像
|
|
65
|
+
const outputs = [];
|
|
66
|
+
if (result.output) {
|
|
67
|
+
spinner.text = '正在下载结果图像...';
|
|
68
|
+
for (let i = 0; i < result.output.length; i++) {
|
|
69
|
+
const outputPath = options.output && result.output.length === 1
|
|
70
|
+
? path.resolve(options.output)
|
|
71
|
+
: path.resolve(outputDir, `tryon_${Date.now()}_${i}.${options.format}`);
|
|
72
|
+
const saved = await client.downloadImage(result.output[i], path.dirname(outputPath), path.basename(outputPath));
|
|
73
|
+
outputs.push(saved);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const durationMs = Date.now() - startTime;
|
|
77
|
+
spinner.succeed('虚拟试穿完成!');
|
|
78
|
+
for (const out of outputs) {
|
|
79
|
+
success(`输出文件: ${out}`);
|
|
80
|
+
}
|
|
81
|
+
info(`模式: ${options.mode}, 类别: ${options.category}, 耗时: ${(durationMs / 1000).toFixed(1)}s`);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
spinner.fail(`试穿失败: ${err?.message || err}`);
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const runResult = await client.run({
|
|
90
|
+
model_image: modelImg,
|
|
91
|
+
garment_image: garmentImg,
|
|
92
|
+
category: options.category,
|
|
93
|
+
mode: options.mode,
|
|
94
|
+
garment_photo_type: options.garmentType,
|
|
95
|
+
num_samples: numSamples,
|
|
96
|
+
output_format: options.format,
|
|
97
|
+
seed: options.seed ? parseInt(options.seed, 10) : undefined,
|
|
98
|
+
});
|
|
99
|
+
const result = await client.poll(runResult.id);
|
|
100
|
+
// 下载输出图像
|
|
101
|
+
const outputs = [];
|
|
102
|
+
if (result.output) {
|
|
103
|
+
for (let i = 0; i < result.output.length; i++) {
|
|
104
|
+
const outputPath = options.output && result.output.length === 1
|
|
105
|
+
? path.resolve(options.output)
|
|
106
|
+
: path.resolve(outputDir, `tryon_${Date.now()}_${i}.${options.format}`);
|
|
107
|
+
const saved = await client.downloadImage(result.output[i], path.dirname(outputPath), path.basename(outputPath));
|
|
108
|
+
outputs.push(saved);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const durationMs = Date.now() - startTime;
|
|
112
|
+
outputSuccess({
|
|
113
|
+
id: runResult.id,
|
|
114
|
+
outputs,
|
|
115
|
+
mode: options.mode,
|
|
116
|
+
category: options.category,
|
|
117
|
+
numSamples,
|
|
118
|
+
durationMs,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
outputError('TRYON_FAILED', `虚拟试穿失败: ${err}`, options);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
addEnhancedHelp(cmd, {
|
|
127
|
+
examples: [
|
|
128
|
+
'# 基本用法 - 本地图片试穿',
|
|
129
|
+
'$ comfy tryon person.jpg garment.jpg',
|
|
130
|
+
'',
|
|
131
|
+
'# 使用 URL 图片',
|
|
132
|
+
'$ comfy tryon https://example.com/model.jpg https://example.com/dress.jpg',
|
|
133
|
+
'',
|
|
134
|
+
'# 指定服装类别和生成模式',
|
|
135
|
+
'$ comfy tryon person.jpg top.jpg -c tops -m performance',
|
|
136
|
+
'',
|
|
137
|
+
'# 生成多张结果',
|
|
138
|
+
'$ comfy tryon person.jpg dress.jpg -n 4 -c one-pieces',
|
|
139
|
+
'',
|
|
140
|
+
'# 指定输出路径',
|
|
141
|
+
'$ comfy tryon person.jpg garment.jpg -o result.png',
|
|
142
|
+
'',
|
|
143
|
+
'# 使用种子复现结果',
|
|
144
|
+
'$ comfy tryon person.jpg garment.jpg --seed 42',
|
|
145
|
+
],
|
|
146
|
+
outputJson: `{
|
|
147
|
+
"success": true,
|
|
148
|
+
"data": {
|
|
149
|
+
"id": "abc123",
|
|
150
|
+
"outputs": ["./comfy-output/tryon_1234567890_0.png"],
|
|
151
|
+
"mode": "quality",
|
|
152
|
+
"category": "auto",
|
|
153
|
+
"numSamples": 1,
|
|
154
|
+
"durationMs": 13000
|
|
155
|
+
}
|
|
156
|
+
}`,
|
|
157
|
+
relatedCommands: [
|
|
158
|
+
{ command: 'image generate <prompt>', description: '文本生成图像' },
|
|
159
|
+
{ command: 'config set fashn.apiKey <key>', description: '设置 FASHN API Key' },
|
|
160
|
+
],
|
|
161
|
+
notes: [
|
|
162
|
+
'使用 FASHN AI tryon-v1.6 模型',
|
|
163
|
+
'支持本地图片路径和 URL',
|
|
164
|
+
'服装类别: auto (自动检测), tops (上装), bottoms (下装), one-pieces (连体)',
|
|
165
|
+
'生成模式: performance (~7s), balanced (~9s), quality (~13s)',
|
|
166
|
+
'设置 FASHN_API_KEY 环境变量或 comfy config set fashn.apiKey',
|
|
167
|
+
],
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=tryon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tryon.js","sourceRoot":"","sources":["../../src/commands/tryon.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAmD,MAAM,0BAA0B,CAAC;AAExG,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,GAAG,GAAG,OAAO;SAChB,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,gDAAgD,CAAC;SAC7D,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;SACxC,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC;SAC1C,MAAM,CAAC,qBAAqB,EAAE,QAAQ,EAAE,EAAE,CAAC;SAC3C,MAAM,CAAC,uBAAuB,EAAE,uCAAuC,EAAE,MAAM,CAAC;SAChF,MAAM,CAAC,mBAAmB,EAAE,yDAAyD,EAAE,SAAS,CAAC;SACjG,MAAM,CAAC,uBAAuB,EAAE,+BAA+B,EAAE,MAAM,CAAC;SACxE,MAAM,CAAC,uBAAuB,EAAE,YAAY,EAAE,GAAG,CAAC;SAClD,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,KAAK,CAAC;SAClD,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC;SAClC,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,YAAoB,EAAE,OAAO,EAAE,EAAE;QAClE,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QAErC,IAAI,CAAC;YACH,aAAa;YACb,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,cAAc,CAAC,cAAc,CAAC,CAAC;YAC3E,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,WAAW,CAAC,iBAAiB,EAAE,gEAAgE,EAAE,OAAO,CAAC,CAAC;gBAC1G,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;YAEvC,+BAA+B;YAC/B,MAAM,YAAY,GAAG,KAAK,EAAE,KAAa,EAAmB,EAAE;gBAC5D,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChE,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACrC,CAAC,CAAC;YAEF,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC/C,YAAY,CAAC,UAAU,CAAC;gBACxB,YAAY,CAAC,YAAY,CAAC;aAC3B,CAAC,CAAC;YAEH,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,CAAC,IAAI,gBAAgB,CAAC;YAClE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAE7B,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,OAAO,CAAC,IAAI,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC;gBAElE,IAAI,CAAC;oBACH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC;wBACjC,WAAW,EAAE,QAAQ;wBACrB,aAAa,EAAE,UAAU;wBACzB,QAAQ,EAAE,OAAO,CAAC,QAAyB;wBAC3C,IAAI,EAAE,OAAO,CAAC,IAAiB;wBAC/B,kBAAkB,EAAE,OAAO,CAAC,WAAoC;wBAChE,WAAW,EAAE,UAAU;wBACvB,aAAa,EAAE,OAAO,CAAC,MAAM;wBAC7B,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;qBAC5D,CAAC,CAAC;oBAEH,OAAO,CAAC,IAAI,GAAG,UAAU,SAAS,CAAC,EAAE,WAAW,CAAC;oBAEjD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE;wBAC7C,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE;4BACrB,OAAO,CAAC,IAAI,GAAG,OAAO,MAAM,KAAK,CAAC;wBACpC,CAAC;qBACF,CAAC,CAAC;oBAEH,SAAS;oBACT,MAAM,OAAO,GAAa,EAAE,CAAC;oBAC7B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wBAClB,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC;wBAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;4BAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;gCAC7D,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;gCAC9B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;4BAC1E,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;4BAChH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;wBACtB,CAAC;oBACH,CAAC;oBAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBAC1C,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;oBAC3B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;wBAC1B,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;oBAC1B,CAAC;oBACD,IAAI,CAAC,OAAO,OAAO,CAAC,IAAI,SAAS,OAAO,CAAC,QAAQ,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC/F,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;oBAC7C,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC;oBACjC,WAAW,EAAE,QAAQ;oBACrB,aAAa,EAAE,UAAU;oBACzB,QAAQ,EAAE,OAAO,CAAC,QAAyB;oBAC3C,IAAI,EAAE,OAAO,CAAC,IAAiB;oBAC/B,kBAAkB,EAAE,OAAO,CAAC,WAAoC;oBAChE,WAAW,EAAE,UAAU;oBACvB,aAAa,EAAE,OAAO,CAAC,MAAM;oBAC7B,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;iBAC5D,CAAC,CAAC;gBAEH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBAE/C,SAAS;gBACT,MAAM,OAAO,GAAa,EAAE,CAAC;gBAC7B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;4BAC7D,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;4BAC9B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;wBAC1E,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;wBAChH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACtB,CAAC;gBACH,CAAC;gBAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;gBAC1C,aAAa,CAAC;oBACZ,EAAE,EAAE,SAAS,CAAC,EAAE;oBAChB,OAAO;oBACP,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,UAAU;oBACV,UAAU;iBACX,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,cAAc,EAAE,WAAW,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,eAAe,CAAC,GAAG,EAAE;QACnB,QAAQ,EAAE;YACR,iBAAiB;YACjB,sCAAsC;YACtC,EAAE;YACF,aAAa;YACb,2EAA2E;YAC3E,EAAE;YACF,eAAe;YACf,yDAAyD;YACzD,EAAE;YACF,UAAU;YACV,uDAAuD;YACvD,EAAE;YACF,UAAU;YACV,oDAAoD;YACpD,EAAE;YACF,YAAY;YACZ,gDAAgD;SACjD;QACD,UAAU,EAAE;;;;;;;;;;EAUd;QACE,eAAe,EAAE;YACf,EAAE,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,QAAQ,EAAE;YAC7D,EAAE,OAAO,EAAE,+BAA+B,EAAE,WAAW,EAAE,kBAAkB,EAAE;SAC9E;QACD,KAAK,EAAE;YACL,2BAA2B;YAC3B,eAAe;YACf,6DAA6D;YAC7D,yDAAyD;YACzD,sDAAsD;SACvD;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import { registerInterruptCommand } from './commands/interrupt.js';
|
|
|
19
19
|
import { registerInitCommand } from './commands/init.js';
|
|
20
20
|
import { registerTtsCommand } from './commands/tts.js';
|
|
21
21
|
import { registerAsrCommand } from './commands/asr.js';
|
|
22
|
+
import { registerTryonCommand } from './commands/tryon.js';
|
|
22
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
23
24
|
const __dirname = dirname(__filename);
|
|
24
25
|
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
@@ -68,6 +69,7 @@ registerEditCommand(program);
|
|
|
68
69
|
registerVideoCommand(program);
|
|
69
70
|
registerTtsCommand(program);
|
|
70
71
|
registerAsrCommand(program);
|
|
72
|
+
registerTryonCommand(program);
|
|
71
73
|
registerDownloadCommand(program);
|
|
72
74
|
// 注册核心命令
|
|
73
75
|
registerWorkflowCommand(program);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,9 @@ export interface DashScopeConfig {
|
|
|
15
15
|
export interface GroqConfig {
|
|
16
16
|
apiKey?: string;
|
|
17
17
|
}
|
|
18
|
+
export interface FashnConfig {
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
}
|
|
18
21
|
export interface ComfyConfig {
|
|
19
22
|
server: string;
|
|
20
23
|
timeout: number;
|
|
@@ -23,6 +26,7 @@ export interface ComfyConfig {
|
|
|
23
26
|
bfl: BFLConfig;
|
|
24
27
|
dashscope: DashScopeConfig;
|
|
25
28
|
groq: GroqConfig;
|
|
29
|
+
fashn: FashnConfig;
|
|
26
30
|
preferBackend: 'auto' | 'bfl' | 'comfyui';
|
|
27
31
|
preferVideoBackend: 'auto' | 'dashscope' | 'comfyui';
|
|
28
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/services/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,SAAS,CAAC;IACf,SAAS,EAAE,eAAe,CAAC;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IAC1C,kBAAkB,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;CACtD;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/services/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,SAAS,CAAC;IACf,SAAS,EAAE,eAAe,CAAC;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IAC1C,kBAAkB,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;CACtD;AAwBD,eAAO,MAAM,MAAM,mBAGjB,CAAC;AAEH,wBAAgB,SAAS,IAAI,WAAW,CAEvC;AAGD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAEvD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAE/C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAGD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAqBrD"}
|
package/dist/services/config.js
CHANGED
|
@@ -16,6 +16,7 @@ const defaultConfig = {
|
|
|
16
16
|
shotType: 'single',
|
|
17
17
|
},
|
|
18
18
|
groq: {},
|
|
19
|
+
fashn: {},
|
|
19
20
|
preferBackend: 'auto',
|
|
20
21
|
preferVideoBackend: 'auto',
|
|
21
22
|
};
|
|
@@ -56,6 +57,7 @@ export function isValidConfigKey(key) {
|
|
|
56
57
|
'dashscope.audio',
|
|
57
58
|
'dashscope.shotType',
|
|
58
59
|
'groq.apiKey',
|
|
60
|
+
'fashn.apiKey',
|
|
59
61
|
'preferBackend',
|
|
60
62
|
'preferVideoBackend',
|
|
61
63
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/services/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/services/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAsCxB,MAAM,aAAa,GAAgB;IACjC,MAAM,EAAE,6BAA6B;IACrC,OAAO,EAAE,MAAM;IACf,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,gBAAgB;IAC3B,GAAG,EAAE;QACH,eAAe,EAAE,CAAC;QAClB,YAAY,EAAE,KAAK;KACpB;IACD,SAAS,EAAE;QACT,UAAU,EAAE,OAAO;QACnB,QAAQ,EAAE,CAAC;QACX,YAAY,EAAE,IAAI;QAClB,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,QAAQ;KACnB;IACD,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,aAAa,EAAE,MAAM;IACrB,kBAAkB,EAAE,MAAM;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAc;IAC1C,WAAW,EAAE,WAAW;IACxB,QAAQ,EAAE,aAAa;CACxB,CAAC,CAAC;AAEH,MAAM,UAAU,SAAS;IACvB,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,KAAU;IAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,CAAC,MAAM,CAAC,GAAwB,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC;AAED,YAAY;AACZ,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,SAAS,GAAG;QAChB,QAAQ;QACR,SAAS;QACT,aAAa;QACb,WAAW;QACX,YAAY;QACZ,qBAAqB;QACrB,kBAAkB;QAClB,kBAAkB;QAClB,sBAAsB;QACtB,oBAAoB;QACpB,wBAAwB;QACxB,iBAAiB;QACjB,oBAAoB;QACpB,aAAa;QACb,cAAc;QACd,eAAe;QACf,oBAAoB;KACrB,CAAC;IACF,OAAO,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export type TryonCategory = 'auto' | 'tops' | 'bottoms' | 'one-pieces';
|
|
2
|
+
export type TryonMode = 'performance' | 'balanced' | 'quality';
|
|
3
|
+
export type TryonGarmentPhotoType = 'auto' | 'flat-lay' | 'model';
|
|
4
|
+
export interface TryonParams {
|
|
5
|
+
model_image: string;
|
|
6
|
+
garment_image: string;
|
|
7
|
+
category?: TryonCategory;
|
|
8
|
+
mode?: TryonMode;
|
|
9
|
+
garment_photo_type?: TryonGarmentPhotoType;
|
|
10
|
+
num_samples?: number;
|
|
11
|
+
output_format?: 'png' | 'jpeg';
|
|
12
|
+
seed?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface FashnRunResponse {
|
|
15
|
+
id: string;
|
|
16
|
+
status: string;
|
|
17
|
+
}
|
|
18
|
+
export interface FashnStatusResponse {
|
|
19
|
+
id: string;
|
|
20
|
+
status: 'starting' | 'processing' | 'completed' | 'failed';
|
|
21
|
+
output?: string[];
|
|
22
|
+
error?: {
|
|
23
|
+
name: string;
|
|
24
|
+
message: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface PollOptions {
|
|
28
|
+
interval?: number;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
onProgress?: (status: string) => void;
|
|
31
|
+
}
|
|
32
|
+
export declare class FashnClient {
|
|
33
|
+
private client;
|
|
34
|
+
constructor(apiKey: string);
|
|
35
|
+
/**
|
|
36
|
+
* 提交虚拟试穿任务
|
|
37
|
+
*/
|
|
38
|
+
run(params: TryonParams): Promise<FashnRunResponse>;
|
|
39
|
+
/**
|
|
40
|
+
* 获取任务状态
|
|
41
|
+
*/
|
|
42
|
+
getStatus(id: string): Promise<FashnStatusResponse>;
|
|
43
|
+
/**
|
|
44
|
+
* 轮询等待结果
|
|
45
|
+
*/
|
|
46
|
+
poll(id: string, options?: PollOptions): Promise<FashnStatusResponse>;
|
|
47
|
+
/**
|
|
48
|
+
* 将本地图像转换为 base64 data URL
|
|
49
|
+
*/
|
|
50
|
+
imageToBase64(filePath: string): Promise<string>;
|
|
51
|
+
/**
|
|
52
|
+
* 下载图像到本地
|
|
53
|
+
*/
|
|
54
|
+
downloadImage(url: string, outputDir: string, filename?: string): Promise<string>;
|
|
55
|
+
private sleep;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=fashn-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fashn-api.d.ts","sourceRoot":"","sources":["../../src/services/fashn-api.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,CAAC;AAC/D,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kBAAkB,CAAC,EAAE,qBAAqB,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC3D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,MAAM;IAW1B;;OAEG;IACG,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAQzD;;OAEG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAKzD;;OAEG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA8B/E;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAStD;;OAEG;IACG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAevF,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
export class FashnClient {
|
|
5
|
+
client;
|
|
6
|
+
constructor(apiKey) {
|
|
7
|
+
this.client = axios.create({
|
|
8
|
+
baseURL: 'https://api.fashn.ai/v1',
|
|
9
|
+
headers: {
|
|
10
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
11
|
+
'Content-Type': 'application/json',
|
|
12
|
+
},
|
|
13
|
+
timeout: 120000,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 提交虚拟试穿任务
|
|
18
|
+
*/
|
|
19
|
+
async run(params) {
|
|
20
|
+
const response = await this.client.post('/run', {
|
|
21
|
+
model_name: 'tryon-v1.6',
|
|
22
|
+
inputs: params,
|
|
23
|
+
});
|
|
24
|
+
return response.data;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 获取任务状态
|
|
28
|
+
*/
|
|
29
|
+
async getStatus(id) {
|
|
30
|
+
const response = await this.client.get(`/status/${id}`);
|
|
31
|
+
return response.data;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 轮询等待结果
|
|
35
|
+
*/
|
|
36
|
+
async poll(id, options = {}) {
|
|
37
|
+
const { interval = 2000, timeout = 300000, onProgress, } = options;
|
|
38
|
+
const startTime = Date.now();
|
|
39
|
+
while (true) {
|
|
40
|
+
if (Date.now() - startTime > timeout) {
|
|
41
|
+
throw new Error('FASHN polling timeout exceeded');
|
|
42
|
+
}
|
|
43
|
+
const result = await this.getStatus(id);
|
|
44
|
+
onProgress?.(result.status);
|
|
45
|
+
if (result.status === 'completed') {
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
if (result.status === 'failed') {
|
|
49
|
+
const errMsg = result.error ? `${result.error.name}: ${result.error.message}` : 'Unknown error';
|
|
50
|
+
throw new Error(`FASHN try-on failed: ${errMsg}`);
|
|
51
|
+
}
|
|
52
|
+
await this.sleep(interval);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 将本地图像转换为 base64 data URL
|
|
57
|
+
*/
|
|
58
|
+
async imageToBase64(filePath) {
|
|
59
|
+
const absolutePath = path.resolve(filePath);
|
|
60
|
+
const buffer = await fs.readFile(absolutePath);
|
|
61
|
+
const base64 = buffer.toString('base64');
|
|
62
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
63
|
+
const mimeType = ext === '.png' ? 'image/png' : 'image/jpeg';
|
|
64
|
+
return `data:${mimeType};base64,${base64}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 下载图像到本地
|
|
68
|
+
*/
|
|
69
|
+
async downloadImage(url, outputDir, filename) {
|
|
70
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
71
|
+
const response = await axios.get(url, {
|
|
72
|
+
responseType: 'arraybuffer',
|
|
73
|
+
timeout: 120000,
|
|
74
|
+
});
|
|
75
|
+
const finalFilename = filename || `tryon_${Date.now()}.png`;
|
|
76
|
+
const outputPath = path.join(outputDir, finalFilename);
|
|
77
|
+
await fs.writeFile(outputPath, response.data);
|
|
78
|
+
return outputPath;
|
|
79
|
+
}
|
|
80
|
+
sleep(ms) {
|
|
81
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=fashn-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fashn-api.js","sourceRoot":"","sources":["../../src/services/fashn-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAsC7B,MAAM,OAAO,WAAW;IACd,MAAM,CAAgB;IAE9B,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YACzB,OAAO,EAAE,yBAAyB;YAClC,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,MAAM,EAAE;gBACnC,cAAc,EAAE,kBAAkB;aACnC;YACD,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,MAAmB;QAC3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE;YAC9C,UAAU,EAAE,YAAY;YACxB,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,UAAuB,EAAE;QAC9C,MAAM,EACJ,QAAQ,GAAG,IAAI,EACf,OAAO,GAAG,MAAM,EAChB,UAAU,GACX,GAAG,OAAO,CAAC;QAEZ,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACpD,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACxC,UAAU,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAE5B,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBAClC,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;gBAChG,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;YACpD,CAAC;YAED,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,QAAgB;QAClC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC;QAC7D,OAAO,QAAQ,QAAQ,WAAW,MAAM,EAAE,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,GAAW,EAAE,SAAiB,EAAE,QAAiB;QACnE,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YACpC,YAAY,EAAE,aAAa;YAC3B,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG,QAAQ,IAAI,SAAS,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACvD,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE9C,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,EAAU;QACtB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;CACF"}
|