koishi-plugin-aka-ai-generator 0.7.0 → 0.7.1

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/lib/index.js CHANGED
@@ -886,7 +886,7 @@ var YunwuVideoProvider = class {
886
886
  }
887
887
  /**
888
888
  * 创建视频生成任务
889
- * API: POST /v1/videos/generations
889
+ * API: POST /v1/video/create
890
890
  */
891
891
  async createVideoTask(prompt, imageUrl, options) {
892
892
  const { logger, ctx } = this.config;
@@ -898,64 +898,127 @@ var YunwuVideoProvider = class {
898
898
  this.config.apiTimeout,
899
899
  logger
900
900
  );
901
+ let orientation = "landscape";
902
+ if (options?.aspectRatio === "9:16") {
903
+ orientation = "portrait";
904
+ } else if (options?.aspectRatio === "1:1") {
905
+ orientation = "portrait";
906
+ }
907
+ let duration = options?.duration || 15;
908
+ if (duration < 15) {
909
+ duration = 15;
910
+ } else if (duration > 25) {
911
+ duration = 25;
912
+ } else if (duration <= 20) {
913
+ duration = 15;
914
+ } else {
915
+ duration = 25;
916
+ }
901
917
  const requestBody = {
918
+ images: [`data:${mimeType};base64,${imageBase64}`],
902
919
  model: this.config.modelId,
920
+ orientation,
903
921
  prompt,
904
- image: `data:${mimeType};base64,${imageBase64}`,
905
- duration: options?.duration || 5,
906
- aspect_ratio: options?.aspectRatio || "16:9"
922
+ size: "large",
923
+ // 高清1080p
924
+ duration,
925
+ watermark: true,
926
+ // 默认优先无水印,出错会兜底到有水印
927
+ private: false
928
+ // 默认视频会发布
907
929
  };
908
- if (options?.fps) {
909
- requestBody.fps = options.fps;
910
- }
911
930
  logger?.info("提交视频生成任务", {
912
931
  model: this.config.modelId,
913
932
  promptLength: prompt.length,
914
933
  duration: requestBody.duration,
915
- aspectRatio: requestBody.aspect_ratio
934
+ orientation: requestBody.orientation
916
935
  });
917
936
  const response = await ctx.http.post(
918
- `${this.config.apiBase}/v1/videos/generations`,
937
+ `${this.config.apiBase}/v1/video/create`,
919
938
  requestBody,
920
939
  {
921
940
  headers: {
922
941
  "Authorization": `Bearer ${this.config.apiKey}`,
923
- "Content-Type": "application/json"
942
+ "Content-Type": "application/json",
943
+ "Accept": "application/json"
924
944
  },
925
945
  timeout: this.config.apiTimeout * 1e3
926
946
  }
927
947
  );
928
948
  if (response.error) {
929
- throw new Error(sanitizeString(response.error.message || "创建任务失败"));
949
+ const errorMsg = response.error.message || response.error.type || "创建任务失败";
950
+ throw new Error(sanitizeString(errorMsg));
951
+ }
952
+ if (response.status && response.status >= 400) {
953
+ const errorMsg = response.data?.error?.message || response.data?.error || response.statusText || "创建任务失败";
954
+ logger?.error("API 返回错误状态", { status: response.status, error: errorMsg, response: response.data });
955
+ throw new Error(sanitizeString(errorMsg));
930
956
  }
931
- const taskId = response.id || response.task_id || response.data?.id;
957
+ const taskId = response.id || response.data?.id;
932
958
  if (!taskId) {
933
959
  logger?.error("未能获取任务ID", { response });
934
- throw new Error("未能获取任务ID");
960
+ throw new Error("未能获取任务ID,请检查 API 响应格式");
935
961
  }
936
962
  logger?.info("视频任务已创建", { taskId });
937
963
  return taskId;
938
964
  } catch (error) {
939
965
  logger?.error("创建视频任务失败", { error: sanitizeError(error) });
940
- throw new Error(`创建视频任务失败: ${sanitizeString(error.message)}`);
966
+ let errorMessage = error.message || "创建视频任务失败";
967
+ if (error.response) {
968
+ const responseData = error.response.data;
969
+ if (responseData?.error) {
970
+ errorMessage = responseData.error.message || responseData.error.type || errorMessage;
971
+ } else if (responseData?.message) {
972
+ errorMessage = responseData.message;
973
+ }
974
+ } else if (error.response?.data?.error) {
975
+ errorMessage = error.response.data.error.message || error.response.data.error.type || errorMessage;
976
+ }
977
+ throw new Error(`创建视频任务失败: ${sanitizeString(errorMessage)}`);
941
978
  }
942
979
  }
943
980
  /**
944
981
  * 查询任务状态
945
- * API: GET /v1/videos/generations/{taskId}
982
+ * API: GET /v1/video/{taskId} (根据创建端点的模式推断)
946
983
  */
947
984
  async queryTaskStatus(taskId) {
948
985
  const { logger, ctx } = this.config;
949
986
  try {
950
- const response = await ctx.http.get(
951
- `${this.config.apiBase}/v1/videos/generations/${taskId}`,
952
- {
953
- headers: {
954
- "Authorization": `Bearer ${this.config.apiKey}`
955
- },
956
- timeout: this.config.apiTimeout * 1e3
987
+ const possibleEndpoints = [
988
+ `/v1/video/${taskId}`,
989
+ `/v1/video/status/${taskId}`,
990
+ `/v1/videos/generations/${taskId}`
991
+ ];
992
+ let response = null;
993
+ let lastError = null;
994
+ for (const endpoint of possibleEndpoints) {
995
+ try {
996
+ response = await ctx.http.get(
997
+ `${this.config.apiBase}${endpoint}`,
998
+ {
999
+ headers: {
1000
+ "Authorization": `Bearer ${this.config.apiKey}`,
1001
+ "Accept": "application/json"
1002
+ },
1003
+ timeout: this.config.apiTimeout * 1e3
1004
+ }
1005
+ );
1006
+ if (response && !response.error) {
1007
+ logger?.debug("查询任务状态成功", { taskId, endpoint });
1008
+ break;
1009
+ }
1010
+ } catch (err) {
1011
+ lastError = err;
1012
+ if (err.response?.status === 404 && possibleEndpoints.indexOf(endpoint) < possibleEndpoints.length - 1) {
1013
+ logger?.debug("尝试下一个查询端点", { taskId, endpoint, nextEndpoint: possibleEndpoints[possibleEndpoints.indexOf(endpoint) + 1] });
1014
+ continue;
1015
+ }
1016
+ throw err;
957
1017
  }
958
- );
1018
+ }
1019
+ if (!response) {
1020
+ throw lastError || new Error("所有查询端点都失败");
1021
+ }
959
1022
  const status = response.status || response.data?.status || "pending";
960
1023
  const videoUrl = response.video_url || response.url || response.data?.video_url || response.data?.url;
961
1024
  return {
@@ -967,7 +1030,11 @@ var YunwuVideoProvider = class {
967
1030
  };
968
1031
  } catch (error) {
969
1032
  logger?.error("查询任务状态失败", { taskId, error: sanitizeError(error) });
970
- throw new Error(`查询任务失败: ${sanitizeString(error.message)}`);
1033
+ let errorMessage = error.message || "查询任务失败";
1034
+ if (error.response?.data?.error) {
1035
+ errorMessage = error.response.data.error.message || error.response.data.error.type || errorMessage;
1036
+ }
1037
+ throw new Error(`查询任务失败: ${sanitizeString(errorMessage)}`);
971
1038
  }
972
1039
  }
973
1040
  /**
@@ -1595,19 +1662,19 @@ var Config = import_koishi2.Schema.intersect([
1595
1662
  videoStyles: import_koishi2.Schema.array(import_koishi2.Schema.object({
1596
1663
  commandName: import_koishi2.Schema.string().required().description("命令名称").role("table-cell", { width: 100 }),
1597
1664
  prompt: import_koishi2.Schema.string().role("textarea", { rows: 2 }).required().description("视频描述 prompt"),
1598
- duration: import_koishi2.Schema.number().min(3).max(10).description("视频时长(秒)"),
1665
+ duration: import_koishi2.Schema.number().default(15).description("视频时长(秒,仅支持 15 或 25)"),
1599
1666
  aspectRatio: import_koishi2.Schema.string().description("宽高比(如 16:9)")
1600
1667
  })).role("table").default([
1601
1668
  {
1602
1669
  commandName: "慢动作视频",
1603
1670
  prompt: "缓慢流畅的运镜,展现细节和质感",
1604
- duration: 8,
1671
+ duration: 25,
1605
1672
  aspectRatio: "16:9"
1606
1673
  },
1607
1674
  {
1608
1675
  commandName: "快节奏视频",
1609
1676
  prompt: "快速动态的场景变化,充满活力",
1610
- duration: 5,
1677
+ duration: 15,
1611
1678
  aspectRatio: "16:9"
1612
1679
  }
1613
1680
  ]).description("视频风格预设")
@@ -2137,7 +2204,7 @@ ${infoParts.join("\n")}`;
2137
2204
  }
2138
2205
  }
2139
2206
  if (config.enableVideoGeneration && videoProvider) {
2140
- ctx.command("图生视频 [img:text]", "根据图片和描述生成视频").option("duration", "-d <duration:number> 视频时长(3-10秒)").option("ratio", "-r <ratio:string> 宽高比(16:9, 9:16, 1:1)").action(async ({ session, options }, img) => {
2207
+ ctx.command("图生视频 [img:text]", "根据图片和描述生成视频").option("duration", "-d <duration:number> 视频时长(15 或 25 秒)").option("ratio", "-r <ratio:string> 宽高比(16:9, 9:16, 1:1)").action(async ({ session, options }, img) => {
2141
2208
  if (!session?.userId) return "会话无效";
2142
2209
  const userId = session.userId;
2143
2210
  const userName = session.username || userId || "未知用户";
@@ -2177,9 +2244,9 @@ ${infoParts.join("\n")}`;
2177
2244
  }
2178
2245
  prompt = text;
2179
2246
  }
2180
- const duration = options?.duration || 5;
2181
- if (duration < 3 || duration > 10) {
2182
- return "视频时长必须在 3-10 秒之间";
2247
+ const duration = options?.duration || 15;
2248
+ if (duration !== 15 && duration !== 25) {
2249
+ return "视频时长必须是 15 或 25 秒";
2183
2250
  }
2184
2251
  const ratio = options?.ratio || "16:9";
2185
2252
  const validRatios = ["16:9", "9:16", "1:1"];
@@ -2289,7 +2356,7 @@ ${infoParts.join("\n")}`;
2289
2356
  finalPrompt,
2290
2357
  imageUrls[0],
2291
2358
  {
2292
- duration: style.duration || 5,
2359
+ duration: style.duration || 15,
2293
2360
  aspectRatio: style.aspectRatio || "16:9"
2294
2361
  },
2295
2362
  config.videoMaxWaitTime
@@ -9,12 +9,12 @@ export declare class YunwuVideoProvider implements VideoProvider {
9
9
  constructor(config: YunwuVideoConfig);
10
10
  /**
11
11
  * 创建视频生成任务
12
- * API: POST /v1/videos/generations
12
+ * API: POST /v1/video/create
13
13
  */
14
14
  createVideoTask(prompt: string, imageUrl: string, options?: VideoGenerationOptions): Promise<string>;
15
15
  /**
16
16
  * 查询任务状态
17
- * API: GET /v1/videos/generations/{taskId}
17
+ * API: GET /v1/video/{taskId} (根据创建端点的模式推断)
18
18
  */
19
19
  queryTaskStatus(taskId: string): Promise<VideoTaskStatus>;
20
20
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-aka-ai-generator",
3
3
  "description": "自用AI生成插件(GPTGod & Yunwu)",
4
- "version": "0.7.0",
4
+ "version": "0.7.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [