✨ 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:
@@ -121,6 +121,7 @@ const EditModelModal = (props) => {
|
||||
endpoints: '',
|
||||
name_rule: props.editingModel?.model_name ? 0 : undefined, // 通过未配置模型过来的固定为精确匹配
|
||||
status: true,
|
||||
sync_official: true,
|
||||
});
|
||||
|
||||
const handleCancel = () => {
|
||||
@@ -145,8 +146,9 @@ const EditModelModal = (props) => {
|
||||
if (!data.endpoints) {
|
||||
data.endpoints = '';
|
||||
}
|
||||
// 处理status,将数字转为布尔值
|
||||
// 处理status/sync_official,将数字转为布尔值
|
||||
data.status = data.status === 1;
|
||||
data.sync_official = (data.sync_official ?? 1) === 1;
|
||||
if (formApiRef.current) {
|
||||
formApiRef.current.setValues({ ...getInitValues(), ...data });
|
||||
}
|
||||
@@ -193,6 +195,7 @@ const EditModelModal = (props) => {
|
||||
tags: Array.isArray(values.tags) ? values.tags.join(',') : values.tags,
|
||||
endpoints: values.endpoints || '',
|
||||
status: values.status ? 1 : 0,
|
||||
sync_official: values.sync_official ? 1 : 0,
|
||||
};
|
||||
|
||||
if (isEdit) {
|
||||
@@ -505,6 +508,16 @@ const EditModelModal = (props) => {
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Switch
|
||||
field='sync_official'
|
||||
label={t('参与官方同步')}
|
||||
extraText={t(
|
||||
'关闭后,此模型将不会被“同步官方”自动覆盖或创建',
|
||||
)}
|
||||
size='large'
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Switch
|
||||
field='status'
|
||||
|
||||
Reference in New Issue
Block a user