subx_cli/services/ai/
cache.rs

1use crate::services::ai::{AnalysisRequest, MatchResult};
2use std::collections::HashMap;
3use std::collections::hash_map::DefaultHasher;
4use std::hash::{Hash, Hasher};
5use std::time::{Duration, SystemTime};
6use tokio::sync::RwLock;
7
8/// AI 分析結果快取
9pub struct AICache {
10    cache: RwLock<HashMap<String, CacheEntry>>,
11    ttl: Duration,
12}
13
14struct CacheEntry {
15    data: MatchResult,
16    created_at: SystemTime,
17}
18
19impl AICache {
20    /// 建立快取,ttl 為過期時間
21    pub fn new(ttl: Duration) -> Self {
22        Self {
23            cache: RwLock::new(HashMap::new()),
24            ttl,
25        }
26    }
27
28    /// 嘗試從快取讀取結果
29    pub async fn get(&self, key: &str) -> Option<MatchResult> {
30        let cache = self.cache.read().await;
31
32        if let Some(entry) = cache.get(key) {
33            if entry.created_at.elapsed().unwrap_or(Duration::MAX) < self.ttl {
34                return Some(entry.data.clone());
35            }
36        }
37        None
38    }
39
40    /// 將新結果寫入快取
41    pub async fn set(&self, key: String, data: MatchResult) {
42        let mut cache = self.cache.write().await;
43        cache.insert(
44            key,
45            CacheEntry {
46                data,
47                created_at: SystemTime::now(),
48            },
49        );
50    }
51
52    /// 根據請求產生快取鍵
53    pub fn generate_key(request: &AnalysisRequest) -> String {
54        let mut hasher = DefaultHasher::new();
55        request.video_files.hash(&mut hasher);
56        request.subtitle_files.hash(&mut hasher);
57        format!("{:x}", hasher.finish())
58    }
59}