koishi-plugin-aka-ai-generator 0.6.15 → 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.d.ts CHANGED
@@ -13,6 +13,12 @@ export interface StyleConfig {
13
13
  export interface StyleGroupConfig {
14
14
  prompts: StyleConfig[];
15
15
  }
16
+ export interface VideoStyleConfig {
17
+ commandName: string;
18
+ prompt: string;
19
+ duration?: number;
20
+ aspectRatio?: string;
21
+ }
16
22
  export interface Config {
17
23
  provider: ImageProvider;
18
24
  yunwuApiKey: string;
@@ -35,6 +41,11 @@ export interface Config {
35
41
  logLevel: 'info' | 'debug';
36
42
  securityBlockWindow: number;
37
43
  securityBlockWarningThreshold: number;
44
+ enableVideoGeneration: boolean;
45
+ videoModelId: string;
46
+ videoMaxWaitTime: number;
47
+ videoCreditsMultiplier: number;
48
+ videoStyles: VideoStyleConfig[];
38
49
  }
39
50
  export declare const Config: Schema<Config>;
40
51
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -875,6 +875,214 @@ var GeminiProvider = class {
875
875
  }
876
876
  };
877
877
 
878
+ // src/providers/yunwu-video.ts
879
+ var YunwuVideoProvider = class {
880
+ static {
881
+ __name(this, "YunwuVideoProvider");
882
+ }
883
+ config;
884
+ constructor(config) {
885
+ this.config = config;
886
+ }
887
+ /**
888
+ * 创建视频生成任务
889
+ * API: POST /v1/video/create
890
+ */
891
+ async createVideoTask(prompt, imageUrl, options) {
892
+ const { logger, ctx } = this.config;
893
+ try {
894
+ logger?.info("下载输入图片", { imageUrl });
895
+ const { data: imageBase64, mimeType } = await downloadImageAsBase64(
896
+ ctx,
897
+ imageUrl,
898
+ this.config.apiTimeout,
899
+ logger
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
+ }
917
+ const requestBody = {
918
+ images: [`data:${mimeType};base64,${imageBase64}`],
919
+ model: this.config.modelId,
920
+ orientation,
921
+ prompt,
922
+ size: "large",
923
+ // 高清1080p
924
+ duration,
925
+ watermark: true,
926
+ // 默认优先无水印,出错会兜底到有水印
927
+ private: false
928
+ // 默认视频会发布
929
+ };
930
+ logger?.info("提交视频生成任务", {
931
+ model: this.config.modelId,
932
+ promptLength: prompt.length,
933
+ duration: requestBody.duration,
934
+ orientation: requestBody.orientation
935
+ });
936
+ const response = await ctx.http.post(
937
+ `${this.config.apiBase}/v1/video/create`,
938
+ requestBody,
939
+ {
940
+ headers: {
941
+ "Authorization": `Bearer ${this.config.apiKey}`,
942
+ "Content-Type": "application/json",
943
+ "Accept": "application/json"
944
+ },
945
+ timeout: this.config.apiTimeout * 1e3
946
+ }
947
+ );
948
+ if (response.error) {
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));
956
+ }
957
+ const taskId = response.id || response.data?.id;
958
+ if (!taskId) {
959
+ logger?.error("未能获取任务ID", { response });
960
+ throw new Error("未能获取任务ID,请检查 API 响应格式");
961
+ }
962
+ logger?.info("视频任务已创建", { taskId });
963
+ return taskId;
964
+ } catch (error) {
965
+ logger?.error("创建视频任务失败", { error: sanitizeError(error) });
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)}`);
978
+ }
979
+ }
980
+ /**
981
+ * 查询任务状态
982
+ * API: GET /v1/video/{taskId} (根据创建端点的模式推断)
983
+ */
984
+ async queryTaskStatus(taskId) {
985
+ const { logger, ctx } = this.config;
986
+ try {
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;
1017
+ }
1018
+ }
1019
+ if (!response) {
1020
+ throw lastError || new Error("所有查询端点都失败");
1021
+ }
1022
+ const status = response.status || response.data?.status || "pending";
1023
+ const videoUrl = response.video_url || response.url || response.data?.video_url || response.data?.url;
1024
+ return {
1025
+ status,
1026
+ taskId,
1027
+ videoUrl,
1028
+ error: response.error || response.data?.error,
1029
+ progress: response.progress || response.data?.progress
1030
+ };
1031
+ } catch (error) {
1032
+ logger?.error("查询任务状态失败", { taskId, error: sanitizeError(error) });
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)}`);
1038
+ }
1039
+ }
1040
+ /**
1041
+ * 轮询等待任务完成
1042
+ */
1043
+ async pollTaskCompletion(taskId, maxWaitTime = 300, pollInterval = 3, onProgress) {
1044
+ const { logger } = this.config;
1045
+ const startTime = Date.now();
1046
+ while (true) {
1047
+ const elapsed = (Date.now() - startTime) / 1e3;
1048
+ if (elapsed > maxWaitTime) {
1049
+ logger?.warn("视频生成超时", { taskId, elapsed, maxWaitTime });
1050
+ throw new Error(`视频生成超时(已等待${Math.floor(elapsed)}秒),任务ID: ${taskId}
1051
+ 请使用"查询视频 ${taskId}"命令稍后查询结果`);
1052
+ }
1053
+ const status = await this.queryTaskStatus(taskId);
1054
+ logger?.debug("任务状态", { taskId, status: status.status, elapsed: Math.floor(elapsed) });
1055
+ if (onProgress) {
1056
+ await onProgress(status);
1057
+ }
1058
+ if (status.status === "completed" && status.videoUrl) {
1059
+ logger?.info("视频生成完成", { taskId, elapsed: Math.floor(elapsed) });
1060
+ return status.videoUrl;
1061
+ }
1062
+ if (status.status === "failed") {
1063
+ throw new Error(status.error || "视频生成失败");
1064
+ }
1065
+ await new Promise((resolve) => setTimeout(resolve, pollInterval * 1e3));
1066
+ }
1067
+ }
1068
+ /**
1069
+ * 生成视频(主入口)
1070
+ */
1071
+ async generateVideo(prompt, imageUrl, options, maxWaitTime = 300) {
1072
+ const { logger } = this.config;
1073
+ try {
1074
+ logger?.info("开始生成视频", { prompt, imageUrl, options });
1075
+ const taskId = await this.createVideoTask(prompt, imageUrl, options);
1076
+ const videoUrl = await this.pollTaskCompletion(taskId, maxWaitTime);
1077
+ logger?.info("视频生成完成", { taskId, videoUrl });
1078
+ return videoUrl;
1079
+ } catch (error) {
1080
+ logger?.error("视频生成失败", { error: sanitizeError(error) });
1081
+ throw error;
1082
+ }
1083
+ }
1084
+ };
1085
+
878
1086
  // src/providers/index.ts
879
1087
  function createImageProvider(config) {
880
1088
  switch (config.provider) {
@@ -1444,6 +1652,32 @@ var Config = import_koishi2.Schema.intersect([
1444
1652
  styleGroups: import_koishi2.Schema.dict(import_koishi2.Schema.object({
1445
1653
  prompts: import_koishi2.Schema.array(StyleItemSchema).role("table").default([]).description("属于该类型的 prompt 列表")
1446
1654
  })).role("table").default({}).description("按类型管理的 prompt 组,键名即为分组名称")
1655
+ }),
1656
+ // 视频生成配置
1657
+ import_koishi2.Schema.object({
1658
+ enableVideoGeneration: import_koishi2.Schema.boolean().default(false).description("启用图生成视频功能(消耗较大,需谨慎开启)"),
1659
+ videoModelId: import_koishi2.Schema.string().default("sora-2").description("视频生成模型ID (sora-2 或 sora-2-pro)"),
1660
+ videoMaxWaitTime: import_koishi2.Schema.number().default(300).min(60).max(600).description("视频生成最大等待时间(秒),超时后可异步查询"),
1661
+ videoCreditsMultiplier: import_koishi2.Schema.number().default(5).min(1).max(20).description("视频生成积分倍数(相对于图片生成,默认5倍)"),
1662
+ videoStyles: import_koishi2.Schema.array(import_koishi2.Schema.object({
1663
+ commandName: import_koishi2.Schema.string().required().description("命令名称").role("table-cell", { width: 100 }),
1664
+ prompt: import_koishi2.Schema.string().role("textarea", { rows: 2 }).required().description("视频描述 prompt"),
1665
+ duration: import_koishi2.Schema.number().default(15).description("视频时长(秒,仅支持 15 或 25)"),
1666
+ aspectRatio: import_koishi2.Schema.string().description("宽高比(如 16:9)")
1667
+ })).role("table").default([
1668
+ {
1669
+ commandName: "慢动作视频",
1670
+ prompt: "缓慢流畅的运镜,展现细节和质感",
1671
+ duration: 25,
1672
+ aspectRatio: "16:9"
1673
+ },
1674
+ {
1675
+ commandName: "快节奏视频",
1676
+ prompt: "快速动态的场景变化,充满活力",
1677
+ duration: 15,
1678
+ aspectRatio: "16:9"
1679
+ }
1680
+ ]).description("视频风格预设")
1447
1681
  })
1448
1682
  ]);
1449
1683
  function apply(ctx, config) {
@@ -1467,6 +1701,19 @@ function apply(ctx, config) {
1467
1701
  }
1468
1702
  __name(getProviderInstance, "getProviderInstance");
1469
1703
  const modelMappingIndex = buildModelMappingIndex(config.modelMappings);
1704
+ let videoProvider = null;
1705
+ if (config.enableVideoGeneration) {
1706
+ videoProvider = new YunwuVideoProvider({
1707
+ apiKey: config.yunwuApiKey,
1708
+ modelId: config.videoModelId,
1709
+ apiBase: "https://yunwu.ai",
1710
+ apiTimeout: config.apiTimeout,
1711
+ logLevel: config.logLevel,
1712
+ logger,
1713
+ ctx
1714
+ });
1715
+ logger.info(`视频生成功能已启用 (模型: ${config.videoModelId})`);
1716
+ }
1470
1717
  const styleDefinitions = collectStyleDefinitions();
1471
1718
  function collectStyleDefinitions() {
1472
1719
  const unique = /* @__PURE__ */ new Map();
@@ -1956,6 +2203,181 @@ ${infoParts.join("\n")}`;
1956
2203
  }
1957
2204
  }
1958
2205
  }
2206
+ if (config.enableVideoGeneration && videoProvider) {
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) => {
2208
+ if (!session?.userId) return "会话无效";
2209
+ const userId = session.userId;
2210
+ const userName = session.username || userId || "未知用户";
2211
+ const videoCredits = config.videoCreditsMultiplier;
2212
+ const limitCheck = await userManager.checkAndReserveQuota(
2213
+ userId,
2214
+ userName,
2215
+ videoCredits,
2216
+ config
2217
+ );
2218
+ if (!limitCheck.allowed) {
2219
+ return limitCheck.message;
2220
+ }
2221
+ if (!userManager.startTask(userId)) {
2222
+ return "您有一个任务正在进行中,请等待完成";
2223
+ }
2224
+ try {
2225
+ const inputResult = await getInputData(session, img, "single");
2226
+ if ("error" in inputResult) {
2227
+ return inputResult.error;
2228
+ }
2229
+ const { images: imageUrls, text: extraText } = inputResult;
2230
+ if (imageUrls.length === 0) {
2231
+ return "未检测到输入图片,请发送一张图片";
2232
+ }
2233
+ let prompt = extraText || "";
2234
+ if (!prompt) {
2235
+ await session.send("请输入视频描述(描述视频中的动作和场景变化)\n提示:描述越详细,生成效果越好");
2236
+ const promptMsg = await session.prompt(3e4);
2237
+ if (!promptMsg) {
2238
+ return "等待超时";
2239
+ }
2240
+ const elements = import_koishi2.h.parse(promptMsg);
2241
+ const text = import_koishi2.h.select(elements, "text").map((e) => e.attrs.content).join(" ").trim();
2242
+ if (!text) {
2243
+ return "未检测到描述";
2244
+ }
2245
+ prompt = text;
2246
+ }
2247
+ const duration = options?.duration || 15;
2248
+ if (duration !== 15 && duration !== 25) {
2249
+ return "视频时长必须是 15 或 25 秒";
2250
+ }
2251
+ const ratio = options?.ratio || "16:9";
2252
+ const validRatios = ["16:9", "9:16", "1:1"];
2253
+ if (!validRatios.includes(ratio)) {
2254
+ return `宽高比必须是以下之一: ${validRatios.join(", ")}`;
2255
+ }
2256
+ await session.send(
2257
+ `🎬 开始生成视频...
2258
+ 📝 描述:${prompt}
2259
+ ⏱️ 时长:${duration}秒
2260
+ 📐 宽高比:${ratio}
2261
+ ⚠️ 预计需要 1-3 分钟,请耐心等待
2262
+ 💡 提示:生成过程中可继续使用其他功能`
2263
+ );
2264
+ const startTime = Date.now();
2265
+ const videoUrl = await videoProvider.generateVideo(
2266
+ prompt,
2267
+ imageUrls[0],
2268
+ {
2269
+ duration,
2270
+ aspectRatio: ratio
2271
+ },
2272
+ config.videoMaxWaitTime
2273
+ );
2274
+ await recordUserUsage(session, "图生视频", videoCredits, false);
2275
+ await session.send(import_koishi2.h.video(videoUrl));
2276
+ const totalTime = Math.floor((Date.now() - startTime) / 1e3);
2277
+ await session.send(`✅ 视频生成完成!(耗时 ${totalTime} 秒)`);
2278
+ } catch (error) {
2279
+ logger.error("视频生成失败", { userId, error: sanitizeError(error) });
2280
+ const errorMsg = error.message || "";
2281
+ if (errorMsg.includes("任务ID:")) {
2282
+ return errorMsg;
2283
+ }
2284
+ return `视频生成失败:${sanitizeString(errorMsg)}`;
2285
+ } finally {
2286
+ userManager.endTask(userId);
2287
+ }
2288
+ });
2289
+ }
2290
+ if (config.enableVideoGeneration && videoProvider) {
2291
+ ctx.command("查询视频 <taskId:string>", "根据任务ID查询视频生成状态").action(async ({ session }, taskId) => {
2292
+ if (!session?.userId) return "会话无效";
2293
+ if (!taskId || !taskId.trim()) {
2294
+ return "请提供任务ID,格式:查询视频 <任务ID>";
2295
+ }
2296
+ try {
2297
+ await session.send("🔍 正在查询视频生成状态...");
2298
+ const status = await videoProvider.queryTaskStatus(taskId.trim());
2299
+ if (status.status === "completed" && status.videoUrl) {
2300
+ await session.send(import_koishi2.h.video(status.videoUrl));
2301
+ return "✅ 视频已生成完成!";
2302
+ } else if (status.status === "processing" || status.status === "pending") {
2303
+ const progressText = status.progress ? `(进度:${status.progress}%)` : "";
2304
+ return `⏳ 视频正在生成中${progressText},请稍后再次查询
2305
+ 任务ID:${taskId}`;
2306
+ } else if (status.status === "failed") {
2307
+ return `❌ 视频生成失败:${status.error || "未知错误"}`;
2308
+ } else {
2309
+ return `❓ 未知状态:${status.status}`;
2310
+ }
2311
+ } catch (error) {
2312
+ logger.error("查询视频任务失败", { taskId, error: sanitizeError(error) });
2313
+ return `查询失败:${sanitizeString(error.message)}`;
2314
+ }
2315
+ });
2316
+ }
2317
+ if (config.enableVideoGeneration && videoProvider && config.videoStyles?.length > 0) {
2318
+ for (const style of config.videoStyles) {
2319
+ if (!style.commandName || !style.prompt) continue;
2320
+ ctx.command(`${style.commandName} [img:text]`, "视频风格转换").action(async ({ session }, img) => {
2321
+ if (!session?.userId) return "会话无效";
2322
+ const userId = session.userId;
2323
+ const userName = session.username || userId || "未知用户";
2324
+ const videoCredits = config.videoCreditsMultiplier;
2325
+ const limitCheck = await userManager.checkAndReserveQuota(
2326
+ userId,
2327
+ userName,
2328
+ videoCredits,
2329
+ config
2330
+ );
2331
+ if (!limitCheck.allowed) {
2332
+ return limitCheck.message;
2333
+ }
2334
+ if (!userManager.startTask(userId)) {
2335
+ return "您有一个任务正在进行中,请等待完成";
2336
+ }
2337
+ try {
2338
+ const inputResult = await getInputData(session, img, "single");
2339
+ if ("error" in inputResult) {
2340
+ return inputResult.error;
2341
+ }
2342
+ const { images: imageUrls, text: extraText } = inputResult;
2343
+ if (imageUrls.length === 0) {
2344
+ return "未检测到输入图片,请发送一张图片";
2345
+ }
2346
+ let finalPrompt = style.prompt;
2347
+ if (extraText) {
2348
+ finalPrompt += " - " + extraText;
2349
+ }
2350
+ await session.send(
2351
+ `🎬 开始生成视频(${style.commandName})...
2352
+ 📝 描述:${finalPrompt}
2353
+ ⏱️ 预计需要 1-3 分钟`
2354
+ );
2355
+ const videoUrl = await videoProvider.generateVideo(
2356
+ finalPrompt,
2357
+ imageUrls[0],
2358
+ {
2359
+ duration: style.duration || 15,
2360
+ aspectRatio: style.aspectRatio || "16:9"
2361
+ },
2362
+ config.videoMaxWaitTime
2363
+ );
2364
+ await recordUserUsage(session, style.commandName, videoCredits, false);
2365
+ await session.send(import_koishi2.h.video(videoUrl));
2366
+ await session.send(`✅ 视频生成完成!`);
2367
+ } catch (error) {
2368
+ logger.error("视频风格转换失败", { userId, style: style.commandName, error: sanitizeError(error) });
2369
+ const errorMsg = error.message || "";
2370
+ if (errorMsg.includes("任务ID:")) {
2371
+ return errorMsg;
2372
+ }
2373
+ return `视频生成失败:${sanitizeString(errorMsg)}`;
2374
+ } finally {
2375
+ userManager.endTask(userId);
2376
+ }
2377
+ });
2378
+ logger.info(`已注册视频风格命令: ${style.commandName}`);
2379
+ }
2380
+ }
1959
2381
  ctx.command(`${COMMANDS.TXT_TO_IMG} [prompt:text]`, "根据文字描述生成图像").option("num", "-n <num:number> 生成图片数量 (1-4)").action(async ({ session, options }, prompt) => {
1960
2382
  if (!session?.userId) return "会话无效";
1961
2383
  const numImages = options?.num || config.defaultNumImages;
@@ -2398,6 +2820,17 @@ Prompt: ${prompt}`);
2398
2820
  result += `• ${cmd.name} - ${cmd.description}
2399
2821
  `;
2400
2822
  });
2823
+ if (config.enableVideoGeneration) {
2824
+ result += "\n🎥 视频生成功能:\n";
2825
+ result += "• 图生视频 - 根据图片和描述生成视频\n";
2826
+ result += "• 查询视频 - 根据任务ID查询视频状态\n";
2827
+ if (config.videoStyles?.length > 0) {
2828
+ config.videoStyles.forEach((style) => {
2829
+ result += `• ${style.commandName} - 视频风格预设
2830
+ `;
2831
+ });
2832
+ }
2833
+ }
2401
2834
  if (userIsAdmin) {
2402
2835
  result += "\n🔧 管理员指令:\n";
2403
2836
  commandRegistry.adminCommands.forEach((cmd) => {
@@ -21,3 +21,5 @@ export declare function createImageProvider(config: ProviderFactoryConfig): Imag
21
21
  export { ImageProvider } from './types';
22
22
  export { GptGodProvider } from './gptgod';
23
23
  export { GeminiProvider } from './gemini';
24
+ export { VideoProvider, VideoTaskStatus, VideoGenerationOptions } from './types';
25
+ export { YunwuVideoProvider } from './yunwu-video';
@@ -15,4 +15,32 @@ export interface ProviderConfig {
15
15
  logger: any;
16
16
  ctx: any;
17
17
  }
18
+ export interface VideoGenerationOptions {
19
+ duration?: number;
20
+ aspectRatio?: string;
21
+ fps?: number;
22
+ style?: string;
23
+ }
24
+ export interface VideoTaskStatus {
25
+ status: 'pending' | 'processing' | 'completed' | 'failed';
26
+ taskId: string;
27
+ videoUrl?: string;
28
+ error?: string;
29
+ progress?: number;
30
+ }
31
+ export interface VideoProvider {
32
+ /**
33
+ * 创建视频生成任务
34
+ * @returns 任务ID
35
+ */
36
+ createVideoTask(prompt: string, imageUrl: string, options?: VideoGenerationOptions): Promise<string>;
37
+ /**
38
+ * 查询任务状态
39
+ */
40
+ queryTaskStatus(taskId: string): Promise<VideoTaskStatus>;
41
+ /**
42
+ * 生成视频(包含轮询等待)
43
+ */
44
+ generateVideo(prompt: string, imageUrl: string, options?: VideoGenerationOptions, maxWaitTime?: number): Promise<string>;
45
+ }
18
46
  export { sanitizeError, sanitizeString } from './utils';
@@ -0,0 +1,28 @@
1
+ import { VideoProvider, VideoTaskStatus, VideoGenerationOptions, ProviderConfig } from './types';
2
+ export interface YunwuVideoConfig extends ProviderConfig {
3
+ apiKey: string;
4
+ modelId: string;
5
+ apiBase: string;
6
+ }
7
+ export declare class YunwuVideoProvider implements VideoProvider {
8
+ private config;
9
+ constructor(config: YunwuVideoConfig);
10
+ /**
11
+ * 创建视频生成任务
12
+ * API: POST /v1/video/create
13
+ */
14
+ createVideoTask(prompt: string, imageUrl: string, options?: VideoGenerationOptions): Promise<string>;
15
+ /**
16
+ * 查询任务状态
17
+ * API: GET /v1/video/{taskId} (根据创建端点的模式推断)
18
+ */
19
+ queryTaskStatus(taskId: string): Promise<VideoTaskStatus>;
20
+ /**
21
+ * 轮询等待任务完成
22
+ */
23
+ private pollTaskCompletion;
24
+ /**
25
+ * 生成视频(主入口)
26
+ */
27
+ generateVideo(prompt: string, imageUrl: string, options?: VideoGenerationOptions, maxWaitTime?: number): Promise<string>;
28
+ }
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.6.15",
4
+ "version": "0.7.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [