mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-30 16:23:31 +00:00
feat(ollama): 按模型请求刷新云端用量
将 Ollama Cloud settings HTML 自动抓取从固定间隔轮询改为请求驱动的 trailing debounce + max-wait:无新请求不再抓取,连续请求最晚在 max-wait 强制刷新;失败退避仍优先于活动 due。新增 debounce_minutes (默认 1),interval_minutes 保留为最长等待兼容字段。
This commit is contained in:
@@ -38,7 +38,7 @@ describe('admin Ollama Cloud usage API', () => {
|
||||
})
|
||||
|
||||
it('uses dedicated global settings endpoints', async () => {
|
||||
const settings = { enabled: false, interval_minutes: 60 }
|
||||
const settings = { enabled: false, interval_minutes: 60, debounce_minutes: 1 }
|
||||
get.mockResolvedValueOnce({ data: settings })
|
||||
put.mockResolvedValueOnce({ data: settings })
|
||||
|
||||
|
||||
@@ -335,11 +335,13 @@ export default {
|
||||
},
|
||||
ollamaCloudUsage: {
|
||||
title: 'Ollama Cloud Usage Refresh',
|
||||
description: 'Periodically refresh official Ollama settings-page usage for individually opted-in accounts. Disabled by default.',
|
||||
description: 'Refresh official Ollama settings-page usage driven by model requests for individually opted-in accounts. Disabled by default. Idle accounts are not polled.',
|
||||
enabled: 'Enable global automatic refresh',
|
||||
enabledHint: 'Only accounts with a stored browser session and their own automatic refresh switch enabled are refreshed. Manual refresh remains available.',
|
||||
intervalMinutes: 'Refresh interval (minutes)',
|
||||
intervalHint: 'Range: 15–1440 minutes. Failures use bounded exponential backoff.',
|
||||
enabledHint: 'Only accounts with a stored browser session and their own automatic refresh switch enabled are refreshed, and only after subsequent model requests. Manual refresh remains available.',
|
||||
intervalMinutes: 'Max wait while requests continue (minutes)',
|
||||
intervalHint: 'Range: 15–1440 minutes. When continuous requests keep sliding the debounce, force a refresh after this wait.',
|
||||
debounceMinutes: 'Quiet period after last request (minutes)',
|
||||
debounceHint: 'Range: 1–60 minutes. Refresh after the latest model request has been quiet for this long.',
|
||||
saved: 'Ollama Cloud usage refresh settings saved',
|
||||
saveFailed: 'Failed to save Ollama Cloud usage refresh settings'
|
||||
},
|
||||
|
||||
@@ -328,11 +328,13 @@ export default {
|
||||
},
|
||||
ollamaCloudUsage: {
|
||||
title: 'Ollama Cloud 用量刷新',
|
||||
description: '定期刷新账号在 Ollama 官方设置页展示的用量;默认关闭。',
|
||||
description: '在模型请求驱动下刷新账号在 Ollama 官方设置页展示的用量;默认关闭。无新请求时不会自动抓取。',
|
||||
enabled: '启用全局自动刷新',
|
||||
enabledHint: '仅刷新已保存浏览器会话且账号自身也开启自动刷新的账号;手动刷新不受影响。',
|
||||
intervalMinutes: '刷新周期(分钟)',
|
||||
intervalHint: '范围 15–1440 分钟。失败后按有上限的指数退避重试。',
|
||||
enabledHint: '仅刷新已保存浏览器会话且账号自身也开启自动刷新的账号;需有后续模型请求才会触发。手动刷新不受影响。',
|
||||
intervalMinutes: '持续请求最长等待(分钟)',
|
||||
intervalHint: '范围 15–1440 分钟。请求持续不断导致 debounce 一直后移时,最晚在此时间强制刷新。',
|
||||
debounceMinutes: '请求安静等待(分钟)',
|
||||
debounceHint: '范围 1–60 分钟。最后一次模型请求安静满此时长后再抓取用量。',
|
||||
saved: 'Ollama Cloud 用量刷新设置已保存',
|
||||
saveFailed: '保存 Ollama Cloud 用量刷新设置失败'
|
||||
},
|
||||
|
||||
@@ -1023,7 +1023,10 @@ export interface OllamaCloudUsageState {
|
||||
|
||||
export interface OllamaCloudUsageSettings {
|
||||
enabled: boolean
|
||||
/** Max wait while model requests keep arriving (minutes). */
|
||||
interval_minutes: number
|
||||
/** Trailing quiet period after the latest model request (minutes). */
|
||||
debounce_minutes: number
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
|
||||
@@ -4220,23 +4220,43 @@
|
||||
data-testid="ollama-cloud-usage-global-enabled"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="ollamaCloudUsageForm.enabled" class="border-t border-gray-100 pt-4 dark:border-dark-700">
|
||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300" for="ollama-cloud-usage-interval">
|
||||
{{ t("admin.settings.ollamaCloudUsage.intervalMinutes") }}
|
||||
</label>
|
||||
<input
|
||||
id="ollama-cloud-usage-interval"
|
||||
v-model.number="ollamaCloudUsageForm.interval_minutes"
|
||||
type="number"
|
||||
min="15"
|
||||
max="1440"
|
||||
class="input w-32"
|
||||
data-testid="ollama-cloud-usage-global-interval"
|
||||
@keydown.enter.prevent="saveOllamaCloudUsageSettings"
|
||||
/>
|
||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t("admin.settings.ollamaCloudUsage.intervalHint") }}
|
||||
</p>
|
||||
<div v-if="ollamaCloudUsageForm.enabled" class="space-y-4 border-t border-gray-100 pt-4 dark:border-dark-700">
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300" for="ollama-cloud-usage-debounce">
|
||||
{{ t("admin.settings.ollamaCloudUsage.debounceMinutes") }}
|
||||
</label>
|
||||
<input
|
||||
id="ollama-cloud-usage-debounce"
|
||||
v-model.number="ollamaCloudUsageForm.debounce_minutes"
|
||||
type="number"
|
||||
min="1"
|
||||
max="60"
|
||||
class="input w-32"
|
||||
data-testid="ollama-cloud-usage-global-debounce"
|
||||
@keydown.enter.prevent="saveOllamaCloudUsageSettings"
|
||||
/>
|
||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t("admin.settings.ollamaCloudUsage.debounceHint") }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300" for="ollama-cloud-usage-interval">
|
||||
{{ t("admin.settings.ollamaCloudUsage.intervalMinutes") }}
|
||||
</label>
|
||||
<input
|
||||
id="ollama-cloud-usage-interval"
|
||||
v-model.number="ollamaCloudUsageForm.interval_minutes"
|
||||
type="number"
|
||||
min="15"
|
||||
max="1440"
|
||||
class="input w-32"
|
||||
data-testid="ollama-cloud-usage-global-interval"
|
||||
@keydown.enter.prevent="saveOllamaCloudUsageSettings"
|
||||
/>
|
||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t("admin.settings.ollamaCloudUsage.intervalHint") }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end border-t border-gray-100 pt-4 dark:border-dark-700">
|
||||
<button
|
||||
@@ -7934,6 +7954,7 @@ const ollamaCloudUsageSaving = ref(false);
|
||||
const ollamaCloudUsageForm = reactive({
|
||||
enabled: false,
|
||||
interval_minutes: 60,
|
||||
debounce_minutes: 1,
|
||||
});
|
||||
|
||||
// Overload Cooldown (529) 状态
|
||||
|
||||
@@ -50,6 +50,7 @@ const {
|
||||
getOllamaCloudUsageSettings: vi.fn().mockResolvedValue({
|
||||
enabled: false,
|
||||
interval_minutes: 60,
|
||||
debounce_minutes: 1,
|
||||
}),
|
||||
updateOllamaCloudUsageSettings: vi.fn().mockImplementation(async (payload) => payload),
|
||||
getGroups: vi.fn(),
|
||||
@@ -647,6 +648,7 @@ describe("admin SettingsView payment visible method controls", () => {
|
||||
getOllamaCloudUsageSettings.mockResolvedValue({
|
||||
enabled: false,
|
||||
interval_minutes: 60,
|
||||
debounce_minutes: 1,
|
||||
});
|
||||
updateOllamaCloudUsageSettings.mockImplementation(async (payload) => payload);
|
||||
getGroups.mockResolvedValue([]);
|
||||
@@ -1007,6 +1009,7 @@ describe("admin SettingsView payment visible method controls", () => {
|
||||
expect(card.find('[data-testid="ollama-cloud-usage-global-interval"]').exists()).toBe(false);
|
||||
|
||||
await card.get('[data-testid="ollama-cloud-usage-global-enabled"]').setValue(true);
|
||||
await card.get('[data-testid="ollama-cloud-usage-global-debounce"]').setValue(3);
|
||||
await card.get('[data-testid="ollama-cloud-usage-global-interval"]').setValue(90);
|
||||
await card.get('[data-testid="ollama-cloud-usage-global-save"]').trigger("click");
|
||||
await flushPromises();
|
||||
@@ -1014,6 +1017,7 @@ describe("admin SettingsView payment visible method controls", () => {
|
||||
expect(updateOllamaCloudUsageSettings).toHaveBeenCalledWith({
|
||||
enabled: true,
|
||||
interval_minutes: 90,
|
||||
debounce_minutes: 3,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user