您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在 SiliconFlow 价格页面添加筛选功能
// ==UserScript== // @name SiliconFlow 模型筛选器 // @namespace siliconflow-model-filter // @version 2025.0.1 // @description 在 SiliconFlow 价格页面添加筛选功能 // @author delph1s // @license MIT // @icon https://siliconflow.cn/logo-footer.svg // @match https://siliconflow.cn/pricing* // @match https://siliconflow.cn/pricing // @grant none // ==/UserScript== (function() { 'use strict'; let isExpanded = false; let extractedModels = []; // 创建样式 function createStyles() { const style = document.createElement('style'); style.textContent = ` /* 主容器 */ #sf-filter-container { position: fixed !important; bottom: 14px !important; right: 14px !important; z-index: 99999 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; } /* 浮动按钮 */ #sf-filter-container .sf-toggle-btn { width: 28px !important; height: 28px !important; border-radius: 14px !important; background: linear-gradient(135deg, rgba(255,255,255,0.25), rgba(255,255,255,0.1)) !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(10px) !important; border: 1px solid rgba(255,255,255,0.2) !important; box-shadow: 0 8px 32px rgba(0,0,0,0.1), 0 2px 8px rgba(0,0,0,0.05) !important; cursor: pointer !important; display: flex !important; align-items: center !important; justify-content: center !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; color: #333 !important; font-size: 14px !important; font-weight: 600 !important; margin: 0 !important; padding: 0 !important; } #sf-filter-container .sf-toggle-btn:hover { transform: scale(1.2) !important; box-shadow: 0 12px 40px rgba(0,0,0,0.15), 0 4px 12px rgba(0,0,0,0.1) !important; } /* 主面板 */ #sf-filter-container .sf-panel { position: absolute !important; bottom: 0 !important; right: 0 !important; width: 360px !important; max-height: 80vh !important; background: linear-gradient(135deg, rgba(255,255,255,0.25), rgba(255,255,255,0.1)) !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(10px) !important; border-radius: 14px !important; border: 1px solid rgba(255,255,255,0.3) !important; box-shadow: 0 20px 60px rgba(0,0,0,0.1), 0 8px 24px rgba(0,0,0,0.05) !important; padding: 24px !important; transform: scale(0.8) translateX(360px) !important; opacity: 0 !important; visibility: hidden !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; overflow: hidden !important; margin: 0 !important; } #sf-filter-container .sf-panel.expanded { // animation: sf-panel-bounce-in 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards; transform: scale(1) translateX(0) !important; opacity: 1 !important; visibility: visible !important; } @keyframes sf-panel-bounce-in { 0% { transform: scale(0.3) translateX(300px) !important; opacity: 0 !important; visibility: visible !important; } 25% { transform: scale(0.7) translateX(150px) !important; opacity: 0.7 !important; } 50% { transform: scale(1.1) translateX(-20px) !important; opacity: 0.9 !important; } 65% { transform: scale(0.9) translateX(10px) !important; opacity: 1 !important; } 80% { transform: scale(1.05) translateX(-5px) !important; } 100% { transform: scale(1) translateX(0) !important; opacity: 1 !important; visibility: visible !important; } } /* 标题 */ #sf-filter-container .sf-title { font-size: 24px !important; font-weight: 700 !important; color: #1d1d1f !important; margin: 0 0 14px 0 !important; padding: 0 !important; text-align: center !important; background: linear-gradient(135deg, #007AFF, #5856D6) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; background-clip: text !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; line-height: 1.2 !important; border: none !important; } /* 关闭按钮 */ #sf-filter-container .sf-close-btn { position: absolute !important; top: 14px !important; right: 14px !important; width: 24px !important; height: 24px !important; border-radius: 14px !important; background: rgba(142, 142, 147, 0) !important; color: #8e8e93 !important; cursor: pointer !important; display: flex !important; align-items: center !important; justify-content: center !important; font-size: 14px !important; transition: all 0.3s ease !important; margin: 0 !important; padding: 0 !important; border: none !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; } #sf-filter-container .sf-close-btn:hover { background: rgba(142, 142, 147, 0.2) !important; color: #1d1d1f !important; } /* 表单组 */ #sf-filter-container .sf-form-group { line-height: 0 !important; margin: 0 0 14px 0 !important; padding: 0 !important; } #sf-filter-container .sf-label { display: block !important; font-size: 16px !important; font-weight: 600 !important; color: #1d1d1f !important; margin: 0 0 7px 0 !important; padding: 0 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; line-height: 1.2 !important; border: none !important; background: none !important; } /* 输入框和选择框 */ #sf-filter-container .sf-input, #sf-filter-container .sf-select { width: 100% !important; padding: 8px 12px !important; background: rgba(142, 142, 147, 0) !important; border: 1px solid rgba(0, 122, 255, 0.5) !important; border-radius: 7px !important; font-size: 14px !important; color: #1d1d1f !important; transition: all 0.2s ease !important; outline: none !important; margin: 0 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; box-sizing: border-box !important; } #sf-filter-container .sf-input:focus, #sf-filter-container .sf-select:focus { background: rgba(255, 255, 255, 0) !important; border-color: rgba(0, 122, 255, 1) !important; // box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.1) !important; } #sf-filter-container .sf-input::placeholder { color: #8e8e93 !important; } /* 按钮 */ #sf-filter-container .sf-btn { width: 100% !important; // height: 36px !important; border-radius: 7px !important; font-size: 14px !important; font-weight: 600 !important; cursor: pointer !important; transition: all 0.3s ease !important; margin: 0 0 14px 0 !important; display: flex !important; align-items: center !important; justify-content: center !important; outline: none !important; padding: 8px 12px !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; box-sizing: border-box !important; border: none !important; } #sf-filter-container .sf-btn-primary { background: linear-gradient(135deg, #007AFFBC, #5856D6BC) !important; color: white !important; } #sf-filter-container .sf-btn-primary:hover { transform: translateY(-1px) !important; box-shadow: 0 8px 25px rgba(0, 122, 255, 0.3) !important; } #sf-filter-container .sf-btn-success { background: linear-gradient(135deg, #34C759BC, #30D158BC) !important; color: white !important; } #sf-filter-container .sf-btn-success:hover:not(:disabled) { transform: translateY(-1px) !important; box-shadow: 0 8px 25px rgba(52, 199, 89, 0.3) !important; } #sf-filter-container .sf-btn:disabled { opacity: 0.5 !important; cursor: not-allowed !important; transform: none !important; } /* 统计信息 */ #sf-filter-container .sf-stats { text-align: center !important; font-size: 14px !important; color: #8e8e93 !important; margin: 0 0 14px 0 !important; padding: 8px 12px !important; background: rgba(142, 142, 147, 0.08) !important; border-radius: 7px !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; font-weight: 400 !important; border: none !important; } /* 结果区域 */ #sf-filter-container .sf-result-area { max-height: 200px !important; overflow-y: auto !important; border-radius: 12px !important; background: rgba(142, 142, 147, 0) !important; border: 1px solid rgba(142, 142, 147, 0.1) !important; margin: 0 !important; padding: 0 !important; } #sf-filter-container .sf-textarea { width: 100% !important; height: 200px !important; padding: 16px !important; border: none !important; background: transparent !important; color: #1d1d1f !important; font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace !important; font-size: 12px !important; line-height: 1.5 !important; resize: none !important; outline: none !important; margin: 0 !important; box-sizing: border-box !important; } #sf-filter-container .sf-textarea::placeholder { color: #8e8e93 !important; } /* 滚动条样式 */ #sf-filter-container .sf-result-area::-webkit-scrollbar, #sf-filter-container .sf-panel::-webkit-scrollbar { width: 6px !important; } #sf-filter-container .sf-result-area::-webkit-scrollbar-track, #sf-filter-container .sf-panel::-webkit-scrollbar-track { background: rgba(142, 142, 147, 0.1) !important; border-radius: 3px !important; } #sf-filter-container .sf-result-area::-webkit-scrollbar-thumb, #sf-filter-container .sf-panel::-webkit-scrollbar-thumb { background: rgba(142, 142, 147, 0.3) !important; border-radius: 3px !important; } #sf-filter-container .sf-result-area::-webkit-scrollbar-thumb:hover, #sf-filter-container .sf-panel::-webkit-scrollbar-thumb:hover { background: rgba(142, 142, 147, 0.5) !important; } /* 动画 */ @keyframes sf-bounce-in { 0% { transform: scale(0.3); opacity: 0; } 50% { transform: scale(1.05); } 70% { transform: scale(0.9); } 100% { transform: scale(1); opacity: 1; } } #sf-filter-container .sf-toggle-btn.sf-animate { animation: sf-bounce-in 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) !important; } `; document.head.appendChild(style); } // 创建界面 function createFilterUI() { const container = document.createElement('div'); container.id = 'sf-filter-container'; container.innerHTML = ` <div class="sf-toggle-btn sf-animate" id="sf-toggle">⚡</div> <div class="sf-panel" id="sf-panel"> <div class="sf-close-btn" id="sf-close">×</div> <div class="sf-title">硅基流动模型筛选器</div> <div class="sf-form-group"> <label class="sf-label">关键词筛选</label> <input type="text" id="sf-keywords" class="sf-input" placeholder="输入关键词,用逗号分隔,如:gpt,claude"> </div> <div class="sf-form-group"> <label class="sf-label">免费模型</label> <select id="sf-free-filter" class="sf-select"> <option value="all">所有模型</option> <option value="free-only">仅免费模型</option> <option value="paid-only">仅付费模型</option> </select> </div> <div class="sf-form-group"> <label class="sf-label">模型类型</label> <select id="sf-model-type" class="sf-select"> <option value="all">所有类型</option> <option value="text">文本模型</option> <option value="image">图像模型</option> <option value="audio">音频模型</option> <option value="video">视频模型</option> <option value="embedding">嵌入模型</option> </select> </div> <div class="sf-form-group"> <label class="sf-label">输出格式</label> <select id="sf-output-format" class="sf-select"> <option value="comma">逗号分隔</option> <option value="newline">换行分隔</option> <option value="detailed">详细信息</option> </select> </div> <button id="sf-filter-btn" class="sf-btn sf-btn-primary">筛选模型</button> <button id="sf-copy-btn" class="sf-btn sf-btn-success" disabled>复制结果</button> <div class="sf-stats"> 找到的模型数量: <span id="sf-model-count">0</span> </div> <div class="sf-result-area"> <textarea id="sf-result-output" class="sf-textarea" placeholder="筛选结果将显示在这里..." readonly></textarea> </div> </div> `; document.body.appendChild(container); // 绑定事件 document.getElementById('sf-toggle').addEventListener('click', togglePanel); document.getElementById('sf-close').addEventListener('click', togglePanel); document.getElementById('sf-filter-btn').addEventListener('click', filterModels); document.getElementById('sf-copy-btn').addEventListener('click', copyResults); // 实时筛选 ['sf-keywords', 'sf-free-filter', 'sf-model-type', 'sf-output-format'].forEach(id => { const element = document.getElementById(id); if (element) { element.addEventListener('change', filterModels); if (element.type === 'text') { element.addEventListener('input', filterModels); } } }); // 首次提取数据 extractModelData(); } // 切换面板 function togglePanel() { const panel = document.getElementById('sf-panel'); isExpanded = !isExpanded; if (isExpanded) { panel.classList.add('expanded'); } else { panel.classList.remove('expanded'); } } // 改进的数据提取函数,专门针对Next.js格式 function extractModelData() { console.log('开始提取模型数据...'); extractedModels = []; try { // 查找包含模型数据的script标签 const scripts = document.querySelectorAll('script'); let modelsData = null; for (let script of scripts) { const content = script.textContent; if (content && content.includes('self.__next_f.push') && content.includes('chats')) { // 提取JSON数据 const match = content.match(/self\.__next_f\.push\(\[.*?\]\)/); if (match) { try { // 解析推送的数据 const pushData = match[0].replace('self.__next_f.push(', '').slice(0, -1); const parsed = JSON.parse(pushData); // 查找包含模型数据的部分 if (parsed.length > 1 && typeof parsed[1] === 'string') { const jsonStr = parsed[1].replace(/^\d+:\[/, '[').replace(/\]$/, ']'); const dataArray = JSON.parse(jsonStr); // 查找数据对象 if (!!dataArray[1] && !!dataArray[1][3] && !!dataArray[1][3].data) { modelsData = dataArray[1][3].data; parseModelData(modelsData); } else { console.warn('未找到数据'); } } } catch (e) { console.warn('解析Next.js数据时出错:', e); } } } } console.log(`最终提取到 ${extractedModels.length} 个模型`); } catch (error) { console.error('提取模型数据时出错:', error); } } // 解析模型数据 function parseModelData(data) { const categories = [ { key: 'chats', type: 'text' }, { key: 'images', type: 'image' }, { key: 'audios', type: 'audio' }, { key: 'videos', type: 'video' }, { key: 'embeddings', type: 'embedding' } ]; categories.forEach(({ key, type }) => { if (data[key] && Array.isArray(data[key])) { console.log(`处理 ${key} 类别,找到 ${data[key].length} 个模型`); data[key].forEach(model => { extractedModels.push({ ...model, category: type }); }); } }); } // 在数据中查找模型 function findModelsInData(data) { if (Array.isArray(data)) { data.forEach(item => findModelsInData(item)); } else if (data && typeof data === 'object') { if (data.chats || data.images || data.audios || data.videos || data.embeddings) { parseModelData(data); } else { Object.values(data).forEach(value => { if (typeof value === 'object') { findModelsInData(value); } }); } } } // 判断模型是否免费 function isModelFree(model) { const pricing = model.pricing || []; // 检查所有价格是否为0 const allPricesZero = pricing.every(p => parseFloat(p.price) === 0); // 检查通用价格字段 const generalPrice = parseFloat(model.price) || 0; const inputPrice = parseFloat(model.inputPrice) || 0; return allPricesZero && generalPrice === 0 && inputPrice === 0; } // 检查模型名称是否包含关键词 function matchesKeywords(modelName, keywords) { if (!keywords.trim()) return true; const keywordList = keywords.split(',').map(k => k.trim().toLowerCase()).filter(k => k); const modelNameLower = modelName.toLowerCase(); return keywordList.some(keyword => modelNameLower.includes(keyword)); } // 筛选模型 function filterModels() { console.log('开始筛选模型...'); if (extractedModels.length === 0) { console.log('没有模型数据,重新提取...'); extractModelData(); if (extractedModels.length === 0) { console.warn('仍然没有找到模型数据'); document.getElementById('sf-result-output').value = '没有找到模型数据,请刷新页面重试'; return; } } const keywords = document.getElementById('sf-keywords').value; const freeFilter = document.getElementById('sf-free-filter').value; const modelType = document.getElementById('sf-model-type').value; const outputFormat = document.getElementById('sf-output-format').value; console.log('筛选参数:', { keywords, freeFilter, modelType, outputFormat }); console.log('可用模型数量:', extractedModels.length); const filteredModels = extractedModels.filter(model => { // 类型筛选 if (modelType !== 'all' && model.category !== modelType) { return false; } // 关键词筛选 if (!matchesKeywords(model.modelName, keywords)) { return false; } // 免费模型筛选 const isFree = isModelFree(model); if (freeFilter === 'free-only' && !isFree) { return false; } if (freeFilter === 'paid-only' && isFree) { return false; } return true; }); console.log('筛选后模型数量:', filteredModels.length); // 按模型名称排序 filteredModels.sort((a, b) => a.modelName.localeCompare(b.modelName)); // 生成输出 let output = ''; if (outputFormat === 'detailed') { output = filteredModels.map(model => { const isFree = isModelFree(model); const freeStatus = isFree ? '免费' : '付费'; return `${model.modelName} | ${freeStatus} | ${model.category}`; }).join('\n'); } else { const modelNames = filteredModels.map(model => model.modelName); output = outputFormat === 'comma' ? modelNames.join(', ') : modelNames.join('\n'); } document.getElementById('sf-result-output').value = output; document.getElementById('sf-model-count').textContent = filteredModels.length; document.getElementById('sf-copy-btn').disabled = filteredModels.length === 0; } // 复制结果 function copyResults() { const textarea = document.getElementById('sf-result-output'); textarea.select(); textarea.setSelectionRange(0, 99999); try { document.execCommand('copy'); const btn = document.getElementById('sf-copy-btn'); const originalText = btn.textContent; btn.textContent = '已复制!'; btn.style.background = 'linear-gradient(135deg, #FF9500, #FF6482)'; setTimeout(() => { btn.textContent = originalText; btn.style.background = 'linear-gradient(135deg, #34C759, #30D158)'; }, 2000); } catch (err) { console.error('复制失败:', err); alert('复制失败,请手动选择文本复制'); } } // 初始化 function init() { createStyles(); createFilterUI(); // 延迟提取数据,确保页面完全加载 setTimeout(() => { extractModelData(); filterModels(); }, 3000); // 定期重试提取数据 const retryInterval = setInterval(() => { if (extractedModels.length === 0) { console.log('重试提取数据...'); extractModelData(); } else { clearInterval(retryInterval); } }, 5000); } // 页面加载完成后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();