/* Copyright (C) 2025 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useRef, useState } from 'react'; import { API, showError, showInfo, showSuccess } from '../../helpers'; import { normalizeModelList } from './upstreamUpdateUtils'; const getManualIgnoredModelCountFromSettings = (settings) => { let parsed = null; if (settings && typeof settings === 'object') { parsed = settings; } else if (typeof settings === 'string') { try { parsed = JSON.parse(settings); } catch (error) { parsed = null; } } if (!parsed || typeof parsed !== 'object') { return 0; } return normalizeModelList(parsed.upstream_model_update_ignored_models).length; }; export const useChannelUpstreamUpdates = ({ t, refresh }) => { const [showUpstreamUpdateModal, setShowUpstreamUpdateModal] = useState(false); const [upstreamUpdateChannel, setUpstreamUpdateChannel] = useState(null); const [upstreamUpdateAddModels, setUpstreamUpdateAddModels] = useState([]); const [upstreamUpdateRemoveModels, setUpstreamUpdateRemoveModels] = useState( [], ); const [upstreamUpdatePreferredTab, setUpstreamUpdatePreferredTab] = useState('add'); const [upstreamApplyLoading, setUpstreamApplyLoading] = useState(false); const [detectAllUpstreamUpdatesLoading, setDetectAllUpstreamUpdatesLoading] = useState(false); const [applyAllUpstreamUpdatesLoading, setApplyAllUpstreamUpdatesLoading] = useState(false); const applyUpstreamUpdatesInFlightRef = useRef(false); const detectChannelUpstreamUpdatesInFlightRef = useRef(false); const detectAllUpstreamUpdatesInFlightRef = useRef(false); const applyAllUpstreamUpdatesInFlightRef = useRef(false); const openUpstreamUpdateModal = ( record, pendingAddModels = [], pendingRemoveModels = [], preferredTab = 'add', ) => { const normalizedAddModels = normalizeModelList(pendingAddModels); const normalizedRemoveModels = normalizeModelList(pendingRemoveModels); if ( !record?.id || (normalizedAddModels.length === 0 && normalizedRemoveModels.length === 0) ) { showInfo(t('该渠道暂无可处理的上游模型更新')); return; } setUpstreamUpdateChannel(record); setUpstreamUpdateAddModels(normalizedAddModels); setUpstreamUpdateRemoveModels(normalizedRemoveModels); const normalizedPreferredTab = preferredTab === 'remove' ? 'remove' : 'add'; setUpstreamUpdatePreferredTab(normalizedPreferredTab); setShowUpstreamUpdateModal(true); }; const closeUpstreamUpdateModal = () => { setShowUpstreamUpdateModal(false); setUpstreamUpdateChannel(null); setUpstreamUpdateAddModels([]); setUpstreamUpdateRemoveModels([]); setUpstreamUpdatePreferredTab('add'); }; const applyUpstreamUpdates = async ({ addModels: selectedAddModels = [], removeModels: selectedRemoveModels = [], } = {}) => { if (applyUpstreamUpdatesInFlightRef.current) { showInfo(t('正在处理,请稍候')); return; } if (!upstreamUpdateChannel?.id) { closeUpstreamUpdateModal(); return; } applyUpstreamUpdatesInFlightRef.current = true; setUpstreamApplyLoading(true); try { const normalizedSelectedAddModels = normalizeModelList(selectedAddModels); const normalizedSelectedRemoveModels = normalizeModelList(selectedRemoveModels); const selectedAddSet = new Set(normalizedSelectedAddModels); const ignoreModels = upstreamUpdateAddModels.filter( (model) => !selectedAddSet.has(model), ); const res = await API.post( '/api/channel/upstream_updates/apply', { id: upstreamUpdateChannel.id, add_models: normalizedSelectedAddModels, ignore_models: ignoreModels, remove_models: normalizedSelectedRemoveModels, }, { skipErrorHandler: true }, ); const { success, message, data } = res.data || {}; if (!success) { showError(message || t('操作失败')); return; } const addedCount = data?.added_models?.length || 0; const removedCount = data?.removed_models?.length || 0; const totalIgnoredCount = getManualIgnoredModelCountFromSettings( data?.settings, ); const ignoredCount = normalizeModelList(ignoreModels).length; showSuccess( t( '已处理上游模型更新:加入 {{added}} 个,删除 {{removed}} 个,本次忽略 {{ignored}} 个,当前已忽略模型 {{totalIgnored}} 个', { added: addedCount, removed: removedCount, ignored: ignoredCount, totalIgnored: totalIgnoredCount, }, ), ); closeUpstreamUpdateModal(); await refresh(); } catch (error) { showError( error?.response?.data?.message || error?.message || t('操作失败'), ); } finally { applyUpstreamUpdatesInFlightRef.current = false; setUpstreamApplyLoading(false); } }; const applyAllUpstreamUpdates = async () => { if (applyAllUpstreamUpdatesInFlightRef.current) { showInfo(t('正在批量处理,请稍候')); return; } applyAllUpstreamUpdatesInFlightRef.current = true; setApplyAllUpstreamUpdatesLoading(true); try { const res = await API.post( '/api/channel/upstream_updates/apply_all', {}, { skipErrorHandler: true }, ); const { success, message, data } = res.data || {}; if (!success) { showError(message || t('批量处理失败')); return; } const channelCount = data?.processed_channels || 0; const addedCount = data?.added_models || 0; const removedCount = data?.removed_models || 0; const failedCount = (data?.failed_channel_ids || []).length; showSuccess( t( '已批量处理上游模型更新:渠道 {{channels}} 个,加入 {{added}} 个,删除 {{removed}} 个,失败 {{fails}} 个', { channels: channelCount, added: addedCount, removed: removedCount, fails: failedCount, }, ), ); await refresh(); } catch (error) { showError( error?.response?.data?.message || error?.message || t('批量处理失败'), ); } finally { applyAllUpstreamUpdatesInFlightRef.current = false; setApplyAllUpstreamUpdatesLoading(false); } }; const detectChannelUpstreamUpdates = async (channel) => { if (detectChannelUpstreamUpdatesInFlightRef.current) { showInfo(t('正在检测,请稍候')); return; } if (!channel?.id) { return; } detectChannelUpstreamUpdatesInFlightRef.current = true; try { const res = await API.post( '/api/channel/upstream_updates/detect', { id: channel.id, }, { skipErrorHandler: true }, ); const { success, message, data } = res.data || {}; if (!success) { showError(message || t('检测失败')); return; } const addCount = data?.add_models?.length || 0; const removeCount = data?.remove_models?.length || 0; showSuccess( t('检测完成:新增 {{add}} 个,删除 {{remove}} 个', { add: addCount, remove: removeCount, }), ); await refresh(); } catch (error) { showError( error?.response?.data?.message || error?.message || t('检测失败'), ); } finally { detectChannelUpstreamUpdatesInFlightRef.current = false; } }; const detectAllUpstreamUpdates = async () => { if (detectAllUpstreamUpdatesInFlightRef.current) { showInfo(t('正在批量检测,请稍候')); return; } detectAllUpstreamUpdatesInFlightRef.current = true; setDetectAllUpstreamUpdatesLoading(true); try { const res = await API.post( '/api/channel/upstream_updates/detect_all', {}, { skipErrorHandler: true }, ); const { success, message, data } = res.data || {}; if (!success) { showError(message || t('批量检测失败')); return; } const channelCount = data?.processed_channels || 0; const addCount = data?.detected_add_models || 0; const removeCount = data?.detected_remove_models || 0; const failedCount = (data?.failed_channel_ids || []).length; showSuccess( t( '批量检测完成:渠道 {{channels}} 个,新增 {{add}} 个,删除 {{remove}} 个,失败 {{fails}} 个', { channels: channelCount, add: addCount, remove: removeCount, fails: failedCount, }, ), ); await refresh(); } catch (error) { showError( error?.response?.data?.message || error?.message || t('批量检测失败'), ); } finally { detectAllUpstreamUpdatesInFlightRef.current = false; setDetectAllUpstreamUpdatesLoading(false); } }; return { showUpstreamUpdateModal, setShowUpstreamUpdateModal, upstreamUpdateChannel, upstreamUpdateAddModels, upstreamUpdateRemoveModels, upstreamUpdatePreferredTab, upstreamApplyLoading, detectAllUpstreamUpdatesLoading, applyAllUpstreamUpdatesLoading, openUpstreamUpdateModal, closeUpstreamUpdateModal, applyUpstreamUpdates, applyAllUpstreamUpdates, detectChannelUpstreamUpdates, detectAllUpstreamUpdates, }; };