mirror of
https://github.com/fancive/obsidian-parallel-reader.git
synced 2026-07-22 06:53:43 +00:00
feat: expose streaming timeout setting
Change-Id: Ide69c0f0fe208a557024f9f77d83c9d1215391cf
This commit is contained in:
parent
9098de6884
commit
174fa7295d
7 changed files with 67 additions and 27 deletions
54
main.js
54
main.js
File diff suppressed because one or more lines are too long
3
main.ts
3
main.ts
|
|
@ -50,6 +50,7 @@ import {
|
|||
getApiBaseUrl,
|
||||
modelForApi,
|
||||
normalizeSettings,
|
||||
normalizeStreamingTimeoutMs,
|
||||
pruneCacheEntries,
|
||||
} from './src/settings';
|
||||
import { ParallelReaderSettingTab } from './src/settings-tab';
|
||||
|
|
@ -788,6 +789,8 @@ export const __test = {
|
|||
modelForApi,
|
||||
normalizeBatchFolderInput,
|
||||
normalizeCardsPayload,
|
||||
normalizeSettings,
|
||||
normalizeStreamingTimeoutMs,
|
||||
nextCardIndex,
|
||||
pruneCacheEntries,
|
||||
recordBatchProcessed,
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ export const STRINGS: Record<string, Record<string, string>> = {
|
|||
clearAllCacheButton: '清除所有缓存',
|
||||
settingStreamingName: '流式输出',
|
||||
settingStreamingDesc: '启用后生成时实时显示 LLM 输出进度(仅 OpenAI Chat 和 Anthropic 格式支持)',
|
||||
settingStreamingTimeoutName: '流式超时 (ms)',
|
||||
settingStreamingTimeoutDesc: '单次流式请求的超时时间;低于 1000ms 或非法值会恢复默认值',
|
||||
cmdBatchGenerate: '批量生成对照笔记(当前文件夹)',
|
||||
batchSelectFolder: '请输入要批量处理的文件夹路径(留空为 Vault 根目录)',
|
||||
batchFolderPrompt: '文件夹路径',
|
||||
|
|
@ -308,6 +310,9 @@ export const STRINGS: Record<string, Record<string, string>> = {
|
|||
settingStreamingName: 'Streaming output',
|
||||
settingStreamingDesc:
|
||||
'Show real-time LLM output progress during generation (OpenAI Chat and Anthropic formats only)',
|
||||
settingStreamingTimeoutName: 'Streaming timeout (ms)',
|
||||
settingStreamingTimeoutDesc:
|
||||
'Timeout for one streaming request; invalid values or values below 1000ms use the default',
|
||||
cmdBatchGenerate: 'Batch generate parallel notes (current folder)',
|
||||
batchSelectFolder: 'Enter the folder path to batch-process (leave blank for Vault root)',
|
||||
batchFolderPrompt: 'Folder path',
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
DEFAULT_SETTINGS,
|
||||
getApiFormat,
|
||||
getApiPreset,
|
||||
normalizeStreamingTimeoutMs,
|
||||
PROMPT_LANGUAGES,
|
||||
UI_LANGUAGES,
|
||||
} from './settings';
|
||||
|
|
@ -218,6 +219,19 @@ export class ParallelReaderSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(tr('settingStreamingTimeoutName'))
|
||||
.setDesc(tr('settingStreamingTimeoutDesc'))
|
||||
.addText((t) =>
|
||||
t
|
||||
.setPlaceholder(String(DEFAULT_SETTINGS.streamingTimeoutMs))
|
||||
.setValue(String(this.plugin.settings.streamingTimeoutMs || DEFAULT_SETTINGS.streamingTimeoutMs))
|
||||
.onChange((v) => {
|
||||
this.plugin.settings.streamingTimeoutMs = normalizeStreamingTimeoutMs(v);
|
||||
this.plugin.saveSettingsDebounced();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export const MAX_DOC_CHARS = 100000;
|
|||
export const PROMPT_VERSION = 2;
|
||||
export const CACHE_SCHEMA_VERSION = 2;
|
||||
export const DEFAULT_MAX_CACHE_ENTRIES = 100;
|
||||
export const MIN_STREAMING_TIMEOUT_MS = 1000;
|
||||
export const PROMPT_LANGUAGES = {
|
||||
zh: '中文',
|
||||
en: 'English',
|
||||
|
|
@ -352,6 +353,7 @@ export function normalizeSettings(settings: PluginSettings): PluginSettings {
|
|||
settings.minCards = normalizeCardCount(settings.minCards, DEFAULT_SETTINGS.minCards);
|
||||
settings.maxCards = normalizeCardCount(settings.maxCards, DEFAULT_SETTINGS.maxCards);
|
||||
if (settings.maxCards < settings.minCards) settings.maxCards = settings.minCards;
|
||||
settings.streamingTimeoutMs = normalizeStreamingTimeoutMs(settings.streamingTimeoutMs);
|
||||
if (typeof settings.customSystemPrompt !== 'string') settings.customSystemPrompt = '';
|
||||
return settings;
|
||||
}
|
||||
|
|
@ -368,6 +370,12 @@ export function normalizeMaxCacheEntries(value: unknown): number {
|
|||
return n;
|
||||
}
|
||||
|
||||
export function normalizeStreamingTimeoutMs(value: unknown): number {
|
||||
const n = Math.floor(Number(value));
|
||||
if (!Number.isFinite(n) || n < MIN_STREAMING_TIMEOUT_MS) return DEFAULT_SETTINGS.streamingTimeoutMs;
|
||||
return n;
|
||||
}
|
||||
|
||||
function cacheEntryTime(entry: CacheEntry): number {
|
||||
const value = entry && (entry.lastAccessedAt || entry.generatedAt || entry.updatedAt);
|
||||
const timestamp = Date.parse(value || '');
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ assert.strictEqual(typeof t.shouldConfirmRegenerate, 'function');
|
|||
assert.strictEqual(typeof t.translate, 'function');
|
||||
assert.strictEqual(typeof t.updateCardAt, 'function');
|
||||
assert.strictEqual(typeof t.validateBatchFolderInput, 'function');
|
||||
assert.strictEqual(typeof t.normalizeSettings, 'function');
|
||||
assert.strictEqual(typeof t.normalizeStreamingTimeoutMs, 'function');
|
||||
|
||||
const baseSettings = {
|
||||
backend: 'api',
|
||||
|
|
|
|||
|
|
@ -351,6 +351,14 @@ const fp2 = t.generationFingerprint({ ...baseSettings });
|
|||
assert.strictEqual(fp1, fp2, 'same settings = same fingerprint');
|
||||
assert.notStrictEqual(fp1, t.generationFingerprint({ ...baseSettings, model: 'other' }), 'different model = different fp');
|
||||
assert.notStrictEqual(fp1, t.generationFingerprint({ ...baseSettings, apiMaxTokens: 8192 }), 'different tokens = different fp');
|
||||
assert.strictEqual(t.normalizeStreamingTimeoutMs('30000'), 30000, 'streaming timeout accepts numeric strings');
|
||||
assert.strictEqual(t.normalizeStreamingTimeoutMs(999), 120000, 'streaming timeout below minimum falls back');
|
||||
assert.strictEqual(t.normalizeStreamingTimeoutMs('bad'), 120000, 'streaming timeout rejects non-numeric values');
|
||||
assert.strictEqual(
|
||||
t.normalizeSettings({ ...baseSettings, streamingTimeoutMs: 500 }).streamingTimeoutMs,
|
||||
120000,
|
||||
'normalizeSettings protects invalid streaming timeout values',
|
||||
);
|
||||
|
||||
// cacheEntryMatches
|
||||
const crypto = require('crypto');
|
||||
|
|
|
|||
Loading…
Reference in a new issue