feat(models-sync): official upstream sync with conflict resolution UI, opt‑out flag, and backend resiliency

Backend
- Add endpoints:
  - GET /api/models/sync_upstream/preview — diff preview (filters out models with sync_official = 0)
  - POST /api/models/sync_upstream — apply sync (create missing; optionally overwrite selected fields)
- Respect opt‑out: skip models with sync_official = 0 in both preview and apply
- Return detailed stats: created_models, created_vendors, updated_models, skipped_models, plus created_list / updated_list
- Add model.Model.SyncOfficial (default 1); auto‑migrated by GORM
- Make HTTP fetching robust:
  - Shared http.Client (connection reuse) with 3x exponential backoff retry
  - 10MB response cap; keep existing IPv4‑first for *.github.io
- Vendor handling:
  - New ensureVendorID helper (cache lookup → DB lookup → create), reduces round‑trips
  - Transactional overwrite to avoid partial updates
- Small cleanups and clearer helpers (containsField, coalesce, chooseStatus)

Frontend
- ModelsActions: add “Sync official” button with Popover (p‑2) explaining community contribution; loading = syncing || previewing; preview → conflict modal → apply flow
- New UpstreamConflictModal:
  - Per‑field columns (description/icon/tags/vendor/name_rule/status) with column‑level checkbox to select all
  - Cell with Checkbox + Tag (“Click to view differences”) and Popover (p‑2) showing Local vs Official values
  - Auto‑hide columns with no conflicts; responsive width; use native Semi Modal footer
  - Full i18n coverage
- useModelsData: add syncing/previewing states; new methods previewUpstreamDiff, applyUpstreamOverwrite, syncUpstream; refresh vendors/models after apply
- EditModelModal: add “Participate in official sync” switch; persisted as sync_official
- ModelsColumnDefs: add “Participate in official sync” column

i18n
- Add missing English keys for the new UI and messages; fix quoting issues

Refs
- Upstream metadata: https://github.com/basellm/llm-metadata
This commit is contained in:
t0ng7u
2025-09-02 02:04:22 +08:00
parent 55c8271311
commit 54f118d9ba
10 changed files with 902 additions and 22 deletions

View File

@@ -1,6 +1,5 @@
{
"主页": "Home",
"文档": "Docs",
"控制台": "Console",
"$%.6f 额度": "$%.6f quota",
"或": "or",
@@ -165,7 +164,6 @@
"出现错误,第 ${count} 次重试中...": "Error occurred, retry attempt ${count}...",
"首页": "Home",
"渠道": "Channel",
"渠道管理": "Channels",
"令牌": "Tokens",
"兑换额度": "Redeem",
"充值": "Recharge",
@@ -174,7 +172,6 @@
"设置": "Settings",
"关于": "About",
"价格": "Pricing",
"聊天": "Chat",
"注销成功!": "Logout successful!",
"注销": "Logout",
"登录": "Sign in",
@@ -443,9 +440,7 @@
"兑换码": "Redeem Code",
"管理用户": "Manage Users",
"额度明细": "Quota Details",
"个人设置": "Personal Settings",
"运营设置": "Operation Settings",
"系统设置": "System Settings",
"其他设置": "Other Settings",
"项目仓库地址": "Project Repository Address",
"可在设置页面设置关于内容,支持 HTML & Markdown": "The About content can be set on the settings page, supporting HTML & Markdown",
@@ -585,10 +580,7 @@
"确定是否要修复数据库一致性?": "Are you sure you want to repair database consistency?",
"进行该操作时,可能导致渠道访问错误,请仅在数据库出现问题时使用": "When performing this operation, it may cause channel access errors. Please only use it when there is a problem with the database.",
"当前没有可用的启用令牌,请确认是否有令牌处于启用状态!": "There are currently no enablement tokens available, please confirm if one is enabled!",
"令牌管理": "API Keys",
"使用日志": "Usage log",
"Midjourney日志": "Midjourney",
"数据看板": "Dashboard",
"模型列表": "Model list",
"常见问题": "FAQ",
"免费体验": "Free trial",
@@ -628,7 +620,6 @@
"重置成功": "Reset successful",
"加载数据出错:": "Error loading data:",
"加载数据时发生错误: ": "An error occurred while loading data:",
"保存成功": "Saved successfully",
"部分保存失败,请重试": "Partial saving failed, please try again",
"请检查输入": "Please check your input",
"如何区分不同分组不同模型的价格:供参考的配置方式": "How to distinguish the prices of different models in different groups: configuration method for reference",
@@ -653,7 +644,6 @@
"窗口等待": "window wait",
"失败": "Failed",
"绘图": "Drawing",
"绘图日志": "Drawing log",
"放大": "Upscalers",
"微妙放大": "Upscale (Subtle)",
"创造放大": "Upscale (Creative)",
@@ -793,7 +783,6 @@
"邮箱": "Email",
"已有账户?": "Already have an account?",
"创意任务": "Tasks",
"用户管理": "User Management",
"任务ID点击查看详情": "Task ID (click to view details)",
"进度": "schedule",
"花费时间": "spend time",
@@ -943,7 +932,6 @@
"不是合法的 JSON 字符串": "Not a valid JSON string",
"个人中心": "Personal center",
"代理商": "Agent",
"钱包管理": "Wallet",
"备注": "Remark",
"工作台": "Workbench",
"已复制:": "Copied:",
@@ -957,7 +945,6 @@
"黑夜模式": "Dark mode",
"管理员设置": "Admin",
"待更新": "To be updated",
"模型广场": "Pricing",
"支付中..": "Paying",
"查看图片": "View pictures",
"并发限制": "Concurrency limit",
@@ -1043,7 +1030,6 @@
"在iframe中加载": "Load in iframe",
"补全倍率": "Completion ratio",
"保存分组数据失败": "Failed to save group data",
"保存失败,请重试": "Save failed, please try again",
"没有可用的使用信息": "No usage information available",
"使用详情": "Usage details",
"收起": "Collapse",
@@ -1187,7 +1173,6 @@
"知识库 ID": "Knowledge Base ID",
"请输入知识库 ID例如123456": "Please enter knowledge base ID, e.g.: 123456",
"可选值": "Optional value",
"任务日志": "Task log",
"你好": "Hello",
"你好,请问有什么可以帮助您的吗?": "Hello, how may I help you?",
"用户分组": "Your default group",
@@ -1329,7 +1314,6 @@
"当剩余额度低于此数值时,系统将通过选择的方式发送通知": "When the remaining quota is lower than this value, the system will send a notification through the selected method",
"Webhook请求结构": "Webhook request structure",
"只支持https系统将以 POST 方式发送通知,请确保地址可以接收 POST 请求": "Only https is supported, the system will send a notification through POST, please ensure the address can receive POST requests",
"保存设置": "Save settings",
"通知邮箱": "Notification email",
"设置用于接收额度预警的邮箱地址,不填则使用账号绑定的邮箱": "Set the email address for receiving quota warning notifications, if not set, the email address bound to the account will be used",
"留空则使用账号绑定的邮箱": "If left blank, the email address bound to the account will be used",
@@ -1501,7 +1485,6 @@
"收益": "Earnings",
"无邀请人": "No Inviter",
"邀请人": "Inviter",
"兑换码管理": "Redemption Code",
"设置兑换码的基本信息": "Set redemption code basic information",
"设置兑换码的额度和数量": "Set redemption code quota and quantity",
"编辑用户": "Edit User",
@@ -1595,7 +1578,6 @@
"加载中...": "Loading...",
"正在跳转...": "Redirecting...",
"暂无公告": "No Notice",
"操练场": "Playground",
"欢迎使用,请完成以下设置以开始使用系统": "Welcome to use, please complete the following settings to start using the system",
"数据库检查": "Database Check",
"验证数据库连接状态": "Verify database connection status",
@@ -1811,7 +1793,6 @@
"系统提示覆盖": "System prompt override",
"模型: {{ratio}}": "Model: {{ratio}}",
"专属倍率": "Exclusive group ratio",
"模型管理": "Models",
"匹配类型": "Matching type",
"描述": "Description",
"供应商": "Vendor",
@@ -2075,5 +2056,18 @@
"保存边栏设置": "Save Sidebar Settings",
"侧边栏设置保存成功": "Sidebar settings saved successfully",
"需要登录访问": "Require Login",
"开启后未登录用户无法访问模型广场": "When enabled, unauthenticated users cannot access the model marketplace"
"开启后未登录用户无法访问模型广场": "When enabled, unauthenticated users cannot access the model marketplace",
"同步官方": "Sync official",
"参与官方同步": "Participate in official sync",
"关闭后,此模型将不会被“同步官方”自动覆盖或创建": "When turned off, this model will be skipped by Sync official (no auto create/overwrite)",
"选择要覆盖的冲突项": "Select conflict items to overwrite",
"点击查看差异": "Click to view differences",
"无冲突项": "No conflict items",
"应用覆盖": "Apply overwrite",
"仅会覆盖你勾选的字段,未勾选的字段保持本地不变。": "Only selected fields will be overwritten; unselected fields remain unchanged.",
"本地": "Local",
"官方": "Official",
"模型社区需要大家的共同维护,如发现数据有误或想贡献新的模型数据,请访问:": "The model community needs everyone's contribution. If you find incorrect data or want to contribute new models, please visit:",
"是": "Yes",
"否": "No"
}