koishi-plugin-aka-ai-generator 0.7.12 → 0.8.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 +136 -59
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -51,7 +51,7 @@ function sanitizeError(error) {
|
|
|
51
51
|
const sanitized = {};
|
|
52
52
|
for (const key in error) {
|
|
53
53
|
const lowerKey = key.toLowerCase();
|
|
54
|
-
if (lowerKey.includes("apikey") || lowerKey.includes("api_key") || lowerKey.includes("
|
|
54
|
+
if (lowerKey.includes("apikey") || lowerKey.includes("api_key") || lowerKey.includes("api-key") || lowerKey === "key" || lowerKey === "authorization" || lowerKey === "token" || lowerKey === "secret" || lowerKey === "password") {
|
|
55
55
|
sanitized[key] = "[REDACTED]";
|
|
56
56
|
continue;
|
|
57
57
|
}
|
|
@@ -64,7 +64,7 @@ function sanitizeError(error) {
|
|
|
64
64
|
__name(sanitizeError, "sanitizeError");
|
|
65
65
|
function sanitizeString(str) {
|
|
66
66
|
if (typeof str !== "string") return str;
|
|
67
|
-
return str.replace(/key["\s:=]+([a-zA-Z0-9_-]{
|
|
67
|
+
return str.replace(/key["'\s:=]+([a-zA-Z0-9_-]{10,})/gi, 'key="[REDACTED]"').replace(/apikey["'\s:=]+([a-zA-Z0-9_-]{10,})/gi, 'apikey="[REDACTED]"').replace(/api_key["'\s:=]+([a-zA-Z0-9_-]{10,})/gi, 'api_key="[REDACTED]"').replace(/api-key["'\s:=]+([a-zA-Z0-9_-]{10,})/gi, 'api-key="[REDACTED]"').replace(/x-api-key["'\s:=]+([a-zA-Z0-9_-]{10,})/gi, 'x-api-key="[REDACTED]"').replace(/authorization["'\s:=]+(Bearer\s+)?([a-zA-Z0-9_-]{10,})/gi, 'authorization="[REDACTED]"').replace(/Bearer\s+([a-zA-Z0-9_-]{10,})/gi, "Bearer [REDACTED]").replace(/([?&])key=([a-zA-Z0-9_-]{10,})/gi, "$1key=[REDACTED]").replace(/([?&])apikey=([a-zA-Z0-9_-]{10,})/gi, "$1apikey=[REDACTED]").replace(/([?&])api_key=([a-zA-Z0-9_-]{10,})/gi, "$1api_key=[REDACTED]").replace(/([?&])token=([a-zA-Z0-9_-]{10,})/gi, "$1token=[REDACTED]").replace(/([?&])access_token=([a-zA-Z0-9_-]{10,})/gi, "$1access_token=[REDACTED]").replace(/sk-[a-zA-Z0-9]{20,}/gi, "[REDACTED-SK]").replace(/AIza[a-zA-Z0-9_-]{30,}/gi, "[REDACTED-GAPI]").replace(/secret["'\s:=]+([a-zA-Z0-9_-]{10,})/gi, 'secret="[REDACTED]"').replace(/password["'\s:=]+([^\s"']{4,})/gi, 'password="[REDACTED]"');
|
|
68
68
|
}
|
|
69
69
|
__name(sanitizeString, "sanitizeString");
|
|
70
70
|
async function downloadImageAsBase64(ctx, url, timeout, logger, maxSize = 10 * 1024 * 1024) {
|
|
@@ -806,7 +806,13 @@ var GeminiProvider = class {
|
|
|
806
806
|
],
|
|
807
807
|
generationConfig: {
|
|
808
808
|
responseModalities: ["IMAGE"]
|
|
809
|
-
}
|
|
809
|
+
},
|
|
810
|
+
safetySettings: [
|
|
811
|
+
{ category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE" },
|
|
812
|
+
{ category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_NONE" },
|
|
813
|
+
{ category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_NONE" },
|
|
814
|
+
{ category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_NONE" }
|
|
815
|
+
]
|
|
810
816
|
};
|
|
811
817
|
logger.debug("调用 Gemini API", { prompt, imageCount: urls.length, numImages, current: i + 1, endpoint });
|
|
812
818
|
try {
|
|
@@ -1771,6 +1777,12 @@ function parseStyleCommandModifiers(argv, imgParam, modelMappingIndex) {
|
|
|
1771
1777
|
flagCandidates.push(token);
|
|
1772
1778
|
index++;
|
|
1773
1779
|
}
|
|
1780
|
+
const debugInfo = {
|
|
1781
|
+
flagCandidates,
|
|
1782
|
+
modelMappingKeys: Array.from(modelMappingIndex.keys()),
|
|
1783
|
+
argsList: argsList.slice(0, 10)
|
|
1784
|
+
// 只取前10个避免太长
|
|
1785
|
+
};
|
|
1774
1786
|
for (const arg of flagCandidates) {
|
|
1775
1787
|
if (!arg.startsWith("-")) continue;
|
|
1776
1788
|
const key = normalizeSuffix(arg);
|
|
@@ -1778,9 +1790,13 @@ function parseStyleCommandModifiers(argv, imgParam, modelMappingIndex) {
|
|
|
1778
1790
|
const mapping = modelMappingIndex.get(key);
|
|
1779
1791
|
if (mapping) {
|
|
1780
1792
|
modifiers.modelMapping = mapping;
|
|
1793
|
+
console.log("[parseStyleCommandModifiers] 找到模型映射", { arg, key, mapping, debugInfo });
|
|
1781
1794
|
break;
|
|
1782
1795
|
}
|
|
1783
1796
|
}
|
|
1797
|
+
if (!modifiers.modelMapping && flagCandidates.some((f) => f.startsWith("-"))) {
|
|
1798
|
+
console.log("[parseStyleCommandModifiers] 未找到模型映射", debugInfo);
|
|
1799
|
+
}
|
|
1784
1800
|
return modifiers;
|
|
1785
1801
|
}
|
|
1786
1802
|
__name(parseStyleCommandModifiers, "parseStyleCommandModifiers");
|
|
@@ -1806,49 +1822,90 @@ var StyleItemSchema = import_koishi2.Schema.object({
|
|
|
1806
1822
|
prompt: import_koishi2.Schema.string().role("textarea", { rows: 4 }).required().description("生成 prompt")
|
|
1807
1823
|
});
|
|
1808
1824
|
var Config = import_koishi2.Schema.intersect([
|
|
1825
|
+
// ===== 1. 供应商选择 =====
|
|
1809
1826
|
import_koishi2.Schema.object({
|
|
1810
1827
|
provider: import_koishi2.Schema.union([
|
|
1811
1828
|
import_koishi2.Schema.const("yunwu").description("云雾 Gemini 服务"),
|
|
1812
1829
|
import_koishi2.Schema.const("gptgod").description("GPTGod 服务"),
|
|
1813
1830
|
import_koishi2.Schema.const("gemini").description("Google Gemini 原生")
|
|
1814
|
-
]).default("yunwu").description("图像生成供应商")
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
+
]).default("yunwu").description("图像生成供应商")
|
|
1832
|
+
}).description("🎨 供应商选择"),
|
|
1833
|
+
// ===== 2. 云雾 API 配置(条件显示) =====
|
|
1834
|
+
import_koishi2.Schema.union([
|
|
1835
|
+
import_koishi2.Schema.object({
|
|
1836
|
+
provider: import_koishi2.Schema.const("yunwu").required(),
|
|
1837
|
+
yunwuApiKey: import_koishi2.Schema.string().role("secret").required().description("云雾 API 密钥"),
|
|
1838
|
+
yunwuModelId: import_koishi2.Schema.string().default("gemini-2.5-flash-image").description("云雾图像生成模型ID")
|
|
1839
|
+
}),
|
|
1840
|
+
import_koishi2.Schema.object({
|
|
1841
|
+
yunwuApiKey: import_koishi2.Schema.string().role("secret").default("").hidden(),
|
|
1842
|
+
yunwuModelId: import_koishi2.Schema.string().default("gemini-2.5-flash-image").hidden()
|
|
1843
|
+
})
|
|
1844
|
+
]),
|
|
1845
|
+
// ===== 3. GPTGod API 配置(条件显示) =====
|
|
1846
|
+
import_koishi2.Schema.union([
|
|
1847
|
+
import_koishi2.Schema.object({
|
|
1848
|
+
provider: import_koishi2.Schema.const("gptgod").required(),
|
|
1849
|
+
gptgodApiKey: import_koishi2.Schema.string().role("secret").required().description("GPTGod API 密钥"),
|
|
1850
|
+
gptgodModelId: import_koishi2.Schema.string().default("nano-banana").description("GPTGod 模型ID")
|
|
1851
|
+
}),
|
|
1852
|
+
import_koishi2.Schema.object({
|
|
1853
|
+
gptgodApiKey: import_koishi2.Schema.string().role("secret").default("").hidden(),
|
|
1854
|
+
gptgodModelId: import_koishi2.Schema.string().default("nano-banana").hidden()
|
|
1855
|
+
})
|
|
1856
|
+
]),
|
|
1857
|
+
// ===== 4. Gemini API 配置(条件显示) =====
|
|
1858
|
+
import_koishi2.Schema.union([
|
|
1859
|
+
import_koishi2.Schema.object({
|
|
1860
|
+
provider: import_koishi2.Schema.const("gemini").required(),
|
|
1861
|
+
geminiApiKey: import_koishi2.Schema.string().role("secret").required().description("Gemini API 密钥"),
|
|
1862
|
+
geminiModelId: import_koishi2.Schema.string().default("gemini-2.5-flash").description("Gemini 模型ID"),
|
|
1863
|
+
geminiApiBase: import_koishi2.Schema.string().default("https://generativelanguage.googleapis.com").description("Gemini API 基础地址")
|
|
1864
|
+
}),
|
|
1865
|
+
import_koishi2.Schema.object({
|
|
1866
|
+
geminiApiKey: import_koishi2.Schema.string().role("secret").default("").hidden(),
|
|
1867
|
+
geminiModelId: import_koishi2.Schema.string().default("gemini-2.5-flash").hidden(),
|
|
1868
|
+
geminiApiBase: import_koishi2.Schema.string().default("https://generativelanguage.googleapis.com").hidden()
|
|
1869
|
+
})
|
|
1870
|
+
]),
|
|
1871
|
+
// ===== 5. 通用设置 =====
|
|
1872
|
+
import_koishi2.Schema.object({
|
|
1831
1873
|
apiTimeout: import_koishi2.Schema.number().default(120).description("API请求超时时间(秒)"),
|
|
1832
1874
|
commandTimeout: import_koishi2.Schema.number().default(180).description("命令执行总超时时间(秒)"),
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1875
|
+
defaultNumImages: import_koishi2.Schema.number().default(1).min(1).max(4).description("默认生成图片数量")
|
|
1876
|
+
}).description("⚙️ 通用设置"),
|
|
1877
|
+
// ===== 6. 限流与配额 =====
|
|
1878
|
+
import_koishi2.Schema.object({
|
|
1836
1879
|
dailyFreeLimit: import_koishi2.Schema.number().default(5).min(1).max(100).description("每日免费调用次数"),
|
|
1837
|
-
// 限流设置
|
|
1838
1880
|
rateLimitWindow: import_koishi2.Schema.number().default(300).min(60).max(3600).description("限流时间窗口(秒)"),
|
|
1839
|
-
rateLimitMax: import_koishi2.Schema.number().default(3).min(1).max(20).description("限流窗口内最大调用次数")
|
|
1840
|
-
|
|
1881
|
+
rateLimitMax: import_koishi2.Schema.number().default(3).min(1).max(20).description("限流窗口内最大调用次数")
|
|
1882
|
+
}).description("🚦 限流与配额"),
|
|
1883
|
+
// ===== 7. 管理员设置 =====
|
|
1884
|
+
import_koishi2.Schema.object({
|
|
1841
1885
|
adminUsers: import_koishi2.Schema.array(import_koishi2.Schema.string()).default([]).description("管理员用户ID列表(不受每日使用限制)"),
|
|
1842
|
-
// 日志级别设置
|
|
1843
1886
|
logLevel: import_koishi2.Schema.union([
|
|
1844
1887
|
import_koishi2.Schema.const("info").description("普通信息"),
|
|
1845
1888
|
import_koishi2.Schema.const("debug").description("完整的debug信息")
|
|
1846
|
-
]).default("info").description("日志输出详细程度")
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1889
|
+
]).default("info").description("日志输出详细程度")
|
|
1890
|
+
}).description("👑 管理员设置"),
|
|
1891
|
+
// ===== 8. 安全策略 =====
|
|
1892
|
+
import_koishi2.Schema.object({
|
|
1893
|
+
securityBlockWindow: import_koishi2.Schema.number().default(600).min(60).max(3600).description("安全策略拦截追踪时间窗口(秒)"),
|
|
1894
|
+
securityBlockWarningThreshold: import_koishi2.Schema.number().default(3).min(1).max(10).description("安全策略拦截警示阈值,连续触发此次数后将发送警示")
|
|
1895
|
+
}).description("🛡️ 安全策略"),
|
|
1896
|
+
// ===== 9. 模型映射 =====
|
|
1897
|
+
import_koishi2.Schema.object({
|
|
1898
|
+
modelMappings: import_koishi2.Schema.array(import_koishi2.Schema.object({
|
|
1899
|
+
suffix: import_koishi2.Schema.string().required().description("指令后缀(例如 4K,对应输入 -4K)"),
|
|
1900
|
+
provider: import_koishi2.Schema.union([
|
|
1901
|
+
import_koishi2.Schema.const("yunwu").description("云雾 Gemini 服务"),
|
|
1902
|
+
import_koishi2.Schema.const("gptgod").description("GPTGod 服务"),
|
|
1903
|
+
import_koishi2.Schema.const("gemini").description("Google Gemini 原生")
|
|
1904
|
+
]).description("可选:覆盖供应商"),
|
|
1905
|
+
modelId: import_koishi2.Schema.string().required().description("触发该后缀时使用的模型 ID")
|
|
1906
|
+
})).role("table").default([]).description("根据 -后缀切换模型/供应商")
|
|
1907
|
+
}).description("🔀 模型映射"),
|
|
1908
|
+
// ===== 10. 风格命令 =====
|
|
1852
1909
|
import_koishi2.Schema.object({
|
|
1853
1910
|
styles: import_koishi2.Schema.array(StyleItemSchema).role("table").default([
|
|
1854
1911
|
{
|
|
@@ -1860,37 +1917,57 @@ var Config = import_koishi2.Schema.intersect([
|
|
|
1860
1917
|
prompt: "请根据用户提供的图片,在严格保持主体身份、外观特征与姿态不变的前提下,生成一张照片级真实感的超写实摄影作品。要求:1. 采用专业相机拍摄(如佳能EOS R5),使用85mm f/1.4人像镜头,呈现柯达Portra 400胶片质感,8K超高清画质,HDR高动态范围,电影级打光效果;2. 画面应具有照片级真实感、超现实主义风格和高细节表现,确保光影、皮肤质感、服饰纹理与背景环境都贴近真实世界;3. 使用自然光影营造真实氛围,呈现raw and natural的原始自然感,具有authentic film snapshot的真实胶片质感;4. 整体需具备tactile feel触感质感和simulated texture模拟纹理细节,可以适度优化噪点与瑕疵,但不要改变主体特征或添加额外元素;5. 整体效果需像专业摄影棚拍摄的真实照片,具有电影级画质;6. 如果主体是人物脸部,脸部生成效果应参考欧美混血白人精致美丽帅气英俊的外观特征进行生成,保持精致立体的五官轮廓、健康光泽的肌肤质感、优雅的气质和自然的表情,确保面部特征协调美观。"
|
|
1861
1918
|
}
|
|
1862
1919
|
]).description("自定义风格命令配置")
|
|
1863
|
-
}),
|
|
1920
|
+
}).description("🎭 风格命令"),
|
|
1921
|
+
// ===== 11. 风格分组 =====
|
|
1864
1922
|
import_koishi2.Schema.object({
|
|
1865
1923
|
styleGroups: import_koishi2.Schema.dict(import_koishi2.Schema.object({
|
|
1866
1924
|
prompts: import_koishi2.Schema.array(StyleItemSchema).role("table").default([]).description("属于该类型的 prompt 列表")
|
|
1867
1925
|
})).role("table").default({}).description("按类型管理的 prompt 组,键名即为分组名称")
|
|
1868
|
-
}),
|
|
1869
|
-
//
|
|
1926
|
+
}).description("📂 风格分组"),
|
|
1927
|
+
// ===== 12. 视频生成(条件显示) =====
|
|
1870
1928
|
import_koishi2.Schema.object({
|
|
1871
|
-
enableVideoGeneration: import_koishi2.Schema.boolean().default(false).description("启用图生成视频功能(消耗较大,需谨慎开启)")
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1929
|
+
enableVideoGeneration: import_koishi2.Schema.boolean().default(false).description("启用图生成视频功能(消耗较大,需谨慎开启)")
|
|
1930
|
+
}).description("🎬 视频生成"),
|
|
1931
|
+
import_koishi2.Schema.union([
|
|
1932
|
+
import_koishi2.Schema.object({
|
|
1933
|
+
enableVideoGeneration: import_koishi2.Schema.const(true).required(),
|
|
1934
|
+
videoProvider: import_koishi2.Schema.union([
|
|
1935
|
+
import_koishi2.Schema.const("yunwu").description("云雾服务")
|
|
1936
|
+
]).default("yunwu").description("视频生成供应商(目前只支持云雾)"),
|
|
1937
|
+
videoApiKey: import_koishi2.Schema.string().role("secret").default("").description("视频生成 API 密钥(独立于图像生成配置)"),
|
|
1938
|
+
videoApiBase: import_koishi2.Schema.string().default("https://yunwu.ai").description("视频生成 API 地址"),
|
|
1939
|
+
videoModelId: import_koishi2.Schema.string().default("sora-2").description("视频生成模型ID (sora-2 或 sora-2-pro)"),
|
|
1940
|
+
videoMaxWaitTime: import_koishi2.Schema.number().default(300).min(60).max(600).description("视频生成最大等待时间(秒)"),
|
|
1941
|
+
videoCreditsMultiplier: import_koishi2.Schema.number().default(5).min(1).max(20).description("视频生成积分倍数(相对于图片生成,默认5倍)"),
|
|
1942
|
+
videoStyles: import_koishi2.Schema.array(import_koishi2.Schema.object({
|
|
1943
|
+
commandName: import_koishi2.Schema.string().required().description("命令名称").role("table-cell", { width: 100 }),
|
|
1944
|
+
prompt: import_koishi2.Schema.string().role("textarea", { rows: 2 }).required().description("视频描述 prompt"),
|
|
1945
|
+
duration: import_koishi2.Schema.number().default(15).description("视频时长(秒,仅支持 15 或 25)"),
|
|
1946
|
+
aspectRatio: import_koishi2.Schema.string().description("宽高比(如 16:9)")
|
|
1947
|
+
})).role("table").default([
|
|
1948
|
+
{
|
|
1949
|
+
commandName: "变视频",
|
|
1950
|
+
prompt: "将该图片生成一段符合产品展现的流畅视频",
|
|
1951
|
+
duration: 15,
|
|
1952
|
+
aspectRatio: "16:9"
|
|
1953
|
+
}
|
|
1954
|
+
]).description("视频风格预设")
|
|
1955
|
+
}),
|
|
1956
|
+
import_koishi2.Schema.object({
|
|
1957
|
+
videoProvider: import_koishi2.Schema.union([import_koishi2.Schema.const("yunwu")]).default("yunwu").hidden(),
|
|
1958
|
+
videoApiKey: import_koishi2.Schema.string().role("secret").default("").hidden(),
|
|
1959
|
+
videoApiBase: import_koishi2.Schema.string().default("https://yunwu.ai").hidden(),
|
|
1960
|
+
videoModelId: import_koishi2.Schema.string().default("sora-2").hidden(),
|
|
1961
|
+
videoMaxWaitTime: import_koishi2.Schema.number().default(300).hidden(),
|
|
1962
|
+
videoCreditsMultiplier: import_koishi2.Schema.number().default(5).hidden(),
|
|
1963
|
+
videoStyles: import_koishi2.Schema.array(import_koishi2.Schema.object({
|
|
1964
|
+
commandName: import_koishi2.Schema.string().required(),
|
|
1965
|
+
prompt: import_koishi2.Schema.string().required(),
|
|
1966
|
+
duration: import_koishi2.Schema.number().default(15),
|
|
1967
|
+
aspectRatio: import_koishi2.Schema.string()
|
|
1968
|
+
})).default([]).hidden()
|
|
1969
|
+
})
|
|
1970
|
+
])
|
|
1894
1971
|
]);
|
|
1895
1972
|
function apply(ctx, config) {
|
|
1896
1973
|
const logger = ctx.logger("aka-ai-generator");
|