koishi-plugin-novelai
Version:
Generate images by diffusion models
976 lines (965 loc) • 82 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name2 in all)
__defProp(target, name2, { get: all[name2], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// data/horde-models.json
var require_horde_models = __commonJS({
"data/horde-models.json"(exports2, module2) {
module2.exports = [
"3DKX",
"526Mix-Animated",
"AAM XL",
"AbsoluteReality",
"Abyss OrangeMix",
"AbyssOrangeMix-AfterDark",
"ACertainThing",
"AIO Pixel Art",
"AlbedoBase XL (SDXL)",
"AMPonyXL",
"Analog Diffusion",
"Analog Madness",
"Animagine XL",
"Anime Illust Diffusion XL",
"Anime Pencil Diffusion",
"Anygen",
"AnyLoRA",
"Anything Diffusion",
"Anything Diffusion Inpainting",
"Anything v3",
"Anything v5",
"App Icon Diffusion",
"Art Of Mtg",
"Aurora",
"A-Zovya RPG Inpainting",
"Babes",
"BB95 Furry Mix",
"BB95 Furry Mix v14",
"Blank Canvas XL",
"BPModel",
"BRA",
"BweshMix",
"CamelliaMix 2.5D",
"Cetus-Mix",
"Char",
"CharHelper",
"Cheese Daddys Landscape Mix",
"Cheyenne",
"ChilloutMix",
"ChromaV5",
"Classic Animation Diffusion",
"Colorful",
"Comic-Diffusion",
"Counterfeit",
"CyberRealistic",
"CyriousMix",
"Dan Mumford Style",
"Dark Sushi Mix",
"Dark Victorian Diffusion",
"Deliberate",
"Deliberate 3.0",
"Deliberate Inpainting",
"DGSpitzer Art Diffusion",
"Disco Elysium",
"Disney Pixar Cartoon Type A",
"DnD Item",
"DnD Map Generator",
"Double Exposure Diffusion",
"Dreamlike Diffusion",
"Dreamlike Photoreal",
"DreamLikeSamKuvshinov",
"Dreamshaper",
"DreamShaper Inpainting",
"DreamShaper XL",
"DucHaiten",
"DucHaiten Classic Anime",
"Dungeons and Diffusion",
"Dungeons n Waifus",
"Edge Of Realism",
"Eimis Anime Diffusion",
"Elldreth's Lucid Mix",
"Elysium Anime",
"Epic Diffusion",
"Epic Diffusion Inpainting",
"Ether Real Mix",
"Experience",
"ExpMix Line",
"FaeTastic",
"Fantasy Card Diffusion",
"Fluffusion",
"Funko Diffusion",
"Furry Epoch",
"Fustercluck",
"Galena Redux",
"Ghibli Diffusion",
"GhostMix",
"GorynichMix",
"Grapefruit Hentai",
"Graphic-Art",
"GTA5 Artwork Diffusion",
"GuFeng",
"GuoFeng",
"HASDX",
"Hassaku",
"Hassanblend",
"Healy's Anime Blend",
"Henmix Real",
"Hentai Diffusion",
"HRL",
"ICBINP - I Can't Believe It's Not Photography",
"ICBINP XL",
"iCoMix",
"iCoMix Inpainting",
"Illuminati Diffusion",
"Inkpunk Diffusion",
"Jim Eidomode",
"JoMad Diffusion",
"Juggernaut XL",
"JWST Deep Space Diffusion",
"Kenshi",
"Laolei New Berry Protogen Mix",
"Lawlas's yiff mix",
"Liberty",
"Lyriel",
"majicMIX realistic",
"Mega Merge Diffusion",
"MeinaMix",
"Microcritters",
"Microworlds",
"Midjourney PaintArt",
"Mistoon Amethyst",
"ModernArt Diffusion",
"Moedel",
"MoistMix",
"MoonMix Fantasy",
"Movie Diffusion",
"Neurogen",
"NeverEnding Dream",
"Nitro Diffusion",
"OpenJourney Diffusion",
"Openniji",
"Papercut Diffusion",
"Pastel Mix",
"Perfect World",
"PFG",
"Photon",
"Poison",
"Pokemon3D",
"Pony Diffusion XL",
"PortraitPlus",
"PPP",
"Pretty 2.5D",
"Project Unreal Engine 5",
"ProtoGen",
"Protogen Anime",
"Protogen Infinity",
"Pulp Vector Art",
"Quiet Goodnight XL",
"Ranma Diffusion",
"RealBiter",
"Real Dos Mix",
"Realisian",
"Realism Engine",
"Realistic Vision",
"Realistic Vision Inpainting",
"Reliberate",
"Rev Animated",
"Robo-Diffusion",
"RPG",
"Samaritan 3d Cartoon",
"Sci-Fi Diffusion",
"SD-Silicon",
"SDXL 1.0",
"Seek.art MEGA",
"Something",
"Stable Cascade 1.0",
"stable_diffusion",
"stable_diffusion_2.1",
"stable_diffusion_inpainting",
"SwamPonyXL",
"SweetBoys 2D",
"ToonYou",
"Trinart Characters",
"Tron Legacy Diffusion",
"Uhmami",
"Ultraskin",
"UMI Olympus",
"Unstable Diffusers XL",
"Unstable Ink Dream",
"URPM",
"Vector Art",
"vectorartz",
"VinteProtogenMix",
"waifu_diffusion",
"Western Animation Diffusion",
"Woop-Woop Photo",
"Yiffy",
"Zack3D",
"Zeipher Female Model"
];
}
});
// data/sd-samplers.json
var require_sd_samplers = __commonJS({
"data/sd-samplers.json"(exports2, module2) {
module2.exports = {
k_dpmpp_2m: "DPM++ 2M",
k_dpmpp_sde: "DPM++ SDE",
k_dpmpp_2m_sde: "DPM++ 2M SDE",
k_dpmpp_2m_sde_heun: "DPM++ 2M SDE Heun",
k_dpmpp_2s_a: "DPM++ 2S a",
k_dpmpp_3m_sde: "DPM++ 3M SDE",
k_euler_a: "Euler a",
k_euler: "Euler",
k_lms: "LMS",
k_heun: "Heun",
k_dpm_2: "DPM2",
k_dpm_2_a: "DPM2 a",
k_dpm_fast: "DPM fast",
k_dpm_ad: "DPM adaptive",
restart: "Restart",
ddim: "DDIM",
plms: "PLMS",
unipc: "UniPC",
k_lcm: "LCM"
};
}
});
// src/locales/zh-CN.yml
var require_zh_CN = __commonJS({
"src/locales/zh-CN.yml"(exports2, module2) {
module2.exports = { commands: { novelai: { description: "AI 画图", usage: "输入用逗号隔开的英文标签,例如 Mr.Quin, dark sword, red eyes。\n查找标签可以使用 Danbooru。\n快来给仓库点个 star 吧:https://github.com/koishijs/novelai-bot", shortcuts: { imagine: "画画|约稿", enhance: "增强" }, options: { enhance: "图片增强模式", model: "设定生成模型", resolution: "设定图片尺寸", override: "禁用默认标签", sampler: "设置采样器", seed: "设置随机种子", steps: "设置迭代步数", scale: "设置对输入的服从度", strength: "图片修改幅度", noise: "图片噪声强度", hiresFix: "启用高分辨率修复", undesired: "排除标签", noTranslator: "禁用自动翻译", iterations: "设置绘制次数", batch: "设置绘制批次大小", smea: "启用 SMEA", smeaDyn: "启用 DYN", scheduler: "设置调度器", decrisper: "启用动态阈值" }, messages: { "exceed-max-iteration": "超过最大绘制次数。", "expect-prompt": "请输入标签。", "expect-image": "请输入图片。", "too-many-images": "过多的图片。", "invalid-content": "输入中含有无效内容。", "latin-only": "只接受英文输入。", "too-many-words": "输入的单词数量过多。", "forbidden-word": "输入含有违禁词。", "concurrent-jobs": "<random>\n <>等会再约稿吧,我已经忙不过来了……</>\n <>是数位板没电了,才…才不是我不想画呢!</>\n <>那你得先教我画画(理直气壮</>\n</random>", waiting: "<random>\n <>少女绘画中……</>\n <>在画了在画了</>\n <>你就在此地不要走动,等我给你画一幅</>\n</random>", pending: "在画了在画了,不过前面还有 {0} 个稿……", "invalid-size": "增强功能仅适用于被生成的图片。普通的 img2img 请直接使用「约稿」而不是「增强」。", "invalid-resolution": "非法的图片尺寸。宽高必须都为 64 的倍数。", "custom-resolution-unsupported": "不支持自定义图片尺寸。", "file-too-large": "文件体积过大。", "unsupported-file-type": "不支持的文件格式。", "download-error": "图片解析失败。", "unknown-error": "发生未知错误。", "response-error": "发生未知错误 ({0})。", "empty-response": "服务器返回了空白图片,请稍后重试。", "request-failed": "请求失败 ({0}),请稍后重试。", "request-timeout": "请求超时。", "invalid-password": "邮箱或密码错误。", "invalid-token": "令牌无效或已过期,请联系管理员。", unauthorized: "令牌未授权,可能需要续费,请联系管理员。" } }, "novelai.upscale": { description: "AI 放大图片", shortcuts: { upscale: "放大" }, options: { scale: "设置放大倍数", resolution: "设定放大尺寸", crop: "是否裁剪以适应尺寸", upscaler: "设置放大模型", upscaler2: "设置放大模型 2", upscaler2visibility: "设置放大模型 2 的可见度", upscaleFirst: "先放大再执行面部修复" }, messages: { "expect-image": "请输入图片。", "download-error": "图片解析失败。", "unknown-error": "发生未知错误。" } } } };
}
});
// src/locales/zh-TW.yml
var require_zh_TW = __commonJS({
"src/locales/zh-TW.yml"(exports2, module2) {
module2.exports = { commands: { novelai: { description: "AI 繪圖", usage: "輸入以逗號分割的英文提示詞,例如 portrait, blonde hair, red eyes。\n查找可用的提示詞標籤可以使用 Danbooru。\n快來給專案標星收藏吧:https://github.com/koishijs/novelai-bot", shortcuts: { imagine: "畫畫|約稿", enhance: "增強" }, options: { enhance: "圖像增強模式", model: "設定生成模型", resolution: "設定圖像尺寸", override: "禁用預設標籤", sampler: "設定採樣器", seed: "設定隨機種子", steps: "設定迭代步數", scale: "設定提示詞的相關性", strength: "圖像修改幅度", noise: "圖像雜訊強度", hiresFix: "啟用高分辨率修復", undesired: "反向提示詞", noTranslator: "禁用自動翻譯", iterations: "設定繪畫次數" }, messages: { "exceed-max-iteration": "超過最大繪畫次數", "expect-prompt": "請輸入提示詞。", "expect-image": "請輸入圖像。", "latin-only": "僅接受英文提示詞。", "too-many-words": "輸入的提示詞數量過多", "forbidden-word": "提示詞中含有違禁詞彙。", "concurrent-jobs": "<random>\n <>等下再畫吧,我已經忙不過來了……</>\n <>我…我纔不是不會畫畫,只是沒時間!</>\n <>我先喝杯咖啡可以嗎,好睏~</>\n</random>", waiting: "<random>\n <>少女繪畫中</>\n <>莫行開,我即時來畫!</>\n</random>", pending: "好酒沉甕底。您還需等我完成前面 {0} 個稿件。", "invalid-size": "增強功能僅適用於 Novel AI 生成圖。若要使用 img2img 功能請直接使用「約稿」而非「增強」。", "invalid-resolution": "圖像尺寸無效。寬度與高度都須爲 64 的倍數。", "custom-resolution-unsupported": "不支援自訂圖像尺寸。", "file-too-large": "文件體積過大。", "unsupported-file-type": "不支援的檔案格式。", "download-error": "圖像解析失敗。", "unknown-error": "發生未知的錯誤。", "response-error": "發生未知的錯誤 ({0})。", "empty-response": "伺服器返回了空圖像,請稍後重試。", "request-failed": "擷取資料失敗 ({0}),請稍後重試。", "request-timeout": "擷取資料超時。", "invalid-password": "電郵地址或密碼不正確。", "invalid-token": "令牌無效或已過期,請聯繫管理員。", unauthorized: "令牌未經授權,可能關聯帳戶需要續費,請聯繫管理員。" } }, "novelai.upscale": { description: "AI 放大圖像", shortcuts: { upscale: "放大" }, options: { scale: "設定放大倍率", resolution: "設定放大尺寸", crop: "是否裁剪以適應尺寸", upscaler: "設定放大模型", upscaler2: "設定放大模型 2", upscaler2visibility: "設定放大模型 2 的可視度", upscaleFirst: "先放大再執行面部修復" }, messages: { "expect-image": "請輸入圖像。", "download-error": "圖像解析失敗。", "unknown-error": "發生未知的錯誤。" } } } };
}
});
// src/locales/en-US.yml
var require_en_US = __commonJS({
"src/locales/en-US.yml"(exports2, module2) {
module2.exports = { commands: { novelai: { description: "Generate Images from Novel AI", usage: 'Enter "novelai" with English prompt or tags, e.g. a girl in the forest, blonde hair, red eyes, white dress, etc.\nYou can also use comma separated tags like those on Danbooru.\nStar it: https://github.com/koishijs/novelai-bot', options: { enhance: "Image Enhance Mode", model: "Set Model for Generation", resolution: "Set Image Resolution", override: "Disable Default Prompts", sampler: "Set Sampler", seed: "Set Random Seed", steps: "Set Iteration Steps", scale: "Set CFG Scale", strength: "Set Denoising Strength", noise: "Set Noising Strength", hiresFix: "Enable Hires Fix.", undesired: "Negative Prompt", noTranslator: "Disable Auto Translation", iterations: "Set Batch Count." }, messages: { "exceed-max-iteration": "Exceeded max batch count.", "expect-prompt": "Expect a prompt.", "expect-image": "Expect an image.", "latin-only": "Invalid prompt, only English words can be used.", "too-many-words": "Too many words in prompt.", "forbidden-word": "Forbidden words in prompt.", "concurrent-jobs": "<random>\n <>Too busy to handle your request...</>\n <>Brb power nap :zzz:</>\n <>(*~*) Have no time to draw a new one.</>\n</random>", waiting: "<random>\n <>The illustrator starts painting.</>\n <>Monet and Da Vinci, whose style is better for this?</>\n</random>", pending: "<plural count={0}>\n <>Sure.</>\n <>Sure, but please wait for me to complete this one before.</>\n <>Bruh, there are {0} jobs pending!</>\n</plural>", "invalid-size": 'The Enhance mode can only be used for images generated. Use "novelai" without enhance option if you are using normal img2img.', "invalid-resolution": "Invalid resolution for image generation. The width and height of image should be multiple of 64.", "custom-resolution-unsupported": "Custom resolution is not supported.", "file-too-large": "File is too large.", "unsupported-file-type": "Unsupported file type.", "download-error": "Parsing image failed.", "unknown-error": "An unknown error occurred.", "response-error": "An unknown error occurred ({0}).", "empty-response": "The server didn't return a valid image.", "request-failed": "Request failed ({0}).", "request-timeout": "Request timeout.", "invalid-password": "Incorrect email address or password.", "invalid-token": "The token is invalid or expired. Please contact your administrator.", unauthorized: "The token is unauthorized, this happens while your account didn't have a valid subscription. Please contact your administrator." } }, "novelai.upscale": { description: "Upscale Images by AI", options: { scale: "Set Upscale By", resolution: "Set Upscale To", crop: "Crop Image Before Upscaling", upscaler: "Set Upscaler", upscaler2: "Set Upscaler", upscaler2visibility: "Set Visibility of Upscaler 2", upscaleFirst: "Upscale Image Before Restoring Face" }, messages: { "expect-image": "Expect an image.", "download-error": "Parsing image failed.", "unknown-error": "An unknown error occurred." } } } };
}
});
// src/locales/fr-FR.yml
var require_fr_FR = __commonJS({
"src/locales/fr-FR.yml"(exports2, module2) {
module2.exports = { commands: { novelai: { description: "Générer des images sur IA", usage: "Entrez « novelai » avec les descriptions textuelles (anglais : prompt) de la scène que vous souhaitez générer.\nDe nombreux modèles exigent que les descriptions textuelles soient en anglais, par ex. a girl in the forest, blonde hair, red eyes, white dress.\nVous pouvez utiliser des balises séparées par des virgules, comme sur Danbooru.\nDonnez-lui une étoile : https://github.com/koishijs/novelai-bot", options: { enhance: "Mode d'amélioration de l'image", model: "Définir le modèle pour la génération", resolution: "Définir la taille de l'image", override: "Remplacer les descriptions textuelles de base", sampler: "Définir l'échantillonneur", seed: "Définir la graine aléatoire", steps: "Définir les étapes de l'itération", scale: "Définir CFG Scale", strength: "Définir l'intensité du débruitage", noise: "Définir l'intensité du bruit", hiresFix: "Activer la correction pour la résolution haute.", undesired: "Définir les descriptions textuelles négatives", noTranslator: "Désactiver la traduction automatique", iterations: "Définir le nombre des générations" }, messages: { "exceed-max-iteration": "Trop du nombre des générations.", "expect-prompt": "Attendrez-vous les descriptions textuelles valides.", "expect-image": "Attendrez-vous une image.", "latin-only": "Les descriptions textuelles ne sont pas valides, vous ne pouvez utiliser que des mots anglais.", "too-many-words": "Trop de mots saisis.", "forbidden-word": "Les descriptions textuelles contiennent des mots prohibés.", "concurrent-jobs": "<random>\n <>Trop occupé pour répondre à votre demande...</>\n <>Courte sieste :zzz:</>\n <>(*~*) Pas le temps d'en dessiner un nouveau.</>\n</random>", waiting: "<random>\n <>D'accord. Je dessine de belles images pour vous.</>\n <>Votre demande est en cours de génération, veuillez attendre un moment.</>\n <>L'illustrateur commence à peindre.</>\n <>Monet et Da Vinci, quel style convient le mieux à cette image ?</>\n</random>", pending: "<plural count={0}>\n <>D'accord.</>\n <>D'accord, mais attendez que je complète la dernière demande.</>\n <>>_< Il y a {0} travaux en cours.</>\n</plural>", "invalid-size": "Le mode d'amélioration de l'image peut être utilisé seulement pour les images générées. Si vous utilisez le mode de img2img, utilisez « novelai » sans l'option « --enhance ».", "invalid-resolution": "La taille de l'image n'est pas valide. La largeur et la hauteur de l'image doivent être des multiples de 64.", "custom-resolution-unsupported": "La personnalisation de la résolution n'est pas prise en charge.", "file-too-large": "Le fichier est trop important.", "unsupported-file-type": "Le format de fichier non reconnu.", "download-error": "Une erreur d'analyse syntaxique de l'image s'est produite.", "unknown-error": "Une erreur inconnue s'est produite.", "response-error": "Une erreur inconnue s'est produite : ({0}).", "empty-response": "Le serveur répond avec l'image invalide.", "request-failed": "La demande a échoué : ({0}).", "request-timeout": "Le délai d'attente de la demande dépassé.", "invalid-password": "L'adresse électronique ou mot de passe introduit est incorrect.", "invalid-token": "Le token est invalide ou a expiré. Veuillez contacter l'administrateur.", unauthorized: "Le token n'est pas autorisé, peut-être que ce token n'a pas d'abonnement valide. Veuillez contacter l'administrateur." } }, "novelai.upscale": { description: "Agrandir des images sur IA", options: { scale: "Mise à l'échelle de", resolution: "Mise à l'échelle à", crop: "Recadrer à la taille avant de l'agrandissement.", upscaler: "Définir l'agrandisseur", upscaler2: "Définir l'agrandisseur 2", upscaler2visibility: "Définir la visibilité de l'agrandisseur 2", upscaleFirst: "Agrandir les images avant de restaurer les visages" }, messages: { "expect-image": "Attendrez-vous une image.", "download-error": "Une erreur d'analyse syntaxique de l'image s'est produite.", "unknown-error": "Une erreur inconnue s'est produite." } } } };
}
});
// src/locales/ja-JP.yml
var require_ja_JP = __commonJS({
"src/locales/ja-JP.yml"(exports2, module2) {
module2.exports = { commands: { novelai: { description: "AI で絵を描く", usage: "コンマで区切られた英語の生成呪文 (プロンプト) を入力してください。例:1girl, red eyes, black hair。\nモデルに用いられる単語は Danbooru のタグとほとんど同じです。\n興味があったら、レポジトリにスターを付けてください:https://github.com/koishijs/novelai-bot", options: { enhance: "向上 (enhance) モードを有効", model: "モデルを指定", resolution: "画像解像度を設定", override: "デフォルトプロンプトを無効にする", sampler: "サンプラーを指定", seed: "シード値を設定", steps: "ステップ数を設定", scale: "CFG スケール値を設定", strength: "ノイズ除去強度を設定", noise: "ノイズ強度を設定", hiresFix: "高解像度修正を有効", undesired: "反対呪文 (ネガティブプロンプト) を設定", noTranslator: "自動翻訳を無効", iterations: "画像生成数を設定" }, messages: { "exceed-max-iteration": "画像生成数が最大に超えました。", "expect-prompt": "生成呪文を入力してください。", "expect-image": "画像を入力してください。", "latin-only": "英数字だけが入力可能です。", "too-many-words": "入力した単語が多すぎる。", "forbidden-word": "一部の入力した単語が禁止されている。", "concurrent-jobs": "<random>\n <>後でね~今、猫の手も借りたいなの!</>\n <>描けるの、た、タブレットが起動できませんだから。</>\n <>じゃ、まず絵を教えて。</>\n</random>", waiting: "<random>\n <>私はプロ絵師だから、どんな絵でも描けるの。</>\n <>仕事している…</>\n</random>", pending: "仕事している前に {0} つの絵が完遂するべきです。", "invalid-size": "向上モードは AI 生成画像のみに用いられる。img2img (指定画像から生成) を使いたければ、「--enhance」を追加せずにコマンドを再実行してください。", "invalid-resolution": "無効な解像度。幅と高さが 64 の倍数である必要があります。", "custom-resolution-unsupported": "カスタム画像解像度は使用できません。", "file-too-large": "ファイルのサイズが大きすぎる。", "unsupported-file-type": "ファイルのタイプがサポートされていません。", "download-error": "画像のダウンロードに失敗しました。", "unknown-error": "不明なエラーが発生しました。", "response-error": "不明なエラーが発生しました ({0})。", "empty-response": "サーバーが無効な画像を返されました、後で試してください。", "request-failed": "リクエストが失敗しました ({0}),後で試してください。", "request-timeout": "リクエストがタイムアウトしました。", "invalid-password": "メールアドレスやパスワードが間違っています。", "invalid-token": "期間切れたまたは無効なトークンです。管理者に連絡してください。", unauthorized: "アカウント契約が期間切れるか、トークンが認可されていません。管理者に連絡してください。" } }, "novelai.upscale": { description: "AI で画像拡大", options: { scale: "拡大倍率を設定", resolution: "拡大目標解像度を設定", crop: "拡大する前に画像をクロップする", upscaler: "拡大モデルを設定", upscaler2: "拡大モデル2を設定", upscaler2visibility: "拡大モデル2の可視度を設定", upscaleFirst: "拡大する前にフェイス修正を行う" }, messages: { "expect-image": "画像を入力してください。", "download-error": "画像のダウンロードに失敗しました。", "unknown-error": "不明なエラーが発生しました。" } } } };
}
});
// src/index.ts
var src_exports = {};
__export(src_exports, {
Config: () => Config,
PromptConfig: () => PromptConfig,
apply: () => apply,
hordeModels: () => hordeModels,
inject: () => inject,
latentUpscalers: () => latentUpscalers,
modelMap: () => modelMap,
models: () => models,
name: () => name,
orientMap: () => orientMap,
orients: () => orients,
parseForbidden: () => parseForbidden,
parseInput: () => parseInput,
reactive: () => reactive,
sampler: () => sampler,
scheduler: () => scheduler,
upscalers: () => upscalers
});
module.exports = __toCommonJS(src_exports);
var import_koishi3 = require("koishi");
// src/config.ts
var import_koishi = require("koishi");
var options = {
userFields: ["authority"]
};
var modelMap = {
safe: "safe-diffusion",
nai: "nai-diffusion",
furry: "nai-diffusion-furry",
"nai-v3": "nai-diffusion-3",
"nai-v4-curated-preview": "nai-diffusion-4-curated-preview",
"nai-v4-full": "nai-diffusion-4-full"
};
var orientMap = {
landscape: { height: 832, width: 1216 },
portrait: { height: 1216, width: 832 },
square: { height: 1024, width: 1024 }
};
var hordeModels = require_horde_models();
var ucPreset = [
// Replace with the prompt words that come with novelai
"nsfw, lowres, {bad}, error, fewer, extra, missing, worst quality",
"jpeg artifacts, bad quality, watermark, unfinished, displeasing",
"chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]"
].join(", ");
var models = Object.keys(modelMap);
var orients = Object.keys(orientMap);
var scheduler;
((scheduler2) => {
scheduler2.nai = ["native", "karras", "exponential", "polyexponential"];
scheduler2.nai4 = ["karras", "exponential", "polyexponential"];
scheduler2.sd = ["Automatic", "Uniform", "Karras", "Exponential", "Polyexponential", "SGM Uniform"];
scheduler2.horde = ["karras"];
scheduler2.comfyUI = ["normal", "karras", "exponential", "sgm_uniform", "simple", "ddim_uniform"];
})(scheduler || (scheduler = {}));
var sampler;
((sampler2) => {
sampler2.nai = {
"k_euler_a": "Euler ancestral",
"k_euler": "Euler",
"k_lms": "LMS",
"ddim": "DDIM",
"plms": "PLMS"
};
sampler2.nai3 = {
"k_euler": "Euler",
"k_euler_a": "Euler ancestral",
"k_dpmpp_2s_ancestral": "DPM++ 2S ancestral",
"k_dpmpp_2m": "DPM++ 2M",
"k_dpmpp_sde": "DPM++ SDE",
"ddim_v3": "DDIM V3"
};
sampler2.nai4 = {
// recommended
"k_euler": "Euler",
"k_euler_a": "Euler ancestral",
"k_dpmpp_2s_ancestral": "DPM++ 2S ancestral",
"k_dpmpp_2m_sde": "DPM++ 2M SDE",
// other
"k_dpmpp_2m": "DPM++ 2M",
"k_dpmpp_sde": "DPM++ SDE"
};
sampler2.sd = require_sd_samplers();
sampler2.horde = {
k_lms: "LMS",
k_heun: "Heun",
k_euler: "Euler",
k_euler_a: "Euler a",
k_dpm_2: "DPM2",
k_dpm_2_a: "DPM2 a",
k_dpm_fast: "DPM fast",
k_dpm_adaptive: "DPM adaptive",
k_dpmpp_2m: "DPM++ 2M",
k_dpmpp_2s_a: "DPM++ 2S a",
k_dpmpp_sde: "DPM++ SDE",
dpmsolver: "DPM solver",
lcm: "LCM",
DDIM: "DDIM"
};
sampler2.comfyui = {
euler: "Euler",
euler_ancestral: "Euler ancestral",
heun: "Heun",
heunpp2: "Heun++ 2",
dpm_2: "DPM 2",
dpm_2_ancestral: "DPM 2 ancestral",
lms: "LMS",
dpm_fast: "DPM fast",
dpm_adaptive: "DPM adaptive",
dpmpp_2s_ancestral: "DPM++ 2S ancestral",
dpmpp_sde: "DPM++ SDE",
dpmpp_sde_gpu: "DPM++ SDE GPU",
dpmpp_2m: "DPM++ 2M",
dpmpp_2m_sde: "DPM++ 2M SDE",
dpmpp_2m_sde_gpu: "DPM++ 2M SDE GPU",
dpmpp_3m_sde: "DPM++ 3M SDE",
dpmpp_3m_sde_gpu: "DPM++ 3M SDE GPU",
ddpm: "DDPM",
lcm: "LCM",
ddim: "DDIM",
uni_pc: "UniPC",
uni_pc_bh2: "UniPC BH2"
};
function createSchema(map) {
return import_koishi.Schema.union(Object.entries(map).map(([key, value]) => {
return import_koishi.Schema.const(key).description(value);
})).loose().description("默认的采样器。").default("k_euler");
}
sampler2.createSchema = createSchema;
__name(createSchema, "createSchema");
function sd2nai(sampler3, model) {
if (sampler3 === "k_euler_a")
return "k_euler_ancestral";
if (model === "nai-v3" && sampler3 in sampler2.nai3)
return sampler3;
else if (sampler3 in sampler2.nai)
return sampler3;
return "k_euler_ancestral";
}
sampler2.sd2nai = sd2nai;
__name(sd2nai, "sd2nai");
})(sampler || (sampler = {}));
var upscalers = [
// built-in upscalers
"None",
"Lanczos",
"Nearest",
// third-party upscalers (might not be available)
"LDSR",
"ESRGAN_4x",
"R-ESRGAN General 4xV3",
"R-ESRGAN General WDN 4xV3",
"R-ESRGAN AnimeVideo",
"R-ESRGAN 4x+",
"R-ESRGAN 4x+ Anime6B",
"R-ESRGAN 2x+",
"ScuNET GAN",
"ScuNET PSNR",
"SwinIR 4x"
];
var latentUpscalers = [
"Latent",
"Latent (antialiased)",
"Latent (bicubic)",
"Latent (bicubic antialiased)",
"Latent (nearest)",
"Latent (nearest-exact)"
];
var PromptConfig = import_koishi.Schema.object({
basePrompt: import_koishi.Schema.computed(import_koishi.Schema.string().role("textarea"), options).description("默认附加的标签。").default("best quality, amazing quality, very aesthetic, absurdres"),
negativePrompt: import_koishi.Schema.computed(import_koishi.Schema.string().role("textarea"), options).description("默认附加的反向标签。").default(ucPreset),
forbidden: import_koishi.Schema.computed(import_koishi.Schema.string().role("textarea"), options).description("违禁词列表。请求中的违禁词将会被自动删除。").default(""),
defaultPromptSw: import_koishi.Schema.boolean().description("是否启用默认标签。").default(false),
defaultPrompt: import_koishi.Schema.string().role("textarea", options).description("默认标签,可以在用户无输入prompt时调用。可选在sd-webui中安装dynamic prompt插件,配合使用以达到随机标签效果。").default(""),
placement: import_koishi.Schema.computed(import_koishi.Schema.union([
import_koishi.Schema.const("before").description("置于最前"),
import_koishi.Schema.const("after").description("置于最后")
]), options).description("默认附加标签的位置。").default("after"),
translator: import_koishi.Schema.boolean().description("是否启用自动翻译。").default(true),
latinOnly: import_koishi.Schema.computed(import_koishi.Schema.boolean(), options).description("是否只接受英文输入。").default(false),
lowerCase: import_koishi.Schema.boolean().description("是否将输入的标签转换为小写。").default(true),
maxWords: import_koishi.Schema.computed(import_koishi.Schema.natural(), options).description("允许的最大单词数量。").default(0)
}).description("输入设置");
var naiFeatures = import_koishi.Schema.object({
anlas: import_koishi.Schema.computed(import_koishi.Schema.boolean(), options).default(true).description("是否允许使用点数。")
});
var sdFeatures = import_koishi.Schema.object({
upscale: import_koishi.Schema.computed(import_koishi.Schema.boolean(), options).default(true).description("是否启用图片放大。")
});
var features = import_koishi.Schema.object({
text: import_koishi.Schema.computed(import_koishi.Schema.boolean(), options).default(true).description("是否启用文本转图片。"),
image: import_koishi.Schema.computed(import_koishi.Schema.boolean(), options).default(true).description("是否启用图片转图片。")
});
var NAI4ParamConfig = import_koishi.Schema.object({
sampler: sampler.createSchema(sampler.nai4).default("k_euler_a"),
scheduler: import_koishi.Schema.union(scheduler.nai4).description("默认的调度器。").default("karras"),
rescale: import_koishi.Schema.computed(import_koishi.Schema.number(), options).min(0).max(1).description("输入服从度调整规模。").default(0)
});
var Config = import_koishi.Schema.intersect([
import_koishi.Schema.object({
type: import_koishi.Schema.union([
import_koishi.Schema.const("token").description("授权令牌"),
...process.env.KOISHI_ENV === "browser" ? [] : [import_koishi.Schema.const("login").description("账号密码")],
import_koishi.Schema.const("naifu").description("naifu"),
import_koishi.Schema.const("sd-webui").description("sd-webui"),
import_koishi.Schema.const("stable-horde").description("Stable Horde"),
import_koishi.Schema.const("comfyui").description("ComfyUI")
]).default("token").description("登录方式。")
}).description("登录设置"),
import_koishi.Schema.union([
import_koishi.Schema.intersect([
import_koishi.Schema.union([
import_koishi.Schema.object({
type: import_koishi.Schema.const("token"),
token: import_koishi.Schema.string().description("授权令牌。").role("secret").required()
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("login"),
email: import_koishi.Schema.string().description("账号邮箱。").required(),
password: import_koishi.Schema.string().description("账号密码。").role("secret").required()
})
]),
import_koishi.Schema.object({
apiEndpoint: import_koishi.Schema.string().description("API 服务器地址。").default("https://api.novelai.net"),
endpoint: import_koishi.Schema.string().description("图片生成服务器地址。").default("https://image.novelai.net"),
headers: import_koishi.Schema.dict(String).role("table").description("要附加的额外请求头。").default({
"referer": "https://novelai.net/",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
})
})
]),
import_koishi.Schema.object({
type: import_koishi.Schema.const("naifu"),
token: import_koishi.Schema.string().description("授权令牌。").role("secret"),
endpoint: import_koishi.Schema.string().description("API 服务器地址。").required(),
headers: import_koishi.Schema.dict(String).role("table").description("要附加的额外请求头。")
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("sd-webui"),
endpoint: import_koishi.Schema.string().description("API 服务器地址。").required(),
headers: import_koishi.Schema.dict(String).role("table").description("要附加的额外请求头。")
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("stable-horde"),
endpoint: import_koishi.Schema.string().description("API 服务器地址。").default("https://stablehorde.net/"),
token: import_koishi.Schema.string().description("授权令牌 (API Key)。").role("secret").default("0000000000"),
nsfw: import_koishi.Schema.union([
import_koishi.Schema.const("disallow").description("禁止"),
import_koishi.Schema.const("censor").description("屏蔽"),
import_koishi.Schema.const("allow").description("允许")
]).description("是否允许 NSFW 内容。").default("allow"),
trustedWorkers: import_koishi.Schema.boolean().description("是否只请求可信任工作节点。").default(false),
pollInterval: import_koishi.Schema.number().role("time").description("轮询进度间隔时长。").default(import_koishi.Time.second)
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("comfyui"),
endpoint: import_koishi.Schema.string().description("API 服务器地址。").required(),
headers: import_koishi.Schema.dict(String).role("table").description("要附加的额外请求头。"),
pollInterval: import_koishi.Schema.number().role("time").description("轮询进度间隔时长。").default(import_koishi.Time.second)
})
]),
import_koishi.Schema.object({
authLv: import_koishi.Schema.computed(import_koishi.Schema.natural(), options).description("使用画图全部功能所需要的权限等级。").default(0),
authLvDefault: import_koishi.Schema.computed(import_koishi.Schema.natural(), options).description("使用默认参数生成所需要的权限等级。").default(0)
}).description("权限设置"),
import_koishi.Schema.object({
features: import_koishi.Schema.object({})
}).description("功能设置"),
import_koishi.Schema.union([
import_koishi.Schema.object({
type: import_koishi.Schema.union(["token", "login"]).hidden(),
features: import_koishi.Schema.intersect([naiFeatures, features])
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("sd-webui"),
features: import_koishi.Schema.intersect([features, sdFeatures])
}),
import_koishi.Schema.object({
features: import_koishi.Schema.intersect([features])
})
]),
import_koishi.Schema.object({}).description("参数设置"),
import_koishi.Schema.union([
import_koishi.Schema.object({
type: import_koishi.Schema.const("sd-webui").required(),
sampler: sampler.createSchema(sampler.sd),
upscaler: import_koishi.Schema.union(upscalers).description("默认的放大算法。").default("Lanczos"),
restoreFaces: import_koishi.Schema.boolean().description("是否启用人脸修复。").default(false),
hiresFix: import_koishi.Schema.boolean().description("是否启用高分辨率修复。").default(false),
hiresFixUpscaler: import_koishi.Schema.union(latentUpscalers.concat(upscalers)).description("高分辨率修复的放大算法。").default("Latent"),
scheduler: import_koishi.Schema.union(scheduler.sd).description("默认的调度器。").default("Automatic")
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("stable-horde").required(),
sampler: sampler.createSchema(sampler.horde),
model: import_koishi.Schema.union(hordeModels).loose().description("默认的生成模型。"),
scheduler: import_koishi.Schema.union(scheduler.horde).description("默认的调度器。").default("karras")
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("naifu").required(),
sampler: sampler.createSchema(sampler.nai)
}),
import_koishi.Schema.object({
type: import_koishi.Schema.const("comfyui").required(),
sampler: sampler.createSchema(sampler.comfyui).description("默认的采样器。").required(),
model: import_koishi.Schema.string().description("默认的生成模型的文件名。").required(),
workflowText2Image: import_koishi.Schema.path({
filters: [{ name: "", extensions: [".json"] }],
allowCreate: true
}).description("API 格式的文本到图像工作流。"),
workflowImage2Image: import_koishi.Schema.path({
filters: [{ name: "", extensions: [".json"] }],
allowCreate: true
}).description("API 格式的图像到图像工作流。"),
scheduler: import_koishi.Schema.union(scheduler.comfyUI).description("默认的调度器。").default("normal")
}),
import_koishi.Schema.intersect([
import_koishi.Schema.object({
model: import_koishi.Schema.union(models).loose().description("默认的生成模型。").default("nai-v3")
}),
import_koishi.Schema.union([
import_koishi.Schema.object({
model: import_koishi.Schema.const("nai-v3"),
sampler: sampler.createSchema(sampler.nai3),
smea: import_koishi.Schema.boolean().description("默认启用 SMEA。"),
smeaDyn: import_koishi.Schema.boolean().description("默认启用 SMEA 采样器的 DYN 变体。"),
scheduler: import_koishi.Schema.union(scheduler.nai).description("默认的调度器。").default("native")
}),
import_koishi.Schema.object({
model: import_koishi.Schema.const("nai-v4-curated-preview"),
...NAI4ParamConfig.dict
}),
import_koishi.Schema.object({
model: import_koishi.Schema.const("nai-v4-full"),
...NAI4ParamConfig.dict
}),
import_koishi.Schema.object({ sampler: sampler.createSchema(sampler.nai) })
]),
import_koishi.Schema.object({ decrisper: import_koishi.Schema.boolean().description("默认启用 decrisper") })
])
]),
import_koishi.Schema.object({
scale: import_koishi.Schema.computed(import_koishi.Schema.number(), options).description("默认对输入的服从度。").default(5),
textSteps: import_koishi.Schema.computed(import_koishi.Schema.natural(), options).description("文本生图时默认的迭代步数。").default(28),
imageSteps: import_koishi.Schema.computed(import_koishi.Schema.natural(), options).description("以图生图时默认的迭代步数。").default(50),
maxSteps: import_koishi.Schema.computed(import_koishi.Schema.natural(), options).description("允许的最大迭代步数。").default(64),
strength: import_koishi.Schema.computed(import_koishi.Schema.number(), options).min(0).max(1).description("默认的重绘强度。").default(0.7),
noise: import_koishi.Schema.computed(import_koishi.Schema.number(), options).min(0).max(1).description("默认的重绘添加噪声强度。").default(0.2),
resolution: import_koishi.Schema.computed(import_koishi.Schema.union([
import_koishi.Schema.const("portrait").description("肖像 (832x2326)"),
import_koishi.Schema.const("landscape").description("风景 (1216x832)"),
import_koishi.Schema.const("square").description("方形 (1024x1024)"),
import_koishi.Schema.object({
width: import_koishi.Schema.natural().description("图片宽度。").default(1024),
height: import_koishi.Schema.natural().description("图片高度。").default(1024)
}).description("自定义")
]), options).description("默认生成的图片尺寸。").default("portrait"),
maxResolution: import_koishi.Schema.computed(import_koishi.Schema.natural(), options).description("允许生成的宽高最大值。").default(1920)
}),
PromptConfig,
import_koishi.Schema.object({
output: import_koishi.Schema.union([
import_koishi.Schema.const("minimal").description("只发送图片"),
import_koishi.Schema.const("default").description("发送图片和关键信息"),
import_koishi.Schema.const("verbose").description("发送全部信息")
]).description("输出方式。").default("default"),
maxIterations: import_koishi.Schema.natural().description("允许的最大绘制次数。").default(1),
maxRetryCount: import_koishi.Schema.natural().description("连接失败时最大的重试次数。").default(3),
requestTimeout: import_koishi.Schema.number().role("time").description("当请求超过这个时间时会中止并提示超时。").default(import_koishi.Time.minute),
recallTimeout: import_koishi.Schema.number().role("time").description("图片发送后自动撤回的时间 (设置为 0 以禁用此功能)。").default(0),
maxConcurrency: import_koishi.Schema.number().description("单个频道下的最大并发数量 (设置为 0 以禁用此功能)。").default(0)
}).description("高级设置")
]);
function parseForbidden(input) {
return input.trim().toLowerCase().replace(/,/g, ",").replace(/!/g, "!").split(/(?:,\s*|\s*\n\s*)/g).filter(Boolean).map((pattern) => {
const strict = pattern.endsWith("!");
if (strict)
pattern = pattern.slice(0, -1);
pattern = pattern.replace(/[^a-z0-9\u00ff-\uffff:]+/g, " ").trim();
return { pattern, strict };
});
}
__name(parseForbidden, "parseForbidden");
var backslash = /@@__BACKSLASH__@@/g;
function parseInput(session, input, config, override) {
if (!input) {
return [
null,
[session.resolve(config.basePrompt), session.resolve(config.defaultPrompt)].join(","),
session.resolve(config.negativePrompt)
];
}
input = input.replace(/\\\\/g, backslash.source).replace(/,/g, ",").replace(/(/g, "(").replace(/)/g, ")").replace(/《/g, "<").replace(/》/g, ">");
if (config.type === "sd-webui") {
input = input.split("\\{").map((s) => s.replace(/\{/g, "(")).join("\\{").split("\\}").map((s) => s.replace(/\}/g, ")")).join("\\}");
} else {
input = input.split("\\(").map((s) => s.replace(/\(/g, "{")).join("\\(").split("\\)").map((s) => s.replace(/\)/g, "}")).join("\\)");
}
input = input.replace(backslash, "\\").replace(/_/g, " ");
if (session.resolve(config.latinOnly) && /[^\s\w"'“”‘’.,:|\\()\[\]{}<>-]/.test(input)) {
return [".latin-only"];
}
const negative = [];
const placement = session.resolve(config.placement);
const appendToList = /* @__PURE__ */ __name((words, input2 = "") => {
const tags = input2.split(/,\s*/g);
if (placement === "before")
tags.reverse();
for (let tag of tags) {
tag = tag.trim();
if (config.lowerCase)
tag = tag.toLowerCase();
if (!tag || words.includes(tag))
continue;
if (placement === "before") {
words.unshift(tag);
} else {
words.push(tag);
}
}
}, "appendToList");
const capture = input.match(/(,\s*|\s+)(-u\s+|--undesired\s+|negative prompts?:\s*)([\s\S]+)/m);
if (capture?.[3]) {
input = input.slice(0, capture.index).trim();
appendToList(negative, capture[3]);
}
const forbidden = parseForbidden(session.resolve(config.forbidden));
const positive = input.split(/,\s*/g).filter((word) => {
word = word.toLowerCase().replace(/[\x00-\x7f]/g, (s) => s.replace(/[^0-9a-zA-Z]/, " ")).replace(/\s+/, " ").trim();
if (!word)
return false;
for (const { pattern, strict } of forbidden) {
if (strict && word.split(/\W+/g).includes(pattern)) {
return false;
} else if (!strict && word.includes(pattern)) {
return false;
}
}
return true;
}).map((word) => {
if (/^<.+>$/.test(word))
return word.replace(/ /g, "_");
return word.toLowerCase();
});
if (Math.max(getWordCount(positive), getWordCount(negative)) > (session.resolve(config.maxWords) || Infinity)) {
return [".too-many-words"];
}
if (!override) {
appendToList(positive, session.resolve(config.basePrompt));
appendToList(negative, session.resolve(config.negativePrompt));
if (config.defaultPromptSw)
appendToList(positive, session.resolve(config.defaultPrompt));
}
return [null, positive.join(", "), negative.join(", ")];
}
__name(parseInput, "parseInput");
function getWordCount(words) {
return words.join(" ").replace(/[^a-z0-9]+/g, " ").trim().split(" ").length;
}
__name(getWordCount, "getWordCount");
// src/utils.ts
var import_koishi2 = require("koishi");
var import_libsodium_wrappers_sumo = require("libsodium-wrappers-sumo");
var import_image_size = __toESM(require("image-size"));
function project(object, mapping) {
const result = {};
for (const key in mapping) {
result[key] = object[mapping[key]];
}
return result;
}
__name(project, "project");
function getImageSize(buffer) {
if (typeof Buffer !== "undefined") {
return (0, import_image_size.default)(new Uint8Array(buffer));
}
const blob = new Blob([buffer]);
const image = new Image();
image.src = URL.createObjectURL(blob);
return (0, import_koishi2.pick)(image, ["width", "height"]);
}
__name(getImageSize, "getImageSize");
var MAX_OUTPUT_SIZE = 1048576;
var MAX_CONTENT_SIZE = 10485760;
var ALLOWED_TYPES = ["image/jpeg", "image/png"];
async function download(ctx, url, headers = {}) {
if (url.startsWith("data:") || url.startsWith("file:")) {
const { mime, data } = await ctx.http.file(url);
if (!ALLOWED_TYPES.includes(mime)) {
throw new NetworkError(".unsupported-file-type");
}
const base64 = (0, import_koishi2.arrayBufferToBase64)(data);
return { buffer: data, base64, dataUrl: `data:${mime};base64,${base64}` };
} else {
const image = await ctx.http(url, { responseType: "arraybuffer", headers });
if (+image.headers.get("content-length") > MAX_CONTENT_SIZE) {
throw new NetworkError(".file-too-large");
}
const mimetype = image.headers.get("content-type");
if (!ALLOWED_TYPES.includes(mimetype)) {
throw new NetworkError(".unsupported-file-type");
}
const buffer = image.data;
const base64 = (0, import_koishi2.arrayBufferToBase64)(buffer);
return { buffer, base64, dataUrl: `data:${mimetype};base64,${base64}` };
}
}
__name(download, "download");
async function calcAccessKey(email, password) {
await import_libsodium_wrappers_sumo.ready;
return (0, import_libsodium_wrappers_sumo.crypto_pwhash)(
64,
new Uint8Array(Buffer.from(password)),
(0, import_libsodium_wrappers_sumo.crypto_generichash)(
import_libsodium_wrappers_sumo.crypto_pwhash_SALTBYTES,
password.slice(0, 6) + email + "novelai_data_access_key"
),
2,
2e6,
import_libsodium_wrappers_sumo.crypto_pwhash_ALG_ARGON2ID13,
"base64"
).slice(0, 64);
}
__name(calcAccessKey, "calcAccessKey");
var NetworkError = class _NetworkError extends Error {
constructor(message, params = {}) {
super(message);
this.params = params;
}
static {
__name(this, "NetworkError");
}
static catch = (mapping) => (e) => {
if (import_koishi2.Quester.Error.is(e)) {
const code = e.response?.status;
for (const key in mapping) {
if (code === +key) {
throw new _NetworkError(mapping[key]);
}
}
}
throw e;
};
};
async function login(ctx) {
if (ctx.config.type === "token") {
await ctx.http.get(ctx.config.apiEndpoint + "/user/subscription", {
timeout: 3e4,
headers: { authorization: "Bearer " + ctx.config.token }
}).catch(NetworkError.catch({ 401: ".invalid-token" }));
return ctx.config.token;
} else if (ctx.config.type === "login" && process.env.KOISHI_ENV !== "browser") {
return ctx.http.post(ctx.config.apiEndpoint + "/user/login", {
timeout: 3e4,
key: await calcAccessKey(ctx.config.email, ctx.config.password)
}).catch(NetworkError.catch({ 401: ".invalid-password" })).then((res) => res.accessToken);
} else {
return ctx.config.token;
}
}
__name(login, "login");
function closestMultiple(num, mult = 64) {
const floor = Math.floor(num / mult) * mult;
const ceil = Math.ceil(num / mult) * mult;
const closest = num - floor < ceil - num ? floor : ceil;
if (Number.isNaN(closest))
return 0;
return closest <= 0 ? mult : closest;
}
__name(closestMultiple, "closestMultiple");
function resizeInput(size) {
const { width, height } = size;
if (width % 64 === 0 && height % 64 === 0 && width * height <= MAX_OUTPUT_SIZE) {
return { width, height };
}
const aspectRatio = width / height;
if (aspectRatio > 1) {
const height2 = 512;
const width2 = closestMultiple(height2 * aspectRatio);
if (width2 * height2 <= MAX_OUTPUT_SIZE) {
return { width: width2, height: height2 };
}
} else {
const width2 = 512;
const height2 = closestMultiple(width2 / aspectRatio);
if (width2 * height2 <= MAX_OUTPUT_SIZE) {
return { width: width2, height: height2 };
}
}
if (aspectRatio > 1) {
const width2 = 1024;
const height2 = closestMultiple(width2 / aspectRatio);
return { width: width2, height: height2 };
} else {
const height2 = 1024;
const width2 = closestMultiple(height2 * aspectRatio);
return { width: width2, height: height2 };
}
}
__name(resizeInput, "resizeInput");
function forceDataPrefix(url, mime = "image/png") {
if (url.startsWith("data:"))
return url;
return `data:${mime};base64,` + url;
}
__name(forceDataPrefix, "forceDataPrefix");
// src/index.ts
var import_adm_zip = __toESM(require("adm-zip"));
var import_path = require("path");
var import_promises = require("fs/promises");
var reactive = true;
var name = "novelai";
function handleError({ logger }, session, err) {
if (import_koishi3.Quester.Error.is(err)) {
if (err.response?.status === 402) {
return session.text(".unauthorized");
} else if (err.response?.status) {
return session.text(".response-error", [err.response.status]);
} else if (err.code === "ETIMEDOUT") {
return session.text(".request-timeout");
} else if (err.code) {
return session.text(".request-failed", [err.code]);
}
}
logger.error(err);
return session.text(".unknown-error");
}
__name(handleError, "handleError");
var inject = {
required: ["http"],
optional: ["translator"]
};
function apply(ctx, config) {
ctx.i18n.define("zh-CN", require_zh_CN());
ctx.i18n.define("zh-TW", require_zh_TW());
ctx.i18n.define("en-US", require_en_US());
ctx.i18n.define("fr-FR", require_fr_FR());
ctx.i18n.define("ja-JP", require_ja_JP());
const tasks = /* @__PURE__ */ Object.create(null);
const globalTasks = /* @__PURE__ */ new Set();
let tokenTask = null;
const getToken = /* @__PURE__ */ __name(() => tokenTask ||= login(ctx), "getToken");
ctx.accept(["token", "type", "email", "password"], () => tokenTask = null);
const useFilter = /* @__PURE__ */ __name((filter) => (session) => {
return session.resolve(filter) ?? true;
}, "useFilter");
const useBackend = /* @__PURE__ */ __name((...types) => () => {
return types.includes(config.type);
}, "useBackend");
const thirdParty = /* @__PURE__ */ __name(() => !["login", "token"].includes(config.type), "thirdParty");
const restricted = /* @__PURE__ */ __name((session) => {
return !thirdParty() && useFilter(config.features.anlas)(session);
}, "restricted");
const noImage = /* @__PURE__ */ __name((session) => {
return !useFilter(config.features.image)(session);
}, "noImage");
const some = /* @__PURE__ */ __name((...args) => (session) => {
return args.some((callback) => callback(session));
}, "some");
const step = /* @__PURE__ */ __name((source, session) => {
const value = +source;
if (value * 0 === 0 && Math.floor(value) === value && value > 0 && value <= session.resolve(config.maxSteps || Infinity))
return value;
throw new Error();
}, "step");
const resolution = /* @__PURE__ */ __name((source, session) => {
if (source in orientMap)
return orientMap[source];
const cap = source.match(/^(\d+)[x×](\d+)$/);
if (!cap)
throw new Error();
const width = closestMultiple(+cap[1]);
const height = closestMultiple(+cap[2]);
if (Math.max(width, height) > session.resolve(config.maxResolution || Infinity)) {
throw new import_koishi3.SessionError("commands.novelai.messages.invalid-resolution");
}
return { width, height, custom: true };
}, "resolution");
const cmd = ctx.command("novelai <prompts:text>").alias("nai").alias("imagine").userFields(["authority"]).shortcut("imagine", { i18n: true, fuzzy: true }).shortcut("enhance", { i18n: true, fuzzy: true, options: { enhance: true } }).option("enhance",