@2515097216/jimeng-free-api 0.8.8 → 0.8.11

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.
@@ -31,10 +31,29 @@ var Environment = class {
31
31
  this.package = _package;
32
32
  }
33
33
  };
34
+ function loadPackageJson() {
35
+ const cwdPkgPath = path.join(process.cwd(), "package.json");
36
+ if (fs.pathExistsSync(cwdPkgPath)) {
37
+ return JSON.parse(fs.readFileSync(cwdPkgPath).toString());
38
+ }
39
+ const entryFile = process.argv[1];
40
+ const entryDir = entryFile ? path.dirname(entryFile) : process.cwd();
41
+ const candidates = [
42
+ path.resolve(entryDir, "../package.json"),
43
+ path.resolve(entryDir, "../../package.json"),
44
+ path.resolve(entryDir, "../../../package.json")
45
+ ];
46
+ for (const p of candidates) {
47
+ if (fs.pathExistsSync(p)) {
48
+ return JSON.parse(fs.readFileSync(p).toString());
49
+ }
50
+ }
51
+ return {};
52
+ }
34
53
  var environment_default = new Environment({
35
54
  cmdArgs,
36
55
  envVars,
37
- package: JSON.parse(fs.readFileSync(path.join(path.resolve(), "package.json")).toString())
56
+ package: loadPackageJson()
38
57
  });
39
58
 
40
59
  // src/lib/configs/service-config.ts
@@ -1177,7 +1196,7 @@ process.setMaxListeners(Infinity);
1177
1196
  process.on("uncaughtException", (err, origin) => {
1178
1197
  logger_default.error(`An unhandled error occurred: ${origin}`, err);
1179
1198
  });
1180
- process.on("unhandledRejection", (_17, promise) => {
1199
+ process.on("unhandledRejection", (_18, promise) => {
1181
1200
  promise.catch((err) => logger_default.error("An unhandled rejection occurred:", err));
1182
1201
  });
1183
1202
  process.on("warning", (warning) => logger_default.warn("System warning: ", warning));
@@ -1580,13 +1599,16 @@ var Server = class {
1580
1599
  var server_default = new Server();
1581
1600
 
1582
1601
  // src/api/routes/index.ts
1583
- import fs8 from "fs-extra";
1602
+ import fs9 from "fs-extra";
1603
+ import path7 from "path";
1604
+ import mime4 from "mime";
1584
1605
 
1585
1606
  // src/api/routes/images.ts
1586
- import fs6 from "fs";
1587
- import _13 from "lodash";
1607
+ import fs7 from "fs";
1608
+ import _14 from "lodash";
1588
1609
 
1589
1610
  // src/api/controllers/images.ts
1611
+ import _13 from "lodash";
1590
1612
  import crypto2 from "crypto";
1591
1613
 
1592
1614
  // src/lib/configs/model-config.ts
@@ -2384,7 +2406,7 @@ async function generateImageComposition(_model, prompt, imageUrls, {
2384
2406
  submit_id: submitId,
2385
2407
  metrics_extra: JSON.stringify({
2386
2408
  promptSource: "custom",
2387
- generateCount: 1,
2409
+ generateCount: finalTargetImageCount,
2388
2410
  enterFrom: "click",
2389
2411
  sceneOptions: JSON.stringify([sceneOption]),
2390
2412
  generateId: submitId,
@@ -2456,7 +2478,7 @@ async function generateImageComposition(_model, prompt, imageUrls, {
2456
2478
  }],
2457
2479
  strength: 0.5
2458
2480
  })),
2459
- prompt_placeholder_info_list: uploadedImageIds.map((_17, index) => ({
2481
+ prompt_placeholder_info_list: uploadedImageIds.map((_18, index) => ({
2460
2482
  type: "",
2461
2483
  id: util_default.uuid(),
2462
2484
  ability_index: index
@@ -2483,6 +2505,7 @@ async function generateImageComposition(_model, prompt, imageUrls, {
2483
2505
  logger_default.info(`\u56FE\u751F\u56FE\u4EFB\u52A1\u5DF2\u63D0\u4EA4\uFF0Chistory_id: ${historyId}\uFF0C\u7B49\u5F85\u751F\u6210\u5B8C\u6210...`);
2484
2506
  let status = 20, failCode, item_list = [];
2485
2507
  let pollCount = 0;
2508
+ let missingRecordCount = 0;
2486
2509
  const maxPollCount = 600;
2487
2510
  while (pollCount < maxPollCount) {
2488
2511
  await new Promise((resolve) => setTimeout(resolve, 1e3));
@@ -2568,8 +2591,15 @@ async function generateImageComposition(_model, prompt, imageUrls, {
2568
2591
  }
2569
2592
  }
2570
2593
  });
2571
- if (!result[historyId])
2572
- throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
2594
+ if (!result[historyId]) {
2595
+ missingRecordCount++;
2596
+ logger_default.warn(`history_id ${historyId} not found in poll result, retry ${missingRecordCount}/10`);
2597
+ if (missingRecordCount >= 10) {
2598
+ throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
2599
+ }
2600
+ continue;
2601
+ }
2602
+ missingRecordCount = 0;
2573
2603
  status = result[historyId].status;
2574
2604
  failCode = result[historyId].fail_code;
2575
2605
  item_list = result[historyId].item_list || [];
@@ -2607,13 +2637,18 @@ async function generateMultiImages(_model, prompt, {
2607
2637
  resolution = "2k",
2608
2638
  sampleStrength = 0.5,
2609
2639
  negativePrompt = "",
2610
- intelligentRatio = false
2640
+ intelligentRatio = false,
2641
+ targetImageCount
2611
2642
  }, refreshToken) {
2612
2643
  const model = getModel(_model);
2613
2644
  const resolutionResult = resolveResolution(resolution, ratio);
2614
2645
  const { width, height, imageRatio, resolutionType } = resolutionResult;
2615
- const targetImageCount = prompt.match(/(\d+)张/) ? parseInt(prompt.match(/(\d+)张/)[1]) : 4;
2616
- logger_default.info(`\u4F7F\u7528 ${_model} \u591A\u56FE\u751F\u6210: ${targetImageCount}\u5F20\u56FE\u7247 ${width}x${height} (${ratio}@${resolution}) \u7CBE\u7EC6\u5EA6: ${sampleStrength}`);
2646
+ const finalTargetImageCount2 = _13.clamp(
2647
+ targetImageCount ?? (prompt.match(/(\d+)张/) ? parseInt(prompt.match(/(\d+)张/)[1]) : 4),
2648
+ 1,
2649
+ 10
2650
+ );
2651
+ logger_default.info(`\u4F7F\u7528 ${_model} \u591A\u56FE\u751F\u6210: ${finalTargetImageCount2}\u5F20\u56FE\u7247 ${width}x${height} (${ratio}@${resolution}) \u7CBE\u7EC6\u5EA6: ${sampleStrength}`);
2617
2652
  const componentId = util_default.uuid();
2618
2653
  const submitId = util_default.uuid();
2619
2654
  const sceneOption = {
@@ -2702,7 +2737,7 @@ async function generateMultiImages(_model, prompt, {
2702
2737
  gen_option: {
2703
2738
  type: "",
2704
2739
  id: util_default.uuid(),
2705
- generate_all: false
2740
+ generate_all: finalTargetImageCount2 > 1
2706
2741
  }
2707
2742
  }
2708
2743
  }
@@ -2718,15 +2753,16 @@ async function generateMultiImages(_model, prompt, {
2718
2753
  const historyId = aigc_data == null ? void 0 : aigc_data.history_record_id;
2719
2754
  if (!historyId)
2720
2755
  throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, "\u8BB0\u5F55ID\u4E0D\u5B58\u5728");
2721
- logger_default.info(`\u591A\u56FE\u751F\u6210\u4EFB\u52A1\u5DF2\u63D0\u4EA4\uFF0Csubmit_id: ${submitId}, history_id: ${historyId}\uFF0C\u7B49\u5F85\u751F\u6210 ${targetImageCount} \u5F20\u56FE\u7247...`);
2756
+ logger_default.info(`\u591A\u56FE\u751F\u6210\u4EFB\u52A1\u5DF2\u63D0\u4EA4\uFF0Csubmit_id: ${submitId}, history_id: ${historyId}\uFF0C\u7B49\u5F85\u751F\u6210 ${finalTargetImageCount2} \u5F20\u56FE\u7247...`);
2722
2757
  let status = 20, failCode, item_list = [];
2723
2758
  let pollCount = 0;
2759
+ let missingRecordCount = 0;
2724
2760
  const maxPollCount = 600;
2725
2761
  while (pollCount < maxPollCount) {
2726
2762
  await new Promise((resolve) => setTimeout(resolve, 1e3));
2727
2763
  pollCount++;
2728
2764
  if (pollCount % 30 === 0) {
2729
- logger_default.info(`\u591A\u56FE\u751F\u6210\u8FDB\u5EA6: \u7B2C ${pollCount} \u6B21\u8F6E\u8BE2 (history_id: ${historyId})\uFF0C\u5F53\u524D\u72B6\u6001: ${status}\uFF0C\u5DF2\u751F\u6210: ${item_list.length}/${targetImageCount} \u5F20\u56FE\u7247...`);
2765
+ logger_default.info(`\u591A\u56FE\u751F\u6210\u8FDB\u5EA6: \u7B2C ${pollCount} \u6B21\u8F6E\u8BE2 (history_id: ${historyId})\uFF0C\u5F53\u524D\u72B6\u6001: ${status}\uFF0C\u5DF2\u751F\u6210: ${item_list.length}/${finalTargetImageCount2} \u5F20\u56FE\u7247...`);
2730
2766
  }
2731
2767
  const result = await request("post", "/mweb/v1/get_history_by_ids", refreshToken, {
2732
2768
  data: {
@@ -2806,20 +2842,27 @@ async function generateMultiImages(_model, prompt, {
2806
2842
  }
2807
2843
  }
2808
2844
  });
2809
- if (!result[historyId])
2810
- throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
2845
+ if (!result[historyId]) {
2846
+ missingRecordCount++;
2847
+ logger_default.warn(`history_id ${historyId} not found in poll result, retry ${missingRecordCount}/10`);
2848
+ if (missingRecordCount >= 10) {
2849
+ throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
2850
+ }
2851
+ continue;
2852
+ }
2853
+ missingRecordCount = 0;
2811
2854
  status = result[historyId].status;
2812
2855
  failCode = result[historyId].fail_code;
2813
2856
  item_list = result[historyId].item_list || [];
2814
- if (item_list.length >= targetImageCount) {
2857
+ if (item_list.length >= finalTargetImageCount2) {
2815
2858
  logger_default.info(`\u591A\u56FE\u751F\u6210\u5B8C\u6210: \u72B6\u6001=${status}, \u5DF2\u751F\u6210 ${item_list.length} \u5F20\u56FE\u7247`);
2816
2859
  break;
2817
2860
  }
2818
2861
  if (pollCount % 60 === 0) {
2819
2862
  logger_default.info(`jimeng-4.0 \u8BE6\u7EC6\u72B6\u6001: status=${status}, item_list.length=${item_list.length}, failCode=${failCode || "none"}`);
2820
2863
  }
2821
- if (status === 10 && item_list.length < targetImageCount && pollCount % 30 === 0) {
2822
- logger_default.info(`jimeng-4.0 \u72B6\u6001\u5DF2\u5B8C\u6210\u4F46\u56FE\u7247\u6570\u91CF\u4E0D\u8DB3: \u72B6\u6001=${status}, \u5DF2\u751F\u6210 ${item_list.length}/${targetImageCount} \u5F20\u56FE\u7247\uFF0C\u7EE7\u7EED\u7B49\u5F85...`);
2864
+ if (status === 10 && item_list.length < finalTargetImageCount2 && pollCount % 30 === 0) {
2865
+ logger_default.info(`jimeng-4.0 \u72B6\u6001\u5DF2\u5B8C\u6210\u4F46\u56FE\u7247\u6570\u91CF\u4E0D\u8DB3: \u72B6\u6001=${status}, \u5DF2\u751F\u6210 ${item_list.length}/${finalTargetImageCount2} \u5F20\u56FE\u7247\uFF0C\u7EE7\u7EED\u7B49\u5F85...`);
2823
2866
  }
2824
2867
  }
2825
2868
  if (pollCount >= maxPollCount) {
@@ -2836,7 +2879,7 @@ async function generateMultiImages(_model, prompt, {
2836
2879
  if (!((_c = (_b = (_a = item == null ? void 0 : item.image) == null ? void 0 : _a.large_images) == null ? void 0 : _b[0]) == null ? void 0 : _c.image_url))
2837
2880
  return ((_d = item == null ? void 0 : item.common_attr) == null ? void 0 : _d.cover_url) || null;
2838
2881
  return item.image.large_images[0].image_url;
2839
- }).filter((url) => url !== null);
2882
+ }).filter((url) => url !== null).slice(0, finalTargetImageCount2);
2840
2883
  logger_default.info(`\u591A\u56FE\u751F\u6210\u7ED3\u679C: \u6210\u529F\u751F\u6210 ${imageUrls.length} \u5F20\u56FE\u7247`);
2841
2884
  return imageUrls;
2842
2885
  }
@@ -2845,7 +2888,8 @@ async function generateImages(_model, prompt, {
2845
2888
  resolution = "2k",
2846
2889
  sampleStrength = 0.5,
2847
2890
  negativePrompt = "",
2848
- intelligentRatio = false
2891
+ intelligentRatio = false,
2892
+ n = 1
2849
2893
  }, refreshToken) {
2850
2894
  const model = getModel(_model);
2851
2895
  const resolutionResult = resolveResolution(resolution, ratio);
@@ -2854,9 +2898,15 @@ async function generateImages(_model, prompt, {
2854
2898
  const { totalCredit } = await getCredit(refreshToken);
2855
2899
  if (totalCredit <= 0)
2856
2900
  await receiveCredit(refreshToken);
2857
- const isMultiImageRequest = /jimeng-[45]\.[0-9]/.test(_model) && (prompt.includes("\u8FDE\u7EED") || prompt.includes("\u7ED8\u672C") || prompt.includes("\u6545\u4E8B") || /\d+张/.test(prompt));
2901
+ const finalN = _13.clamp(Number(n) || 1, 1, 10);
2902
+ const isMultiImageRequest = /jimeng-[45]\.[0-9]/.test(_model) && (finalN > 1 || prompt.includes("\u8FDE\u7EED") || prompt.includes("\u7ED8\u672C") || prompt.includes("\u6545\u4E8B") || /\d+张/.test(prompt));
2858
2903
  if (isMultiImageRequest) {
2859
- return await generateMultiImages(_model, prompt, { ratio, resolution, sampleStrength, negativePrompt, intelligentRatio }, refreshToken);
2904
+ return await generateMultiImages(
2905
+ _model,
2906
+ prompt,
2907
+ { ratio, resolution, sampleStrength, negativePrompt, intelligentRatio, targetImageCount: finalN > 1 ? finalN : void 0 },
2908
+ refreshToken
2909
+ );
2860
2910
  }
2861
2911
  const componentId = util_default.uuid();
2862
2912
  const submitId = util_default.uuid();
@@ -2961,6 +3011,7 @@ async function generateImages(_model, prompt, {
2961
3011
  logger_default.info(`\u6587\u751F\u56FE\u4EFB\u52A1\u5DF2\u63D0\u4EA4\uFF0Csubmit_id: ${submitId}, history_id: ${historyId}\uFF0C\u7B49\u5F85\u751F\u6210\u5B8C\u6210...`);
2962
3012
  let status = 20, failCode, item_list = [];
2963
3013
  let pollCount = 0;
3014
+ let missingRecordCount = 0;
2964
3015
  const maxPollCount = 600;
2965
3016
  while (pollCount < maxPollCount) {
2966
3017
  await new Promise((resolve) => setTimeout(resolve, 1e3));
@@ -3067,8 +3118,15 @@ async function generateImages(_model, prompt, {
3067
3118
  }
3068
3119
  }
3069
3120
  });
3070
- if (!result[historyId])
3071
- throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
3121
+ if (!result[historyId]) {
3122
+ missingRecordCount++;
3123
+ logger_default.warn(`history_id ${historyId} not found in poll result, retry ${missingRecordCount}/10`);
3124
+ if (missingRecordCount >= 10) {
3125
+ throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
3126
+ }
3127
+ continue;
3128
+ }
3129
+ missingRecordCount = 0;
3072
3130
  status = result[historyId].status;
3073
3131
  failCode = result[historyId].fail_code;
3074
3132
  item_list = result[historyId].item_list || [];
@@ -3102,6 +3160,55 @@ async function generateImages(_model, prompt, {
3102
3160
  return imageUrls;
3103
3161
  }
3104
3162
 
3163
+ // src/lib/local-assets.ts
3164
+ import path6 from "path";
3165
+ import axios3 from "axios";
3166
+ import fs6 from "fs-extra";
3167
+ function resolveExtension(sourceUrl, contentType, fallback = "bin") {
3168
+ if (contentType) {
3169
+ const ext = util_default.mimeToExtension(contentType.split(";")[0].trim());
3170
+ if (ext) return ext;
3171
+ }
3172
+ const urlExt = util_default.extractURLExtension(sourceUrl);
3173
+ if (urlExt) return urlExt;
3174
+ return fallback;
3175
+ }
3176
+ function normalizePrefix(prefix = "") {
3177
+ if (!prefix) return "";
3178
+ return prefix.startsWith("/") ? prefix : `/${prefix}`;
3179
+ }
3180
+ function buildPublicBaseUrl(headers = {}) {
3181
+ const forwardedProto = headers["x-forwarded-proto"];
3182
+ const forwardedHost = headers["x-forwarded-host"];
3183
+ const host = forwardedHost || headers.host;
3184
+ if (!host) return null;
3185
+ const protocol = forwardedProto || "http";
3186
+ return `${protocol}://${host}${normalizePrefix(config_default.service.urlPrefix)}`;
3187
+ }
3188
+ async function saveRemoteAssetToLocalUrl(remoteUrl, assetType = "images", publicBaseUrl) {
3189
+ const response = await axios3.get(remoteUrl, {
3190
+ responseType: "arraybuffer",
3191
+ timeout: 12e4
3192
+ });
3193
+ const ext = resolveExtension(
3194
+ remoteUrl,
3195
+ response.headers["content-type"],
3196
+ assetType === "videos" ? "mp4" : "png"
3197
+ );
3198
+ const dateDir = util_default.getDateString("yyyyMMdd");
3199
+ const relativePath = path6.posix.join("generated", assetType, dateDir, `${util_default.uuid(false)}.${ext}`);
3200
+ const outputPath = path6.join(config_default.system.publicDirPath, ...relativePath.split("/"));
3201
+ await fs6.ensureDir(path6.dirname(outputPath));
3202
+ await fs6.writeFile(outputPath, response.data);
3203
+ const baseUrl = publicBaseUrl || `${config_default.service.publicDirUrl.replace(/\/public$/, "")}${normalizePrefix(config_default.service.urlPrefix)}`;
3204
+ const localUrl = `${baseUrl}/public/${relativePath}`;
3205
+ logger_default.info(`asset localized: ${remoteUrl} -> ${localUrl}`);
3206
+ return localUrl;
3207
+ }
3208
+ async function saveRemoteAssetsToLocalUrls(remoteUrls, assetType = "images", publicBaseUrl) {
3209
+ return Promise.all(remoteUrls.map((url) => saveRemoteAssetToLocalUrl(url, assetType, publicBaseUrl)));
3210
+ }
3211
+
3105
3212
  // src/api/routes/images.ts
3106
3213
  var images_default = {
3107
3214
  prefix: "/v1/images",
@@ -3117,9 +3224,9 @@ var images_default = {
3117
3224
  const contentType = request2.headers["content-type"] || "";
3118
3225
  const isMultiPart = contentType.startsWith("multipart/form-data");
3119
3226
  if (isMultiPart) {
3120
- request2.validate("body.model", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.prompt", _13.isString).validate("body.negative_prompt", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.ratio", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.resolution", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.intelligent_ratio", (v) => _13.isUndefined(v) || typeof v === "string" && (v === "true" || v === "false") || _13.isBoolean(v)).validate("body.sample_strength", (v) => _13.isUndefined(v) || typeof v === "string" && !isNaN(parseFloat(v)) || _13.isFinite(v)).validate("body.response_format", (v) => _13.isUndefined(v) || _13.isString(v)).validate("headers.authorization", _13.isString);
3227
+ request2.validate("body.model", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.prompt", _14.isString).validate("body.negative_prompt", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.ratio", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.resolution", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.intelligent_ratio", (v) => _14.isUndefined(v) || typeof v === "string" && (v === "true" || v === "false") || _14.isBoolean(v)).validate("body.sample_strength", (v) => _14.isUndefined(v) || typeof v === "string" && !isNaN(parseFloat(v)) || _14.isFinite(v)).validate("body.n", (v) => _14.isUndefined(v) || typeof v === "string" && /^\d+$/.test(v) || _14.isFinite(v) && v >= 1 && v <= 10).validate("body.response_format", (v) => _14.isUndefined(v) || _14.isString(v)).validate("headers.authorization", _14.isString);
3121
3228
  } else {
3122
- request2.validate("body.model", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.prompt", _13.isString).validate("body.images", (v) => _13.isUndefined(v) || _13.isArray(v)).validate("body.negative_prompt", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.ratio", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.resolution", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.intelligent_ratio", (v) => _13.isUndefined(v) || _13.isBoolean(v)).validate("body.sample_strength", (v) => _13.isUndefined(v) || _13.isFinite(v)).validate("body.response_format", (v) => _13.isUndefined(v) || _13.isString(v)).validate("headers.authorization", _13.isString);
3229
+ request2.validate("body.model", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.prompt", _14.isString).validate("body.images", (v) => _14.isUndefined(v) || _14.isArray(v)).validate("body.negative_prompt", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.ratio", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.resolution", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.intelligent_ratio", (v) => _14.isUndefined(v) || _14.isBoolean(v)).validate("body.sample_strength", (v) => _14.isUndefined(v) || _14.isFinite(v)).validate("body.n", (v) => _14.isUndefined(v) || _14.isFinite(v) && v >= 1 && v <= 10).validate("body.response_format", (v) => _14.isUndefined(v) || _14.isString(v)).validate("headers.authorization", _14.isString);
3123
3230
  }
3124
3231
  let images = null;
3125
3232
  if (isMultiPart) {
@@ -3130,7 +3237,7 @@ var images_default = {
3130
3237
  if (imageFiles.length > 10) {
3131
3238
  throw new Error("\u6700\u591A\u652F\u630110\u5F20\u8F93\u5165\u56FE\u7247");
3132
3239
  }
3133
- images = imageFiles.map((file) => fs6.readFileSync(file.filepath));
3240
+ images = imageFiles.map((file) => fs7.readFileSync(file.filepath));
3134
3241
  }
3135
3242
  }
3136
3243
  } else {
@@ -3140,18 +3247,18 @@ var images_default = {
3140
3247
  throw new Error("\u6700\u591A\u652F\u630110\u5F20\u8F93\u5165\u56FE\u7247");
3141
3248
  }
3142
3249
  bodyImages.forEach((image, index) => {
3143
- if (!_13.isString(image) && !_13.isObject(image)) {
3250
+ if (!_14.isString(image) && !_14.isObject(image)) {
3144
3251
  throw new Error(`\u56FE\u7247 ${index + 1} \u683C\u5F0F\u4E0D\u6B63\u786E\uFF1A\u5E94\u4E3AURL\u5B57\u7B26\u4E32\u6216\u5305\u542Burl\u5B57\u6BB5\u7684\u5BF9\u8C61`);
3145
3252
  }
3146
- if (_13.isObject(image) && !image.url) {
3253
+ if (_14.isObject(image) && !image.url) {
3147
3254
  throw new Error(`\u56FE\u7247 ${index + 1} \u7F3A\u5C11url\u5B57\u6BB5`);
3148
3255
  }
3149
3256
  });
3150
- images = bodyImages.map((image) => _13.isString(image) ? image : image.url);
3257
+ images = bodyImages.map((image) => _14.isString(image) ? image : image.url);
3151
3258
  }
3152
3259
  }
3153
3260
  const tokens = tokenSplit(request2.headers.authorization);
3154
- const token = _13.sample(tokens);
3261
+ const token = _14.sample(tokens);
3155
3262
  const {
3156
3263
  model,
3157
3264
  prompt,
@@ -3160,11 +3267,14 @@ var images_default = {
3160
3267
  resolution,
3161
3268
  intelligent_ratio: intelligentRatio,
3162
3269
  sample_strength: sampleStrength,
3270
+ n,
3163
3271
  response_format
3164
3272
  } = request2.body;
3165
3273
  const finalSampleStrength = isMultiPart && typeof sampleStrength === "string" ? parseFloat(sampleStrength) : sampleStrength;
3166
3274
  const finalIntelligentRatio = isMultiPart && typeof intelligentRatio === "string" ? intelligentRatio === "true" : intelligentRatio;
3167
- const responseFormat = _13.defaultTo(response_format, "url");
3275
+ const finalN = isMultiPart && typeof n === "string" ? parseInt(n) : n;
3276
+ const responseFormat = _14.defaultTo(response_format, "url");
3277
+ const publicBaseUrl = buildPublicBaseUrl(request2.headers);
3168
3278
  let imageUrls;
3169
3279
  let resultData = {
3170
3280
  created: util_default.unixTimestamp()
@@ -3185,14 +3295,16 @@ var images_default = {
3185
3295
  resolution,
3186
3296
  sampleStrength: finalSampleStrength,
3187
3297
  negativePrompt,
3188
- intelligentRatio: finalIntelligentRatio
3298
+ intelligentRatio: finalIntelligentRatio,
3299
+ n: finalN
3189
3300
  }, token);
3190
3301
  }
3191
3302
  let data = [];
3192
3303
  if (responseFormat == "b64_json") {
3193
3304
  data = (await Promise.all(imageUrls.map((url) => util_default.fetchFileBASE64(url)))).map((b64) => ({ b64_json: b64 }));
3194
3305
  } else {
3195
- data = imageUrls.map((url) => ({
3306
+ const localUrls = await saveRemoteAssetsToLocalUrls(imageUrls, "images", publicBaseUrl);
3307
+ data = localUrls.map((url) => ({
3196
3308
  url
3197
3309
  }));
3198
3310
  }
@@ -3211,9 +3323,9 @@ var images_default = {
3211
3323
  const contentType = request2.headers["content-type"] || "";
3212
3324
  const isMultiPart = contentType.startsWith("multipart/form-data");
3213
3325
  if (isMultiPart) {
3214
- request2.validate("body.model", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.prompt", _13.isString).validate("body.negative_prompt", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.ratio", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.resolution", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.intelligent_ratio", (v) => _13.isUndefined(v) || typeof v === "string" && (v === "true" || v === "false") || _13.isBoolean(v)).validate("body.sample_strength", (v) => _13.isUndefined(v) || typeof v === "string" && !isNaN(parseFloat(v)) || _13.isFinite(v)).validate("body.response_format", (v) => _13.isUndefined(v) || _13.isString(v)).validate("headers.authorization", _13.isString);
3326
+ request2.validate("body.model", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.prompt", _14.isString).validate("body.negative_prompt", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.ratio", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.resolution", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.intelligent_ratio", (v) => _14.isUndefined(v) || typeof v === "string" && (v === "true" || v === "false") || _14.isBoolean(v)).validate("body.sample_strength", (v) => _14.isUndefined(v) || typeof v === "string" && !isNaN(parseFloat(v)) || _14.isFinite(v)).validate("body.response_format", (v) => _14.isUndefined(v) || _14.isString(v)).validate("headers.authorization", _14.isString);
3215
3327
  } else {
3216
- request2.validate("body.model", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.prompt", _13.isString).validate("body.images", _13.isArray).validate("body.negative_prompt", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.ratio", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.resolution", (v) => _13.isUndefined(v) || _13.isString(v)).validate("body.intelligent_ratio", (v) => _13.isUndefined(v) || _13.isBoolean(v)).validate("body.sample_strength", (v) => _13.isUndefined(v) || _13.isFinite(v)).validate("body.response_format", (v) => _13.isUndefined(v) || _13.isString(v)).validate("headers.authorization", _13.isString);
3328
+ request2.validate("body.model", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.prompt", _14.isString).validate("body.images", _14.isArray).validate("body.negative_prompt", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.ratio", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.resolution", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.intelligent_ratio", (v) => _14.isUndefined(v) || _14.isBoolean(v)).validate("body.sample_strength", (v) => _14.isUndefined(v) || _14.isFinite(v)).validate("body.response_format", (v) => _14.isUndefined(v) || _14.isString(v)).validate("headers.authorization", _14.isString);
3217
3329
  }
3218
3330
  let images = [];
3219
3331
  if (isMultiPart) {
@@ -3228,7 +3340,7 @@ var images_default = {
3228
3340
  if (imageFiles.length > 10) {
3229
3341
  throw new Error("\u6700\u591A\u652F\u630110\u5F20\u8F93\u5165\u56FE\u7247");
3230
3342
  }
3231
- images = imageFiles.map((file) => fs6.readFileSync(file.filepath));
3343
+ images = imageFiles.map((file) => fs7.readFileSync(file.filepath));
3232
3344
  } else {
3233
3345
  const bodyImages = request2.body.images;
3234
3346
  if (!bodyImages || bodyImages.length === 0) {
@@ -3238,17 +3350,17 @@ var images_default = {
3238
3350
  throw new Error("\u6700\u591A\u652F\u630110\u5F20\u8F93\u5165\u56FE\u7247");
3239
3351
  }
3240
3352
  bodyImages.forEach((image, index) => {
3241
- if (!_13.isString(image) && !_13.isObject(image)) {
3353
+ if (!_14.isString(image) && !_14.isObject(image)) {
3242
3354
  throw new Error(`\u56FE\u7247 ${index + 1} \u683C\u5F0F\u4E0D\u6B63\u786E\uFF1A\u5E94\u4E3AURL\u5B57\u7B26\u4E32\u6216\u5305\u542Burl\u5B57\u6BB5\u7684\u5BF9\u8C61`);
3243
3355
  }
3244
- if (_13.isObject(image) && !image.url) {
3356
+ if (_14.isObject(image) && !image.url) {
3245
3357
  throw new Error(`\u56FE\u7247 ${index + 1} \u7F3A\u5C11url\u5B57\u6BB5`);
3246
3358
  }
3247
3359
  });
3248
- images = bodyImages.map((image) => _13.isString(image) ? image : image.url);
3360
+ images = bodyImages.map((image) => _14.isString(image) ? image : image.url);
3249
3361
  }
3250
3362
  const tokens = tokenSplit(request2.headers.authorization);
3251
- const token = _13.sample(tokens);
3363
+ const token = _14.sample(tokens);
3252
3364
  const {
3253
3365
  model,
3254
3366
  prompt,
@@ -3261,7 +3373,8 @@ var images_default = {
3261
3373
  } = request2.body;
3262
3374
  const finalSampleStrength = isMultiPart && typeof sampleStrength === "string" ? parseFloat(sampleStrength) : sampleStrength;
3263
3375
  const finalIntelligentRatio = isMultiPart && typeof intelligentRatio === "string" ? intelligentRatio === "true" : intelligentRatio;
3264
- const responseFormat = _13.defaultTo(response_format, "url");
3376
+ const responseFormat = _14.defaultTo(response_format, "url");
3377
+ const publicBaseUrl = buildPublicBaseUrl(request2.headers);
3265
3378
  const resultUrls = await generateImageComposition(model, prompt, images, {
3266
3379
  ratio,
3267
3380
  resolution,
@@ -3273,7 +3386,8 @@ var images_default = {
3273
3386
  if (responseFormat == "b64_json") {
3274
3387
  data = (await Promise.all(resultUrls.map((url) => util_default.fetchFileBASE64(url)))).map((b64) => ({ b64_json: b64 }));
3275
3388
  } else {
3276
- data = resultUrls.map((url) => ({
3389
+ const localUrls = await saveRemoteAssetsToLocalUrls(resultUrls, "images", publicBaseUrl);
3390
+ data = localUrls.map((url) => ({
3277
3391
  url
3278
3392
  }));
3279
3393
  }
@@ -3288,14 +3402,14 @@ var images_default = {
3288
3402
  };
3289
3403
 
3290
3404
  // src/api/routes/chat.ts
3291
- import _14 from "lodash";
3405
+ import _15 from "lodash";
3292
3406
 
3293
3407
  // src/api/controllers/chat.ts
3294
3408
  import { PassThrough } from "stream";
3295
3409
 
3296
3410
  // src/api/controllers/videos.ts
3297
3411
  import crypto3 from "crypto";
3298
- import fs7 from "fs";
3412
+ import fs8 from "fs";
3299
3413
  var DEFAULT_ASSISTANT_ID3 = 513695;
3300
3414
  var DEFAULT_MODEL2 = "jimeng-video-3.0";
3301
3415
  var DEFAULT_DRAFT_VERSION = "3.2.8";
@@ -3371,8 +3485,8 @@ var MATERIAL_TYPE_CODE = {
3371
3485
  audio: 3
3372
3486
  };
3373
3487
  function detectMaterialType(file) {
3374
- const mime4 = (file.mimetype || file.mimeType || "").toLowerCase();
3375
- if (mime4 && MIME_TO_MATERIAL_TYPE[mime4]) return MIME_TO_MATERIAL_TYPE[mime4];
3488
+ const mime5 = (file.mimetype || file.mimeType || "").toLowerCase();
3489
+ if (mime5 && MIME_TO_MATERIAL_TYPE[mime5]) return MIME_TO_MATERIAL_TYPE[mime5];
3376
3490
  const filename = (file.originalFilename || file.newFilename || "").toLowerCase();
3377
3491
  const dotIdx = filename.lastIndexOf(".");
3378
3492
  if (dotIdx >= 0) {
@@ -4058,7 +4172,7 @@ async function generateVideo(_model, prompt, {
4058
4172
  }
4059
4173
  try {
4060
4174
  logger_default.info(`\u5F00\u59CB\u4E0A\u4F20\u7B2C ${i + 1} \u4E2A\u6587\u4EF6: ${file.originalFilename || file.filepath}`);
4061
- const buffer = fs7.readFileSync(file.filepath);
4175
+ const buffer = fs8.readFileSync(file.filepath);
4062
4176
  const imageUri = await uploadImageBufferForVideo(buffer, refreshToken);
4063
4177
  if (imageUri) {
4064
4178
  uploadIDs.push(imageUri);
@@ -4428,7 +4542,7 @@ async function generateSeedanceVideo(_model, prompt, {
4428
4542
  const materialType = detectMaterialType(file);
4429
4543
  try {
4430
4544
  logger_default.info(`Seedance: \u5F00\u59CB\u4E0A\u4F20\u7B2C ${i + 1} \u4E2A\u6587\u4EF6 (${materialType}): ${file.originalFilename || file.filepath}`);
4431
- const buffer = fs7.readFileSync(file.filepath);
4545
+ const buffer = fs8.readFileSync(file.filepath);
4432
4546
  if (materialType === "image") {
4433
4547
  const imageUri = await uploadImageBufferForVideo(buffer, refreshToken);
4434
4548
  if (imageUri) {
@@ -4817,7 +4931,7 @@ var MAX_RETRY_COUNT = 3;
4817
4931
  var RETRY_DELAY = 5e3;
4818
4932
  function parseModel(model) {
4819
4933
  const [_model, size] = model.split(":");
4820
- const [_17, width, height] = /(\d+)[\W\w](\d+)/.exec(size) ?? [];
4934
+ const [_18, width, height] = /(\d+)[\W\w](\d+)/.exec(size) ?? [];
4821
4935
  return {
4822
4936
  model: _model,
4823
4937
  width: size ? Math.ceil(parseInt(width) / 2) * 2 : 1024,
@@ -4827,7 +4941,7 @@ function parseModel(model) {
4827
4941
  function isVideoModel(model) {
4828
4942
  return model.startsWith("jimeng-video") || model.startsWith("seedance-");
4829
4943
  }
4830
- async function createCompletion(messages, refreshToken, _model = DEFAULT_MODEL, retryCount = 0) {
4944
+ async function createCompletion(messages, refreshToken, _model = DEFAULT_MODEL, retryCount = 0, publicBaseUrl) {
4831
4945
  return (async () => {
4832
4946
  if (messages.length === 0)
4833
4947
  throw new APIException(exceptions_default.API_REQUEST_PARAMS_INVALID, "\u6D88\u606F\u4E0D\u80FD\u4E3A\u7A7A");
@@ -4886,7 +5000,8 @@ curl -X POST http://localhost:3000/v1/videos/generations \\
4886
5000
  },
4887
5001
  refreshToken
4888
5002
  );
4889
- logger_default.info(`\u89C6\u9891\u751F\u6210\u6210\u529F\uFF0CURL: ${videoUrl}`);
5003
+ const localVideoUrl = await saveRemoteAssetToLocalUrl(videoUrl, "videos", publicBaseUrl);
5004
+ logger_default.info(`\u89C6\u9891\u751F\u6210\u6210\u529F\uFF0CURL: ${localVideoUrl}`);
4890
5005
  return {
4891
5006
  id: util_default.uuid(),
4892
5007
  model: _model,
@@ -4896,7 +5011,7 @@ curl -X POST http://localhost:3000/v1/videos/generations \\
4896
5011
  index: 0,
4897
5012
  message: {
4898
5013
  role: "assistant",
4899
- content: `![video](${videoUrl})
5014
+ content: `![video](${localVideoUrl})
4900
5015
  `
4901
5016
  },
4902
5017
  finish_reason: "stop"
@@ -4940,6 +5055,7 @@ curl -X POST http://localhost:3000/v1/videos/generations \\
4940
5055
  },
4941
5056
  refreshToken
4942
5057
  );
5058
+ const localImageUrls = await saveRemoteAssetsToLocalUrls(imageUrls, "images", publicBaseUrl);
4943
5059
  return {
4944
5060
  id: util_default.uuid(),
4945
5061
  model: _model || model,
@@ -4949,7 +5065,7 @@ curl -X POST http://localhost:3000/v1/videos/generations \\
4949
5065
  index: 0,
4950
5066
  message: {
4951
5067
  role: "assistant",
4952
- content: imageUrls.reduce(
5068
+ content: localImageUrls.reduce(
4953
5069
  (acc, url, i) => acc + `![image_${i}](${url})
4954
5070
  `,
4955
5071
  ""
@@ -4968,13 +5084,13 @@ curl -X POST http://localhost:3000/v1/videos/generations \\
4968
5084
  logger_default.warn(`Try again after ${RETRY_DELAY / 1e3}s...`);
4969
5085
  return (async () => {
4970
5086
  await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
4971
- return createCompletion(messages, refreshToken, _model, retryCount + 1);
5087
+ return createCompletion(messages, refreshToken, _model, retryCount + 1, publicBaseUrl);
4972
5088
  })();
4973
5089
  }
4974
5090
  throw err;
4975
5091
  });
4976
5092
  }
4977
- async function createCompletionStream(messages, refreshToken, _model = DEFAULT_MODEL, retryCount = 0) {
5093
+ async function createCompletionStream(messages, refreshToken, _model = DEFAULT_MODEL, retryCount = 0, publicBaseUrl) {
4978
5094
  return (async () => {
4979
5095
  const { model, width, height } = parseModel(_model);
4980
5096
  logger_default.info(messages);
@@ -5060,10 +5176,11 @@ async function createCompletionStream(messages, refreshToken, _model = DEFAULT_M
5060
5176
  messages[messages.length - 1].content,
5061
5177
  { ratio: "16:9", resolution: "720p" },
5062
5178
  refreshToken
5063
- ).then((videoUrl) => {
5179
+ ).then(async (videoUrl) => {
5064
5180
  clearInterval(progressInterval);
5065
5181
  clearTimeout(timeoutId);
5066
- logger_default.info(`\u89C6\u9891\u751F\u6210\u6210\u529F\uFF0CURL: ${videoUrl}`);
5182
+ const localVideoUrl = await saveRemoteAssetToLocalUrl(videoUrl, "videos", publicBaseUrl);
5183
+ logger_default.info(`\u89C6\u9891\u751F\u6210\u6210\u529F\uFF0CURL: ${localVideoUrl}`);
5067
5184
  stream.write(
5068
5185
  "data: " + JSON.stringify({
5069
5186
  id: util_default.uuid(),
@@ -5078,11 +5195,11 @@ async function createCompletionStream(messages, refreshToken, _model = DEFAULT_M
5078
5195
 
5079
5196
  \u2705 \u89C6\u9891\u751F\u6210\u5B8C\u6210\uFF01
5080
5197
 
5081
- ![video](${videoUrl})
5198
+ ![video](${localVideoUrl})
5082
5199
 
5083
5200
  \u60A8\u53EF\u4EE5\uFF1A
5084
5201
  1. \u76F4\u63A5\u67E5\u770B\u4E0A\u65B9\u89C6\u9891
5085
- 2. \u4F7F\u7528\u4EE5\u4E0B\u94FE\u63A5\u4E0B\u8F7D\u6216\u5206\u4EAB\uFF1A${videoUrl}`
5202
+ 2. \u4F7F\u7528\u4EE5\u4E0B\u94FE\u63A5\u4E0B\u8F7D\u6216\u5206\u4EAB\uFF1A${localVideoUrl}`
5086
5203
  },
5087
5204
  finish_reason: null
5088
5205
  }
@@ -5168,9 +5285,10 @@ ${errorMessage}`
5168
5285
  messages[messages.length - 1].content,
5169
5286
  { width, height },
5170
5287
  refreshToken
5171
- ).then((imageUrls) => {
5172
- for (let i = 0; i < imageUrls.length; i++) {
5173
- const url = imageUrls[i];
5288
+ ).then(async (imageUrls) => {
5289
+ const localImageUrls = await saveRemoteAssetsToLocalUrls(imageUrls, "images", publicBaseUrl);
5290
+ for (let i = 0; i < localImageUrls.length; i++) {
5291
+ const url = localImageUrls[i];
5174
5292
  stream.write(
5175
5293
  "data: " + JSON.stringify({
5176
5294
  id: util_default.uuid(),
@@ -5184,7 +5302,7 @@ ${errorMessage}`
5184
5302
  content: `![image_${i}](${url})
5185
5303
  `
5186
5304
  },
5187
- finish_reason: i < imageUrls.length - 1 ? null : "stop"
5305
+ finish_reason: i < localImageUrls.length - 1 ? null : "stop"
5188
5306
  }
5189
5307
  ]
5190
5308
  }) + "\n\n"
@@ -5197,7 +5315,7 @@ ${errorMessage}`
5197
5315
  object: "chat.completion.chunk",
5198
5316
  choices: [
5199
5317
  {
5200
- index: imageUrls.length + 1,
5318
+ index: localImageUrls.length + 1,
5201
5319
  delta: {
5202
5320
  role: "assistant",
5203
5321
  content: "\u56FE\u50CF\u751F\u6210\u5B8C\u6210\uFF01"
@@ -5240,7 +5358,8 @@ ${errorMessage}`
5240
5358
  messages,
5241
5359
  refreshToken,
5242
5360
  _model,
5243
- retryCount + 1
5361
+ retryCount + 1,
5362
+ publicBaseUrl
5244
5363
  );
5245
5364
  })();
5246
5365
  }
@@ -5253,17 +5372,18 @@ var chat_default = {
5253
5372
  prefix: "/v1/chat",
5254
5373
  post: {
5255
5374
  "/completions": async (request2) => {
5256
- request2.validate("body.model", (v) => _14.isUndefined(v) || _14.isString(v)).validate("body.messages", _14.isArray).validate("headers.authorization", _14.isString);
5375
+ request2.validate("body.model", (v) => _15.isUndefined(v) || _15.isString(v)).validate("body.messages", _15.isArray).validate("headers.authorization", _15.isString);
5257
5376
  const tokens = tokenSplit(request2.headers.authorization);
5258
- const token = _14.sample(tokens);
5377
+ const token = _15.sample(tokens);
5259
5378
  const { model, messages, stream } = request2.body;
5379
+ const publicBaseUrl = buildPublicBaseUrl(request2.headers);
5260
5380
  if (stream) {
5261
- const stream2 = await createCompletionStream(messages, token, model);
5381
+ const stream2 = await createCompletionStream(messages, token, model, 0, publicBaseUrl);
5262
5382
  return new Response(stream2, {
5263
5383
  type: "text/event-stream"
5264
5384
  });
5265
5385
  } else
5266
- return await createCompletion(messages, token, model);
5386
+ return await createCompletion(messages, token, model, 0, publicBaseUrl);
5267
5387
  }
5268
5388
  }
5269
5389
  };
@@ -5277,19 +5397,19 @@ var ping_default = {
5277
5397
  };
5278
5398
 
5279
5399
  // src/api/routes/token.ts
5280
- import _15 from "lodash";
5400
+ import _16 from "lodash";
5281
5401
  var token_default = {
5282
5402
  prefix: "/token",
5283
5403
  post: {
5284
5404
  "/check": async (request2) => {
5285
- request2.validate("body.token", _15.isString);
5405
+ request2.validate("body.token", _16.isString);
5286
5406
  const live = await getTokenLiveStatus(request2.body.token);
5287
5407
  return {
5288
5408
  live
5289
5409
  };
5290
5410
  },
5291
5411
  "/points": async (request2) => {
5292
- request2.validate("headers.authorization", _15.isString);
5412
+ request2.validate("headers.authorization", _16.isString);
5293
5413
  const tokens = tokenSplit(request2.headers.authorization);
5294
5414
  const points = await Promise.all(tokens.map(async (token) => {
5295
5415
  return {
@@ -5453,7 +5573,7 @@ var models_default = {
5453
5573
  };
5454
5574
 
5455
5575
  // src/api/routes/videos.ts
5456
- import _16 from "lodash";
5576
+ import _17 from "lodash";
5457
5577
  var videos_default = {
5458
5578
  prefix: "/v1/videos",
5459
5579
  post: {
@@ -5466,16 +5586,16 @@ var videos_default = {
5466
5586
  }
5467
5587
  const contentType = request2.headers["content-type"] || "";
5468
5588
  const isMultiPart = contentType.startsWith("multipart/form-data");
5469
- request2.validate("body.model", (v) => _16.isUndefined(v) || _16.isString(v)).validate("body.prompt", (v) => _16.isUndefined(v) || _16.isString(v)).validate("body.ratio", (v) => _16.isUndefined(v) || _16.isString(v)).validate("body.resolution", (v) => _16.isUndefined(v) || _16.isString(v)).validate("body.duration", (v) => {
5470
- if (_16.isUndefined(v)) return true;
5589
+ request2.validate("body.model", (v) => _17.isUndefined(v) || _17.isString(v)).validate("body.prompt", (v) => _17.isUndefined(v) || _17.isString(v)).validate("body.ratio", (v) => _17.isUndefined(v) || _17.isString(v)).validate("body.resolution", (v) => _17.isUndefined(v) || _17.isString(v)).validate("body.duration", (v) => {
5590
+ if (_17.isUndefined(v)) return true;
5471
5591
  if (isMultiPart && typeof v === "string") {
5472
5592
  const num = parseInt(v);
5473
5593
  return num >= 4 && num <= 15 || num === 5 || num === 10;
5474
5594
  }
5475
- return _16.isFinite(v) && (v >= 4 && v <= 15 || v === 5 || v === 10);
5476
- }).validate("body.file_paths", (v) => _16.isUndefined(v) || _16.isArray(v)).validate("body.filePaths", (v) => _16.isUndefined(v) || _16.isArray(v)).validate("body.response_format", (v) => _16.isUndefined(v) || _16.isString(v)).validate("headers.authorization", _16.isString);
5595
+ return _17.isFinite(v) && (v >= 4 && v <= 15 || v === 5 || v === 10);
5596
+ }).validate("body.file_paths", (v) => _17.isUndefined(v) || _17.isArray(v)).validate("body.filePaths", (v) => _17.isUndefined(v) || _17.isArray(v)).validate("body.response_format", (v) => _17.isUndefined(v) || _17.isString(v)).validate("headers.authorization", _17.isString);
5477
5597
  const tokens = tokenSplit(request2.headers.authorization);
5478
- const token = _16.sample(tokens);
5598
+ const token = _17.sample(tokens);
5479
5599
  const {
5480
5600
  model = DEFAULT_MODEL2,
5481
5601
  prompt,
@@ -5528,10 +5648,12 @@ var videos_default = {
5528
5648
  }]
5529
5649
  };
5530
5650
  } else {
5651
+ const publicBaseUrl = buildPublicBaseUrl(request2.headers);
5652
+ const localVideoUrl = await saveRemoteAssetToLocalUrl(videoUrl, "videos", publicBaseUrl);
5531
5653
  return {
5532
5654
  created: util_default.unixTimestamp(),
5533
5655
  data: [{
5534
- url: videoUrl,
5656
+ url: localVideoUrl,
5535
5657
  revised_prompt: prompt
5536
5658
  }]
5537
5659
  };
@@ -5551,13 +5673,32 @@ var routes_default = [
5551
5673
  {
5552
5674
  get: {
5553
5675
  "/": async () => {
5554
- const content = await fs8.readFile("public/welcome.html");
5676
+ const content = await fs9.readFile("public/welcome.html");
5555
5677
  return new Response(content, {
5556
5678
  type: "html",
5557
5679
  headers: {
5558
5680
  Expires: "-1"
5559
5681
  }
5560
5682
  });
5683
+ },
5684
+ "/public/(.*)": async (request2) => {
5685
+ const rawPath = decodeURIComponent(request2.params[0] || "").replace(/^[/\\]+/, "");
5686
+ if (!rawPath) throw new Error("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
5687
+ const root = path7.resolve(config_default.system.publicDirPath);
5688
+ const filePath = path7.resolve(root, rawPath);
5689
+ const relative = path7.relative(root, filePath);
5690
+ if (relative.startsWith("..") || path7.isAbsolute(relative)) {
5691
+ throw new Error("\u975E\u6CD5\u6587\u4EF6\u8DEF\u5F84");
5692
+ }
5693
+ if (!await fs9.pathExists(filePath)) {
5694
+ throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
5695
+ }
5696
+ return new Response(fs9.createReadStream(filePath), {
5697
+ type: mime4.getType(filePath) || "application/octet-stream",
5698
+ headers: {
5699
+ "Cache-Control": "public, max-age=31536000, immutable"
5700
+ }
5701
+ });
5561
5702
  }
5562
5703
  }
5563
5704
  },
@@ -5585,4 +5726,4 @@ export {
5585
5726
  generateSeedanceVideo,
5586
5727
  routes_default
5587
5728
  };
5588
- //# sourceMappingURL=chunk-KHOQ4PCS.js.map
5729
+ //# sourceMappingURL=chunk-YJIZUPUG.js.map