From 7f3961be3565ca3f4e6da6255d456188550cd0fb Mon Sep 17 00:00:00 2001
From: hangwin
This page tests the new model caching functionality.
+ + + + + + + + + + + + diff --git a/app/chrome-extension/utils/semantic-similarity-engine.ts b/app/chrome-extension/utils/semantic-similarity-engine.ts index 5e14e7a..49b8d13 100644 --- a/app/chrome-extension/utils/semantic-similarity-engine.ts +++ b/app/chrome-extension/utils/semantic-similarity-engine.ts @@ -5,6 +5,377 @@ import { SIMDMathEngine } from './simd-math-engine'; import { OffscreenManager } from './offscreen-manager'; import { OFFSCREEN_MESSAGE_TYPES } from '@/common/message-types'; +// Cache configuration for ONNX models +const CACHE_NAME = 'onnx-model-cache-v1'; // Change version to force cache update +const CACHE_EXPIRY_DAYS = 7; // Cache expiry in days +const MAX_CACHE_SIZE_MB = 500; // Maximum cache size in MB + +/** + * Cache metadata interface + */ +interface CacheMetadata { + timestamp: number; + modelUrl: string; + size: number; + version: string; +} + +/** + * Get cache metadata key for a model URL + */ +function getCacheMetadataKey(modelUrl: string): string { + return `metadata:${modelUrl}`; +} + +/** + * Check if cache entry is expired + */ +function isCacheExpired(metadata: CacheMetadata): boolean { + const now = Date.now(); + const expiryTime = metadata.timestamp + CACHE_EXPIRY_DAYS * 24 * 60 * 60 * 1000; + return now > expiryTime; +} + +/** + * Get total cache size in bytes + */ +async function getCacheTotalSize(): PromiseThis page tests the new model caching functionality.
- - - - - - - - - - - - diff --git a/app/chrome-extension/utils/model-cache-manager.ts b/app/chrome-extension/utils/model-cache-manager.ts new file mode 100644 index 0000000..17ce529 --- /dev/null +++ b/app/chrome-extension/utils/model-cache-manager.ts @@ -0,0 +1,303 @@ +/** + * Model Cache Manager + */ + +const CACHE_NAME = 'onnx-model-cache-v1'; +const CACHE_EXPIRY_DAYS = 14; +const MAX_CACHE_SIZE_MB = 500; + +export interface CacheMetadata { + timestamp: number; + modelUrl: string; + size: number; + version: string; +} + +export interface CacheEntry { + url: string; + size: number; + sizeMB: number; + timestamp: number; + age: string; + expired: boolean; +} + +export interface CacheStats { + totalSize: number; + totalSizeMB: number; + entryCount: number; + entries: CacheEntry[]; +} + +interface CacheEntryDetails { + url: string; + timestamp: number; + size: number; +} + +export class ModelCacheManager { + private static instance: ModelCacheManager | null = null; + + public static getInstance(): ModelCacheManager { + if (!ModelCacheManager.instance) { + ModelCacheManager.instance = new ModelCacheManager(); + } + return ModelCacheManager.instance; + } + + private constructor() {} + + private getCacheMetadataKey(modelUrl: string): string { + const encodedUrl = encodeURIComponent(modelUrl); + return `https://cache-metadata.local/${encodedUrl}`; + } + + private isCacheExpired(metadata: CacheMetadata): boolean { + const now = Date.now(); + const expiryTime = metadata.timestamp + CACHE_EXPIRY_DAYS * 24 * 60 * 60 * 1000; + return now > expiryTime; + } + + private isMetadataUrl(url: string): boolean { + return url.startsWith('https://cache-metadata.local/'); + } + + private async collectCacheEntries(): Promise<{ + entries: CacheEntryDetails[]; + totalSize: number; + entryCount: number; + }> { + const cache = await caches.open(CACHE_NAME); + const keys = await cache.keys(); + const entries: CacheEntryDetails[] = []; + let totalSize = 0; + let entryCount = 0; + + for (const request of keys) { + if (this.isMetadataUrl(request.url)) continue; + + const response = await cache.match(request); + if (response) { + const blob = await response.blob(); + const size = blob.size; + totalSize += size; + entryCount++; + + const metadataResponse = await cache.match(this.getCacheMetadataKey(request.url)); + let timestamp = 0; + + if (metadataResponse) { + try { + const metadata: CacheMetadata = await metadataResponse.json(); + timestamp = metadata.timestamp; + } catch (error) { + console.warn('Failed to parse cache metadata:', error); + } + } + + entries.push({ + url: request.url, + timestamp, + size, + }); + } + } + + return { entries, totalSize, entryCount }; + } + + public async cleanupCacheOnDemand(newDataSize: number = 0): Promise缓存大小
+ +{{ cacheStats?.totalSizeMB || 0 }} MB
+缓存条目
+ +{{ cacheStats?.entryCount || 0 }}
+暂无缓存数据
+正在加载缓存信息...
+PVYCe_nT7l^l3Bu
zv?aAqpSDCNe>*t_^r_o1_#I-XJUx#$M6*EE>XYPndNt83zSx)(eEl0jGZ?~6{3S6E
z@=ODtI}Cyo6U}xn_M+egjfr}t_BJcL`j>Ve4y@k8Up;ZFJ#kfD@E_`lTjjc1n8#P>
z&3N73xnDh@zIsBrdis_RG}AUM#a9A$5LelR9Mt?
zGc^2GZqkWGzJ?@mvK2Egx|?PPBG{PvPd3j?W
ziZth3OwgR3-D#d@xi!*U0cTcwiudSN-&i&YQy!gjJ3mZQD6t+TyY`*1JnPWPh4@kZLoHpQ>)Xl_NT
zb{osj1Re*=j~^3_JGN@jX0vjwbFdrQxp&*rDi#FtrBd(67{D<<)VjI+H|WX?XTj0#
znqGmFLYtQBWnXjkRT|Gb!%MQYe>vI$5a|5;mQj4K-@ba;IVQ4}GKZM?!<%={K4QjD
zWcXC;_1llTnBj|z05fEIAks&&!f*$3Mj~fh)ZiK0B4bBn1U_c$h>XV~V`qdJk445V
zW*mO}@cQkKn6oQ#_Aux9yLWFeeNRqstDGV4e^}0*rvLKY&(GhyqCB|(f5UPG`0$2u
z4Tgct<0Bl(br{k@ym
a=dK3rbCTEI0_$SMcQz8Z#U
z-(QE4a?Q(Mucj<6q*7gZbYOL!6t%k4f1K~81z5V8SW
DKT
z_t@uf%Z+D$1D33+@(O%=6&-vx|3?q%q}psFkri{B?HI
y3UtNCv6eDBfHA{@d9@1+SQEe|wE|!**%`9b3=BJU1aA
zi3>MJ`Q#+buab$-;Y0lhvA7$arQWhu%a3m0!zc%Jt-poIbcWoH+JG!84?(O=BHX2B
z1Kwj*{G{}A6-TovYSg6R^e2XDqm+c(;|$&<$(R4mjgec_JnQDaG