@civitai/ 生成元数据
读写 AI 生成元数据 嵌入于图像中: 即时、 采样器、 种子, 以及自动1111、ComfyUI、SwarmUI、RuinedFooocus和civitai.com 输入的资源 PNG / JPEG / WebP 文件. 不是另一个通用的exif解析器:它理解生成器格式, 能够活下来 并且能够用真实的图像来验证 无本地附属地; 浏览器和节点.
安装
pnpm add @civitai/generation-metadata
快速启动( 不需要插件)
import { readMetadata, normalizeGeneration, copyMetadata } from '@civitai/generation-metadata';
// node with a file path? import { readMetadataFromFile } from '@civitai/generation-metadata/node'
const md = await readMetadata(fileOrBytesOrUrl);
console.log(md.generator); // 'automatic1111' | 'comfyui' | 'swarmui' | 'ruinedfooocus' | null
console.log(md.raw.prompt, md.raw.steps, md.raw.sampler); // the verbatim parsed bag
// Prefer the normalized view for typed access — `raw` is a loose bag whose
// index signature makes a typo'd key compile as `unknown`, not an error.
// normalizeGeneration is a pure function over md.raw, supported for everyone,
// no plugin required; the only field a non-civitai consumer won't get is the
// resources' modelVersionId (a civitai identifier, added by the civitai plugin).
const gen = normalizeGeneration(md.raw, md.generator);
// Resizing/converting strips metadata; copyMetadata restores it:
const restored = await copyMetadata(originalFile, resizedBytes);
在浏览器中尝试: https://civitai.github.io/media-metadata/ (中文(简体) ) —— 将任意图像降入 查看确切的剖面, 与/没有 civitai 插件进行比较, 测试调整回程大小,以及 报告分析错误的图像.
解析器是从 civitai.com (英语) 应用和现在 被一系列真实的图像锁住 每次测试都进行剖析和往返.
阅读
读者是 默认的赤骨 并被插件所扩展。 软件包捆绑一个插件:
civitai(),增加了civitai.com所写的一切. 需要从 Civitai 读取图像
这个 ——没有插件,civitai特定块会降解(见下文插件).
import { readMetadata } from '@civitai/generation-metadata';
import { civitai } from '@civitai/generation-metadata/civitai';
const md = await readMetadata(fileOrBytesOrUrl, { plugins: [civitai()] });
// md.raw -> THE CORE OUTPUT: the verbatim per-generator bag, every
// passthrough key intact (also the civitai app's storage shape)
// md.civitai -> the plugin's namespace: { madeOnSite, extra, generation }.
// `generation` is the plugin's NORMALIZED view of raw (camelCase,
// guaranteed number types, one merged `resources` list with
// modelVersionId on civitai-identified entries)
// md.generator -> 'automatic1111' | 'comfyui' | 'swarmui' | 'ruinedfooocus' | null
// md.format -> 'png' | 'jpeg' | 'webp' | 'unknown'
// md.exif -> raw flattened tags
核心停止在 md.raw ——忠实地,有计划地验证出发电机所写的.
这是什么 encodeMetadata 消费. 规范化是一个插件关切: civitai 插件
一种观点 正常观点 md.civitai.generation,其他插件可自由使用
正常化的方式不同,或根本不相同。 插件从不写入共享袋的顶级; 每个
获得自己的命名空间( e)md.civitai) (中文(简体) ).
输入可以是 Uint8Array, (中文(简体) ), ArrayBuffer, (中文(简体) ), Blob编号 :File,或 URL 字符串(比较)。 只节点
方便之所居处 @civitai/generation-metadata/node (单位:千美元)readMetadataFromFile) (中文(简体) ).
形状 md.raw
这些字段都是由四台发电机组成的计划,并始终如一地打入 被胁迫,即使消息来源写出字符串:
| 外地 | 类型 | 页:1 |
|---|---|---|
prompt, (中文(简体) ), negativePrompt, (中文(简体) ), sampler | string? | 空字符串变为缺失 |
steps, (中文(简体) ), cfgScale, (中文(简体) ), seed, (中文(简体) ), clipSkip | number? | 被胁迫 |
hashes | Record<string, string>? | model 编号 : vae 编号 : lora:NAME 编号 : embed:NAME 密钥 |
resources, (中文(简体) ), additionalResources | 数组 | {type, name?, weight?, hash?} 形状 |
civitaiResources | 数组 | 仅使用 civitai 插件 : {modelVersionId, type?, weight?} |
comfy | 字符串或对象 | comfyUI 图表 (prompt + 键 workflow 贾森) |
version, (中文(简体) ), engine, (中文(简体) ), extra | 错误c | 生成器/工具细节 |
其它的都是个 保存的通过密钥 —— 说 'Model hash', (中文(简体) ), width, (中文(简体) ),
'Denoising strength', (中文(简体) ), 'AddNet Module 1'康菲尤尔 models编号 :vaes 数组 - 已键入 unknown
和不同的每个发电机。 每个生成器的参考物是
已执行的命案: fixtures/images/<generator>/ 有一个 *.expected.json 旁边
显示其完整 md.raw。 。 。 .
三个不同的东西被命名 workflow数字 : raw.workflow 是一个 字符串 (civitai的工作流程)
名称,例如:. txt2img); ComfyUI工作流程 JSON 生活在 raw.comfy; 和 : MetadataPayload.workflow
是巴布亚新几内亚 workflow 写方块文字.
解析粘贴文本
parseGenerationText 剖析 A1111 风格的参数字符串( “ 复制生成数据” 格式)
输入同一个信封 readMetadata 返回——插件完全应用,所以粘贴了文本并读取
文件输入相同的下游代码 :
import { parseGenerationText } from '@civitai/generation-metadata';
import { civitai } from '@civitai/generation-metadata/civitai';
const md = parseGenerationText(pastedParameters, { plugins: [civitai()] });
// md.raw, md.civitai.generation — same as a file read; md.format is 'unknown'
注意: 任何被标签的描述 generator: 'automatic1111' (没有可靠的办法)
因此不要显示粘贴路径的 tool 作为
权威.
支持的格式
| 发电机 | 集装箱 | 元数据所在的地方 |
|---|---|---|
| 自动1111(并兼容:Forge,现场civitai) | 巴布亚新几内亚, JPEG | parameters 文本块/ EXIF 用户Comment |
| 康菲乌伊 | 巴布亚新几内亚、WebP、JPEG(遗产) | prompt + 键 workflow 块 / EXIF 模型标签 / 用户Comment JSON |
| 沼泽地 | 巴布亚新几内亚 | sui_image_params JSON进来了 parameters |
| 破坏焦点 | 巴布亚新几内亚 | JSON进来了 parameters 带有 software 标记 |
检测命令事项(格式重叠),从原应用执行中保留.
写入
写方存在如此 图像的再大小或转换不会悄悄地破坏其生成 数据 ——包括PNG上的ComfyUI工作流程,预包装应用代码丢失.
import {
copyMetadata,
embedMetadata,
payloadFromMediaMetadata,
} from '@civitai/generation-metadata';
// The resize-safe primitive: re-embed source metadata into resized/converted bytes
const restored = await copyMetadata(originalFile, resizedBytes);
// Or lower-level:
const payload = payloadFromMediaMetadata(await readMetadata(originalFile));
const withMeta = await embedMetadata(pngOrJpegBytes, payload);
- 巴布亚新几内亚: 写
parameters编号 :prompt编号 :workflow作为tEXt块数( e)iTXt文本时 取代同键字块 艺术家/软件旅行eXIf块 (Civitai的同一机制生成器用于其PNG输出,其中所有元数据—— 用户Comment包含——生活于EXIF-in-PNG),所以现场标记活了格式转换. - JPEG 组合: 构建并组合一个 APP1 EXIF 段( 艺术家、 软件、 用户Comment), 替换一个 已有 Exif 段。 Raw source 用户Comment 字节被逐字节带入, 所以 JPEG JPEG 副本是无字节的.
- 网络P: v1 中只读.
影印本还能留下什么
copyMetadata 工作关闭 源代码的原始标签 (单位:千美元)md.exif — 原始块文本 /
用户Comment 字节, 从未解析或规范数据 。 这使得它独立插件( 无)
plugins 选项,不需要),豁免解析错误,并且能够保存它不能保存的元数据
甚至是剖析.
| 资料来源 目标 | 结果 |
|---|---|
| JPEG —— JPEG —— JPEG | 无字节 (用户Comment 字节带有逐字记录) |
| 巴布亚新几内亚-巴布亚新几内亚 | 文字块逐字重嵌; eXIf 从艺人/软件重建 |
| JPEG 巴布亚新几内亚 | 用户Comment 解码为 a parameters 块; 艺人/软件输入 eXIf |
| PNG —— JPEG —— 巴布亚新几内亚 | parameters 文本重新编码为 UTF-16 用户Comment |
| ComfyUI ~ JPEG (英语) | 最佳遗存用户Comment 格式 — 图表存续, meta.comfy 不同 |
| – 微博P | 掷出 (单位:千美元)Metadata writing is not supported) 门有: canEmbedMetadata(sniffFormat(bytes)) |
剖析结果在每一个支持的转换的两侧都是一样的——固定套件
声称每个图像,包括前后链jpeg → png → jpeg) (中文(简体) ).
插件
核心解析出四种生成器格式的"香草"风格,并且对具体站点一无所知. A 类
ParserPlugin 有三个接合点:
parsers转换登记册(包装、替换、扩展、重新排序解析器)context- 合并ParserContext贡献(详细行提取器、样本地图、, 排除密钥, 调试钩钩)enrich——解析后注释结果信封. 同步 做同声工作 (hash lookups, API calls) 读取之外, 或将其预先解入插件的关闭方式civitai({ resolveAir })已经.
插件实例必须跨已读重用( 同一实例可能看到许多文件); 保存 插件对象的每个读取状态。 每个插件只写自己的信封命名空间,以及 通过声明合并方式输入访问权限 :
declare module '@civitai/generation-metadata' {
interface PluginNamespaces {
myPlugin: { jobId?: string };
}
}
// enrich: (md) => { md.myPlugin = { jobId: ... } } — typed, no casts
捆绑起来 civitai() 插件
import { readCivitaiMetadata } from '@civitai/generation-metadata/civitai';
const md = await readCivitaiMetadata(input); // civitai() baked in; md.civitai guaranteed present
readCivitaiMetadata 当您想要civitai语义时, 是推荐的切入点
忘记插件不可能,返回类型会丢弃 ? 打开 md.civitai明确
表单 readMetadata(input, { plugins: [civitai()] }) 等同的.
对于已经作为包(例如以前存储在数据库中)而不是文件的元数据,
normalizeCivitaiGeneration(raw, generator?) 生产出什么 md.civitai.generation 将
包含——包括: modelVersionId 资源折叠——在可见的情况下没有文件或Exif。 这个
generator 是可选的 : 省略它对于从未记录过一行的存储行, 而结果只是
没有 tool (缺席于猜想). normalizeGeneration 它的生成者不可知论基础
(除了civitai资源折叠,以及从包根再出口),和
对于任何消费者,无论是否属于Civitai,都支持公共API.
它补充说: Civitai resources: 编号 : Civitai metadata: 细节行块(带有 AIR + version-id)
决议,通过 civitai({ resolveAir })页:1 CivitaiModelSelector ComfyUI节点,
civitai的现场生成格式( 遗留用户Comment JSON, 主管) extraMetadata
工作流程-AIR + civitaiResources 决 定 engine: 'Civitai',则
madeOnSite 标记.
Civitai的管弦乐手写出标准的A1111文本,并附有它的块,所以 没有
插件标准字段( 即时、 采样器、 步骤、 大小、...) 仍可完整解析 - 核心电梯
任何未识别 Key: {...}编号 :Key: [...] JSON 作为生线挡出细节线
传递( e)raw['Civitai resources'] 而不是让它操纵扫描仪。 这个
插件是怎样的 解释 这些区块(civitaiResources 已解决的版本代号, extra, (中文(简体) ),
madeOnSite),以及如何处理现场ComfyUI格式.
写你自己
见 examples/06-third-party-usage.ts 用于完整的自定义插件(一个细节-行提取器+)
一个丰富的钩子. parseGenerationText 财务报告和审定财务报表 encodeMetadata 接受相同的建议
{ plugins, context } 选项.
可注射公约ParserContext(中文(简体) )
标本正常化(samplerMap(中文(简体) )
samplerMap 是一个单独的共享表格形状 A1111 display name → [native aliases]
(单位:千美元)'Euler a' → ['euler_ancestral']) (中文(简体) ). 它只用于一个方向: ComfyUI, SwarmUI,和
破损的Fooocus 解析器查看他们的本地采样器名称 以别名表示值 并重写到
A1111 名称(带有 _karras 当调度器为 karras 时重试 。 A1111 解析器从未使用过..
它的文本已经包含 A1111 词汇 。 一个表起作用了 因为那些UII 都发出相同的
comfy- system case family; SwarmUI 额外保留本地名 originalSampler。 。 。 .
- 添加一个新的生态系统名称 在同一条目中附加别名——不需要第二个地图:
map.set('DPM++ 2M', [...map.get('DPM++ 2M'), 'my_ui_dpm_2m'])。 。 。 . - 禁用常态 (保留原生土名)通过
samplerMap: new Map()。 。 。 . - 您注册的自定义解析器可以忽略
ctx.samplerMap并关闭在自己的桌子上.
A1111 编码政策 (a1111ExcludedKeys(中文(简体) )
a1111ExcludedKeys 是内部/交叉分隔器中统一元数据密钥的否定列表
字段,而不是 A1111 文本字段(在细节行通过和编码上跳过)。 这是一个
拒绝列表而不是允许列表, 因为 A1111 格式是开放式的 —— 扩展添加
任意 Key: value 双胞胎, 和许可名单会默默地放下他们。 默认
(单位:千美元)defaultA1111ExcludedKeys)覆盖此包的内部密钥;如果您添加您的密钥,则扩展其:
import { defaultA1111ExcludedKeys, encodeMetadata } from '@civitai/generation-metadata';
encodeMetadata(meta, 'automatic1111', {
a1111ExcludedKeys: [...defaultA1111ExcludedKeys, 'myInternalKey'],
});
实例和操场
examples/ 包含 civitai 使用此软件包的可运行脚本 –上传
预处理、 调整大小保留- 元数据、 复制生成数据、 粘贴参数、 源元数据
提取——加上带有自定义的第三方使用示例 ParserContext。每个文件头
确切的 civitai 呼叫网站 它的镜子; docs/civitai-migration.md 将每个呼叫站点映射到
它的替换 API.
pnpm examples # run them all against the fixture corpus
pnpm playground # drag-and-drop parser inspector at http://localhost:5199
# (hosted: https://civitai.github.io/media-metadata/)
游乐场是一个 dev 唯一的 Vite 页面: 放下任意图像( 或粘贴一个 civitai CDN URL) 并查看
检测到生成器,解析出元数据,重新编码出A1111文本,可嵌入有效载荷,并有生标签.
插件复选框控制用于下一个读取的插件,“compare vs 赤核”则添加一个
键级 diff 显示每个插件的准确贡献。 模式可链接 :
http://localhost:5199/?plugins=none 以赤核模式打开(无插件读取/写入测试),
?plugins=civitai&compare=1 以插件加 diff 视图来打开;拖动复选框保留
同步的 URL 。 A 类 报告分析问题 按钮
为分析错误的图像打开预填的 GitHub 问题——见下文.
描述错误的图像
坏剖面通过两步管道成为试验装置:
- 有谁通过 fixture-报告模板 (或操场的每张卡) 报告按钮/ 多选择“ 报告 N 选中的” 按钮并拖动 原文 图像 file(s) into it——每期数个是好的;每个附件成为自己的固定.
- 维护者添加
fixture-report标签; 标签fixture-report.yml工作流程下载 附加,吸收到fixtures/祝福人们的期待 当前 解析器 输出,并打开 PR 。 审查者将预期与报告进行比较——如果 parser需要修复,固定在树枝上,在合并前有一个回放.
标签门指未经信任的上传在不维护者动作的情况下从不进入回放.
每张牌都有一张 变形+复制Metadata 将图像大小调整/转换到
a 画布(它剥去所有元数据,与应用程序的调整路径相同),用
copyMetadata,重新读取结果,并标出它"元数据保存完好"或"为这个损失"
目标"带有密钥级别diff——外加已转换文件的下载按钮.
定型测试( T)
fixtures/images/<generator>/ 持有来自civitai.com的真实图像 – 每个生成器数个
带着祝福 <name>.expected.json测试套房自动发现每个图像并声称:
- 解析:输出等于祝福的期望.
- 往返旅行: 锐度调整/转换图像(它会剥去元数据),
copyMetadata从 原始的,重读的,元数据深度等于期望的,对于其中列出的每一种格式 修补器roundTrip.formats。 。 。 .
工作流量 :
pnpm test # run everything
pnpm bless [filter] # regenerate expected.json from current output (review the diff!)
pnpm fetch-fixtures --verify-only # check committed fixtures against manifest sha256s
fixtures/manifest.json 记录每个图像的源地址和sha256。 新固定装置: 放下
右侧目录中的图像( 或使用) scripts/ingest.ts),运行 pnpm bless,审查,承诺。 中情局
从来就没有祝福过——改变的期望总是经过审查的、审慎的决定.
添加解析器
执行 MetadataParser<TState> (单位:千美元)src/image/parsers/types.ts: detect 检查平地
标记 不改变它们 返回您的常态或状态 null· ; parse 转动状态
输入元数据; encode 将本地文本格式化。 登记在册
src/image/parsers/registry.ts (顺序事项),增加3到5个真正的固定图像,并祝福.
与 Civitai 应用软件的蓄意差异
- 应用程序
getMetadata()剥去meta.extra有效载荷降至3个特定应用密钥作为 其zod schema 的副作用; 此套件保持完整的extra记录。 (应用可再行 detect失败跳到下一个解析器, 而不是中止整个读取 .- 添加网重读自
AddNet Weight A ${i}(扩展所写)和非无限 重量省略。 从历史上看,NaN 重量失败了计划验证并抛弃了整个 元数据对象——每个 AddNet 时代图像解析到{}. (在应用软件中平行排列;见 文件/公司调查,md项目1。 ) - A1111 联合国
quote()编号 :unquote()语义学( 每上游)infotext_utils.py:编码器 JSON-引文 含有逗号/新行/冒号/引号的值, 以及引用的 parser unquotes 回引到 a plain string(应用程序将其变成垃圾嵌入对象). 引出数值起自key:(单位:千美元)Lora hashes, (中文(简体) ),ControlNet 0)仍然被解析为嵌入式块,匹配应用输出. - 破损的Fooocus探测器具有白空间耐受性(
"software":"RuinedFooocus"有无 空间);应用程序需要python-json间隔. - SwarmUI的版本从光谱校正读取
swarm_version键(也在应用程序中被固定). parseGenerationText计数器在剖面上验证,所以数字字段作为数字返回 应用是旧的parsePromptMetadata返回原始字符串——代码比较meta.steps === '30'安静地休息.
发展
pnpm install
pnpm test # vitest, includes the fixture corpus
pnpm typecheck
pnpm lint
pnpm build # tsup -> dist (ESM + CJS + d.ts)
节点 24 (.nvmrc),第10页.