Spaces:
Running
Running
| (() => { | |
| const MODEL_CONFIG = window.AIFORECAST_MODEL_CONFIG || null; | |
| const ANALYSIS_CACHE_VERSION = window.AIFORECAST_ANALYSIS_CACHE_VERSION || 'chronos2-v1'; | |
| window.AIFORECAST_ANALYSIS_CACHE_VERSION = ANALYSIS_CACHE_VERSION; | |
| const AI_CONTEXT_POLICY = window.AIFORECAST_FORECAST_CONTEXT_CONFIG || window.AI_CONTEXT_POLICY || Object.freeze({ | |
| default: 384, | |
| allowed: [128, 256, 384, 512], | |
| scope: "workspace", | |
| }); | |
| function normalizeModels(selection = null) { | |
| if (MODEL_CONFIG && typeof MODEL_CONFIG.normalizeSelection === 'function') { | |
| return MODEL_CONFIG.normalizeSelection(selection); | |
| } | |
| return { | |
| kronos: Boolean(selection?.kronos), | |
| timesfm: Boolean(selection?.timesfm), | |
| chronos: Boolean(selection?.chronos), | |
| }; | |
| } | |
| function getModelSignature(selection = null) { | |
| if (MODEL_CONFIG && typeof MODEL_CONFIG.signature === 'function') { | |
| return MODEL_CONFIG.signature(selection); | |
| } | |
| const normalized = normalizeModels(selection); | |
| return Object.entries(normalized) | |
| .filter(([, enabled]) => enabled) | |
| .map(([modelKey]) => modelKey) | |
| .join('+') || 'none'; | |
| } | |
| function normalizeContextLength(contextLength, fallback = AI_CONTEXT_POLICY.default || 384) { | |
| const numericValue = Number(contextLength); | |
| if (Number.isFinite(numericValue) && AI_CONTEXT_POLICY.allowed.includes(numericValue)) { | |
| return numericValue; | |
| } | |
| return fallback; | |
| } | |
| function normalizeHorizon(value) { | |
| const numericValue = Number(value); | |
| return Number.isFinite(numericValue) && numericValue > 0 | |
| ? numericValue | |
| : null; | |
| } | |
| function buildAnalysisRequestContext(requestMeta = {}, pane = null, payload = null) { | |
| const workspaceContextLength = typeof window.getWorkspaceForecastContextLength === 'function' | |
| ? window.getWorkspaceForecastContextLength() | |
| : (window.Workspace?.forecastSettings?.contextLength ?? AI_CONTEXT_POLICY.default); | |
| const models = normalizeModels( | |
| requestMeta.models | |
| || payload?.model_selection?.requested | |
| || pane?.aiModels | |
| || null, | |
| ); | |
| return { | |
| symbol: requestMeta.symbol ?? payload?.symbol ?? pane?.symbol ?? null, | |
| interval: requestMeta.interval ?? payload?.interval ?? pane?.interval ?? null, | |
| horizon: normalizeHorizon(requestMeta.horizon ?? payload?.horizon ?? pane?.horizon), | |
| models, | |
| modelSignature: requestMeta.modelSignature ?? getModelSignature(models), | |
| cacheVersion: ANALYSIS_CACHE_VERSION, | |
| contextLength: normalizeContextLength( | |
| requestMeta.contextLength | |
| ?? payload?.model_selection?.shared_context_length | |
| ?? workspaceContextLength, | |
| AI_CONTEXT_POLICY.default || 384, | |
| ), | |
| }; | |
| } | |
| function contextsMatch(left, right, options = {}) { | |
| if (!left || !right) { | |
| return false; | |
| } | |
| const requireHorizon = options.requireHorizon !== false; | |
| return ( | |
| left.symbol === right.symbol | |
| && left.interval === right.interval | |
| && left.modelSignature === right.modelSignature | |
| && left.cacheVersion === right.cacheVersion | |
| && left.contextLength === right.contextLength | |
| && ( | |
| !requireHorizon | |
| || left.horizon === right.horizon | |
| ) | |
| ); | |
| } | |
| function buildPaneAnalysisCacheKey(requestMeta = {}, pane = null, payload = null) { | |
| const context = buildAnalysisRequestContext(requestMeta, pane, payload); | |
| return [ | |
| context.symbol || 'unknown', | |
| context.interval || 'unknown', | |
| `h=${context.horizon ?? 'na'}`, | |
| `m=${context.modelSignature}`, | |
| `ctx=${context.contextLength}`, | |
| `rv=${ANALYSIS_CACHE_VERSION}`, | |
| ].join('|'); | |
| } | |
| function createPaneAnalysisCacheEntry(payload, requestMeta = {}, pane = null) { | |
| return { | |
| payload, | |
| ...buildAnalysisRequestContext(requestMeta, pane, payload), | |
| }; | |
| } | |
| function isPayloadCommitReady(payload, pane = null) { | |
| if (!payload?.analysis) { | |
| return false; | |
| } | |
| if (pane?.lastAnalysis?.payload === payload) { | |
| if (pane.lastAnalysis.commitReady === true) { | |
| return true; | |
| } | |
| if (pane.lastAnalysis.complete === true) { | |
| return true; | |
| } | |
| } | |
| const aggregation = payload?.analysis?.presentation?.aggregation || {}; | |
| const aiModels = payload?.analysis?.ai_models || {}; | |
| if (aggregation.commit_ready === true || aiModels.commit_ready === true) { | |
| return true; | |
| } | |
| if (aggregation.complete === true || aiModels.complete === true) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| function matchesPanePayloadCurrentContext( | |
| pane, | |
| payload, | |
| options = {}, | |
| ) { | |
| if (!pane || !payload?.analysis) { | |
| return false; | |
| } | |
| const currentContext = buildAnalysisRequestContext({}, pane); | |
| const requireComplete = options.requireComplete === true; | |
| const allowTechnicalFallback = options.allowTechnicalFallback === true; | |
| if (pane.lastAnalysis?.payload === payload) { | |
| const storedContext = buildAnalysisRequestContext(pane.lastAnalysis, pane, payload); | |
| return ( | |
| contextsMatch(storedContext, currentContext) | |
| && (!requireComplete || isPayloadCommitReady(payload, pane)) | |
| ); | |
| } | |
| if (pane.lastTechnicalAnalysis?.payload === payload) { | |
| return ( | |
| allowTechnicalFallback | |
| && pane.lastTechnicalAnalysis.symbol === currentContext.symbol | |
| && pane.lastTechnicalAnalysis.interval === currentContext.interval | |
| ); | |
| } | |
| const payloadContext = buildAnalysisRequestContext({}, pane, payload); | |
| return ( | |
| contextsMatch(payloadContext, currentContext) | |
| && (!requireComplete || isPayloadCommitReady(payload, pane)) | |
| ); | |
| } | |
| function resolvePaneDisplayPayload(pane, preferredPayload = null) { | |
| const currentContext = buildAnalysisRequestContext({}, pane); | |
| const displaySnapshotPayload = pane?.aiSession?.displaySnapshot?.payload || null; | |
| if (matchesPanePayloadCurrentContext(pane, displaySnapshotPayload, { requireComplete: true })) { | |
| return displaySnapshotPayload; | |
| } | |
| if (matchesPanePayloadCurrentContext(pane, preferredPayload)) { | |
| return preferredPayload; | |
| } | |
| if (matchesPanePayloadCurrentContext(pane, pane?.lastAnalysis?.payload)) { | |
| return pane.lastAnalysis.payload; | |
| } | |
| const cachedPayload = getCachedPaneAnalysisPayload(pane, currentContext); | |
| if (matchesPanePayloadCurrentContext(pane, cachedPayload, { requireComplete: true })) { | |
| return cachedPayload; | |
| } | |
| if (matchesPanePayloadCurrentContext(pane, pane?.lastTechnicalAnalysis?.payload, { allowTechnicalFallback: true })) { | |
| return pane.lastTechnicalAnalysis.payload; | |
| } | |
| return null; | |
| } | |
| function getCachedPaneAnalysisPayload(pane, requestMeta = {}) { | |
| const cacheKey = buildPaneAnalysisCacheKey(requestMeta, pane); | |
| const cacheEntry = pane?.analysisPayloadCache?.[cacheKey]; | |
| if (!cacheEntry) { | |
| return null; | |
| } | |
| const entry = cacheEntry?.payload | |
| ? cacheEntry | |
| : createPaneAnalysisCacheEntry(cacheEntry, requestMeta, pane); | |
| const requestedContext = buildAnalysisRequestContext(requestMeta, pane); | |
| const cachedContext = buildAnalysisRequestContext(entry, pane, entry.payload); | |
| return contextsMatch(cachedContext, requestedContext) | |
| ? entry.payload | |
| : null; | |
| } | |
| window.AIForecastAnalysisRuntime = Object.freeze({ | |
| ANALYSIS_CACHE_VERSION, | |
| normalizeModels, | |
| getModelSignature, | |
| normalizeContextLength, | |
| buildAnalysisRequestContext, | |
| buildPaneAnalysisCacheKey, | |
| createPaneAnalysisCacheEntry, | |
| getCachedPaneAnalysisPayload, | |
| matchesPanePayloadCurrentContext, | |
| resolvePaneDisplayPayload, | |
| }); | |
| })(); | |