Civitai Creator Studio `/licensing` 批量授权费用编辑器:设计文档解读与源码级实现剖析

发布时间:2026/9/17 19:23:04
Civitai Creator Studio `/licensing` 批量授权费用编辑器:设计文档解读与源码级实现剖析 Civitai Creator Studio/licensing批量授权费用编辑器设计文档解读与源码级实现剖析【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai导读本文以 docs/creator-studio/licensing.md 为骨架系统讲解 Civitai Creator Studio 中批量授权费用licensing fee编辑器的完整设计——从独立页面 vs/models模式的架构分叉、用户故事、布局组件、服务端数据读取、写入动作到成员门控与各类状态处理。结合 creator-studio-plan.md 的实施计划与apps/creator-studio下的真实源码bulk-actions.ts、BulkBar.svelte、BulkActionDialog.svelte、licensing-fee.ts等你可以掌握批量费用编辑的端到端实现路径一次多选、一次确认把费用应用到创作者自己的大量模型版本上。一、页面定位一个批量操作工具而非又一个模型管理页/licensing是 Creator Studiocreator.civitai.com的 SvelteKit spoke 应用中的批量授权费用编辑页。它要解决的问题非常具体创作者拥有大量模型版本逐个进入/models逐行设置费用既繁琐又容易遗漏批量编辑器让创作者在一次操作内完成三件事设置apply费用为选中的所有版本写入同一个授权费用清除clear费用一次性关掉多个版本的费用应用模型类型默认建议apply default by type按每个版本所属的模型类型套用默认费用建议LoRA 约 0.1 buzz/张、base 模型约 1 buzz/张。文档开篇即点明它的定位v12026-07-09 决定批量费用编辑是此工具的核心目的而非快速跟进功能它是 models.md单版本管理的多版本伴生品。两者的关系是相同的行数据模型版本model versions相同的字段每版本费用per-version fee相同的写入setLicensingFee单版本/bulkSetLicensingFee批量。也就是说无论批量编辑最终渲染在哪个路由下它都不是第二套实现——两个界面共享同一个行组件并调用同一个monetization 模块apps/creator-studio/src/lib/server/monetization/中的同一批函数。二、悬而未决的架构分叉独立页面还是/models的一种模式文档明确指出/licensing与/models几乎完全重叠且实施计划§8把它们列为独立页面却显式标记此问题未解决要求在开始构建前先做决策。三个候选方案方案形态优点代价A — 独立/licensing页面按计划表列为单独路由导航入口干净有一个专门的批量金钱操作界面两个页面需保持同步B —/models上的?modebulk同一路由通过 searchParam 把表格切换为多选 批量操作栏模式零分歧创作者原本就在那里易于发现路由内部需处理两种形态C —/models内的 TabManage/Bulk fees一个路由、两个视图状态、独立 Tab单路由两视图状态清晰Tab 状态需妥善管理文档的立场很坚决无论选哪个都不是第二套实现。两个界面共享同一个行组件并调用同一个 monetization 模块的setLicensingFee单个/bulkSetLicensingFee多个。本文后续内容即为无论批量编辑渲染在哪里都要遵守的批量行为规范。三、用户故事与交互流程作为一个拥有大量版本的创作者我打开批量编辑器通过筛选/搜索缩小到我关心的版本集合多选行或全选所有匹配项然后在一个动作里应用费用、清除费用或应用模型类型默认建议。因为这是涉及金钱的操作我会在它应用到每个选中版本之前通过一个确认对话框确认变更。这条用户故事定义了批量编辑器的核心体验约束筛选优先先搜索/筛选再选择再操作多选与全选匹配支持逐行多选也支持选中当前筛选条件下的所有匹配版本金钱操作需确认应用前必须弹窗确认文档注释its money一次操作作用全部一次确认作用于所有选中版本。四、布局与组件基于civitai/ui的 shadcn-svelte 原语文档明确要求不要手搓组件一律使用civitai/uishadcn-svelte原语。核心组件清单如下tabledata-table带前置checkbox列一行一个版本即与 models.md 共享的行组件表头提供全选。列包含版本version· base model ·模型类型model type· 当前费用用badge显示Active/Paused/Off状态。批量操作栏Bulk action bar当 ≥1 行被选中时出现包含input费用金额buttonApply fee、Clear fees、Apply default by type以及实时计数如42 versions selected。dialog确认对话框应用前确认汇总变更内容例如 Set 0.1 buzz/image on 42 versions — 8 already have a fee, overwrite?给 42 个版本设置 0.1 buzz/张——其中 8 个已有费用覆盖。sonnertoast展示操作结果。badge展示每行费用状态。input/搜索与筛选控件绑定到 URL searchParams见下文读取。源码印证BulkBar.svelte与BulkActionDialog.svelte在真实仓库中这两个组件已经实现为 BulkBar.svelte 与 BulkActionDialog.svelte并比文档更进一步地泛化出 5 种批量动作BulkBar.svelte 渲染批量操作栏左侧Checkbox支持全选匹配select all matchingindeterminate状态表示已有选中但未全选计数文案精确区分{count} selected与Select all {matchingCount}当部分选中项已不再匹配当前筛选时会显示黄色提示{offViewCount} no longer match your filters右侧提供Licensing fee、Paid access、Usage control按钮一个 More 下拉菜单承载破坏性操作Clear licensing fee…/Remove paid access…末尾还有Export CSV导出按钮。动作枚举定义在 bulk-actions.ts// The operations the bulk bar can start. Each opens a form — nothing applies straight from the bar. export const BULK_ACTIONS [ fee, paidAccess, usageControl, clearFee, removeAccess, ] as const; export type BulkAction (typeof BULK_ACTIONS)[number]; export const DESTRUCTIVE_ACTIONS: readonly BulkAction[] [clearFee, removeAccess]; export const BULK_ACTION_FORM: RecordBulkAction, string { fee: ?/bulkSetFee, paidAccess: ?/bulkSetPaidAccess, usageControl: ?/bulkSetUsageControl, clearFee: ?/bulkClearFee, removeAccess: ?/bulkRemovePaidAccess, };值得注意的实现要点批量操作栏本身不直接执行写入——点击按钮只是开启一个表单BULK_ACTIONS注释Each opens a form — nothing applies straight from the bar真正的写入走 SvelteKit 的表单动作form action。这正好呼应文档应用前必须确认对话框的设计BulkActionDialog.svelte会把选中的versionIds放入隐藏字段versionIds通过use:enhance提交到BULK_ACTION_FORM[action]对应的动作。BulkActionDialog.svelte 在安全细节上做了大量设计不允许点击外部关闭interactOutsideBehaviorignore这些表单承载着整个选择的定价一次误点会丢弃它或在中途写入时隐藏仍在运行的 apply写入进行中不可关闭请求无论如何都会继续关闭会让创作者对半个选择还在变更毫无感知破坏性操作需要输入确认词clearFee要求输入clear、removeAccess要求输入remove且文案直白Theres no undo — export first if you want a record.没有撤销——想要记录就先导出成功后对话框变成回执而非直接关闭一次操作通常是下一个操作的铺垫——成功面板显示{updated} versions updated、被跳过/失败的计数以及这 N 个版本仍处于选中状态并可一键衔接下一个建议动作如设置费用后建议Set download price部分失败可见skipped如已发布版本无法再开早访问窗口与failed如无法门控的 usage control以 Alert 形式列出。五、数据读取readspage.server.ts数据在服务端加载通过civitai/dbkysely无 Prisma 引擎查询作用域严格限定为locals.user.id与 models.md § Data 的形状一致。需要加载的内容包括创作者的模型 版本及其费用字段licensingFee、licensingFeeType、active标志见 plan §7.1——成员费用在会员失效时自动暂停、但保留数值以及每个版本的模型类型驱动默认建议。用户的会员tier决定费用写入是否可用——复用主应用既有端点/服务见 plan §5.2。getDefaultFeeSuggestions模型类型默认费用建议LoRA 约 0.1、base 约 1 buzz/张见 plan §5.3。明确不是分析页无 ClickHouse。表格状态搜索 / 筛选 / 排序 / 分页全部存放在URL searchParams中可深链接、可刷新。另一个明确要求分页或虚拟化是必须的——批量场景本身就是大量版本的场景Paginate/virtualize — the bulk caseisthe many-versions case。源码印证费用的输入形态与比率模型值得展开的是费用字段的实际录入形态。虽然文档写的是fractional (0.01 precision)源码 licensing-fee.ts 表明用户界面从不输入小数而是输入N ⚡ per M images的整数字符串由服务端转换为每张图的小数费用export const licensingFeeRatioSchema z .object({ buzz: z.coerce.number().int().min(0, Buzz cannot be negative.), images: z.coerce.number().int().refine((n) IMAGE_VALUES.includes(n), Choose one of the offered image amounts.), }) .transform((v, ctx) { if (v.buzz 0) return null; // empty / 0 buzz clears the fee const perImage Math.round((v.buzz / v.images) * 100) / 100; if (perImage 0) { /* That fee rounds to nothing — the smallest is 1 ⚡ per 100 generations. */ } if (perImage FEE_SCHEMA_CEILING) { /* too high */ } return perImage; });这段代码同时说明了边界约束最小费用1 ⚡ / 100 次生成 0.01 buzz/张呼应 plan §9 中 Justin 确认的费用可小至 1 buzz per 100 images最大费用FEE_SCHEMA_CEILING maxLicensingFeeCeiling(video)源码注释明确这是500与civitai/buzz中MAX_LICENSING_FEE 100的每图基准区分开且按媒体的capMediaType轴浮动0 即清除buzz 0或归零的费用都表示清除费用。相关的常量与工具函数统一从civitai/buzz包转发fee.tsMAX_LICENSING_FEE、FEE_IMAGE_OPTIONS、DEFAULT_FEE_IMAGES、SUGGESTED_FEE_PER_IMAGE、DEFAULT_SUGGESTED_FEE_PER_IMAGE、feeToRatio、ratioToFee、formatFeeRatio、maxLicensingFeeCeiling、capMediaType、monetizationLimits、resolveCapTier、feeMaxFor、suggestedFee、seedFeeRatio、suggestedFeeRatio等。formatFeeRatio渲染媒体无关的 N ⚡ / M generations 标签费用适用于图片、视频等。默认建议的实际落地可见 settings/page.svelte/settings/page.svelte) 的文案1 ⚡ / generation, LoRAs 1 ⚡ / 10 generations即 base 1 buzz/张、LoRA 0.1 buzz/张PricingSlotHistory.svelte 也确认默认费用是 0.1/image。六、动作写入writesform actions → monetization 模块所有批量变更都通过 creator-studio 的monetization 模块apps/creator-studio/src/lib/server/monetization/执行用 kysely 直接写ModelVersion表——不发 buzz 调用、不写 ClickHouse这是 plan §5.1 的核心架构决策业务逻辑运行在进程内无主应用 tRPC 跳转。文档给出的动作表必须完整继承动作操作备注对选中的版本应用费用bulkSetLicensingFee(versionIds, fee)仅限会员支持小数0.01 精度校验边界。即使费用被暂停数值也保留。清除选中版本的费用bulkSetLicensingFee(versionIds, null)在整个选择范围内关闭费用。按类型应用默认建议按解析出的默认值逐个执行bulkSetLicensingFee先通过getDefaultFeeSuggestions解析每个版本的默认值再设置。安全与一致性约束授权在模块内部断言会员tier针对整个批次——禁用的 UI 只是 UX服务端会重新校验所有权按版本检查批次必须确认locals.user.id拥有每一个id与 models.md § Actions 一致叠加stacking不在这里处理——后端已经处理plan §7.3乐观更新金钱字段可以接受但失败要回滚部分失败要报告哪些 id 失败。源码印证bulkSetLicensingFee的完整校验链licensing-fee.ts 中的bulkSetLicensingFee完整实现了上述约束其校验链路可以拆解为归一化normalizeFee把原始输入钳制/四舍五入到[0, FEE_SCHEMA_CEILING]内的两位小数null表示清除非法输入返回undefined。空选择拒绝Select at least one version.。所有权 字段装配ownedVersions通过ModelVersion ⋈ Model联表查询WHERE Model.userId userId AND Model.deletedAt IS NULL——查询本身即所有权检查Doubles as the ownership check并带出费用操作所需的baseModel非商用守卫、modelType按类型默认、currentFee、poi真实人物等字段。非商用 base model 拦截NON_COMMERCIAL_BASE_MODELS new Set([Ideogram 4.0])——其许可禁止商用不能带费用与主应用server/common/constants.ts的nonCommercialBaseModels保持同步。真实人物POI拦截licensingFeeBlockedFor({ poi })—— A model depicting a real person cant be monetized. 对应测试见 licensing-fee-poi-guard.test.ts。按版本的仅增上限检查raisesOverCap(normalized, v.currentFee, maxLicensingFeeCeiling(capMediaType(v.baseModel)))——批次只有在会把某个版本抬升到其媒体类型上限以上时才被拒绝这样在混合选择上重新应用祖父级费用仍然可行。错误信息会给出最严格的上限并点名最多 5 个违规版本nameList防止1 of them无法定位见注释 868m15nnc。月度定价额度pricing slots只有从未定价 → 定价的版本消耗额度unpricedVersionIds判定条件是无费用且无永久门控——避免对已在出售的版本二次计费再经assertPricingAllowed(userId, membership, newlyPricedIds.length)校验资格下限与每月额度清除费用时releasePricingSlots在事务外依据写后状态释放可释放版本releasableVersionIds。权利声明rights affirmation给尚无声明记录的版本先stampRightsAffirmation用 SQLCOALESCE(meta, {}::jsonb) || ...合并避免读改写覆盖主应用的其他 key若存在待声明版本而用户未勾选确认返回RIGHTS_AFFIRMATION_REQUIRED_ERROR。单事务写入writeFeestampRightsAffirmationrecordPricingSlots在一个dbWrite.transaction()内完成——一个费用上线却没有其声明记录正是该功能要杜绝的产物。清除时还会一并清掉licensingFeeType与licensingFeeSettlementCurrency残留的类型/货币描述着一个已不存在的费用。清除费用时释放定价额度事务提交后、基于写后状态调用releasePricingSlots。路由侧models/page.server.ts/models/page.server.ts)的bulkSetFee表单动作解析隐藏字段versionIds逗号分隔、经 zodversionIdsSchema校验调用bulkSetLicensingFee成功后调用bustVersionCache使版本缓存失效——注意当前仓库中批量费用 UI 实际落在/models路由下对应文档无论渲染在哪里的承诺。七、状态States设计文档枚举了批量编辑器必须处理的全部状态Loading加载中骨架行skeleton rows。Empty空没有模型 → 空状态 指向主应用上传页的链接与 models.md 相同。Nothing selected未选中批量操作栏隐藏表格只读。Non-member非会员页面正常加载但费用/应用/清除控件禁用并附/join升级引导费用是会员门控功能。Fee paused费用暂停版本所有者的会员过期 → 显示Paused数值保留、不再计费plan §7.1。Error / partial错误/部分失败toast 失败 id 的行内错误乐观变更回滚。源码印证乐观更新与回执语义BulkActionDialog.svelte 的提交处理submit正是文档乐观更新 失败回滚 部分失败报告的实现成功时把表单动作返回的updated/skipped/failed计数送入回执面板文档注释The action only fails outright when NOTHING succeeded, so a run that skipped or failed most of the selection still lands here and has to say so.——只有全部失败才是 failure 分支跳过/部分失败必须如实呈现随后invalidateAll()刷新数据选择被刻意保留——一次成功的写入正是把行移出当前筛选的操作写完后这些行恰好不再匹配筛选。对话框还针对跨页选择给出了实现级答案因为select all matching会触及本页从未加载过的版本freeGenPreview/unpricedPreview/publishedPreview都以fetch(formAction)在服务端解析避免用页面可见行推断全量选择。八、门控Gating每一次费用写入都受会员tier门控这里不存在未门控的批量动作。双层执行UI 层禁用 tooltip 提示模块层对整个批次重新校验。具体门槛tier 还是完整 CP 会员在当时尚未最终拍板plan §9。不过计划文档记录了后续决定2026-07-09所有会员专属动作统一以完整 Creator Program 会员身份为单一门槛理由是仅凭 tier 会让新注册的 bronze 订阅者就能给他人模型设费CP 需要创作者评分 ≥ 40000见 pre-implementation-decisions.md B1并从onboardingCP 标志解析。九、共享与交叉引用行组件 setLicensingFee/bulkSetLicensingFee与 models.md 共享——本文档规范的是同一份数据上的批量表面不是分叉实现。每账户默认费用建议 / 结算货币默认值见 settings.md。导航项通过共享的nav.ts支持memberOnly标记会员感知。十、开放问题Open questions文档在收尾处列出构建前必须回答的问题摘录如下作为设计评审清单很有价值独立页 vs/models模式——即第二节的分叉构建前必须决策A / B / C。默认值应用语义——只应用到选中的版本还是应用到某一模型类型的全部版本覆盖已有费用还是只填充空费用倾向仅选中 一个说明多少版本已有费用的确认。跨页选择——多选是否跨分页页面持久化全选匹配是服务端筛选应用更安全无超大 id 列表吗选择是否应存活在 URL 状态中批量范围——仅费用还是也包括批量访问开关/ 无限期销售倾向v1 仅费用——访问是 models.md 上的逐版本操作。误覆盖护栏——强制确认对话框需包含受影响计数与变更前后摘要对于金钱字段是否需要一个撤销 / 近期变更记录界面十一、参考路径速查设计文档docs/creator-studio/licensing.md单版本管理docs/creator-studio/models.md实施计划含 §5.3 操作、§7.1 架构、§8 分期、§9 决策docs/creator-studio-plan.md批量动作枚举apps/creator-studio/src/lib/monetization/bulk-actions.ts批量操作栏组件apps/creator-studio/src/lib/components/BulkBar.svelte批量确认对话框apps/creator-studio/src/lib/components/BulkActionDialog.svelte费用工具函数转发civitai/buzzapps/creator-studio/src/lib/monetization/fee.ts服务端费用写入含setLicensingFee/bulkSetLicensingFeeapps/creator-studio/src/lib/server/monetization/licensing-fee.ts批量费用守卫测试apps/creator-studio/src/lib/server/tests/licensing-fee-poi-guard.test.ts批量表单动作挂载点apps/creator-studio/src/routes/(app)/models/page.server.ts/models/page.server.ts)【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询