1
0
Files
gpt/src/core/writer.rs
2026-03-03 16:02:31 +09:00

87 lines
2.8 KiB
Rust

use anyhow::{Context, Result};
use chrono::Utc;
use serde_json::{json, Value};
use std::fs;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
use crate::core::config::{self, COLLECTION_MEMORY};
static TID_COUNTER: AtomicU64 = AtomicU64::new(0);
fn generate_tid() -> String {
const CHARSET: &[u8] = b"234567abcdefghijklmnopqrstuvwxyz";
let micros = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_micros() as u64;
let clock_id = TID_COUNTER.fetch_add(1, Ordering::Relaxed) & 0x3FF;
let v = ((micros << 10) | clock_id) & 0x7FFFFFFFFFFFFFFF;
let mut tid = String::with_capacity(13);
for i in (0..13).rev() {
let idx = ((v >> (i * 5)) & 0x1f) as usize;
tid.push(CHARSET[idx] as char);
}
tid
}
fn build_memory_record(did: &str, tid: &str, text: &str) -> Value {
let now = Utc::now().format("%Y-%m-%dT%H:%M:%SZ").to_string();
json!({
"uri": format!("at://{}/{}/{}", did, COLLECTION_MEMORY, tid),
"value": {
"$type": COLLECTION_MEMORY,
"did": did,
"content": {
"$type": format!("{}#markdown", COLLECTION_MEMORY),
"text": text
},
"createdAt": now
}
})
}
/// Save a single memory element as a new TID file
pub fn save_memory(content: &str) -> Result<()> {
let cfg = config::load();
let tid = generate_tid();
let record = build_memory_record(cfg.did(), &tid, content);
let dir = config::collection_dir(&cfg, COLLECTION_MEMORY);
fs::create_dir_all(&dir)
.with_context(|| format!("Failed to create {}", dir.display()))?;
let path = dir.join(format!("{}.json", tid));
let json_str = serde_json::to_string_pretty(&record)?;
fs::write(&path, json_str)
.with_context(|| format!("Failed to write {}", path.display()))
}
/// Delete all memory files, then write new ones from the given items
pub fn compress_memory(items: &[String]) -> Result<()> {
let cfg = config::load();
let dir = config::collection_dir(&cfg, COLLECTION_MEMORY);
// delete all existing memory files
if let Ok(entries) = fs::read_dir(&dir) {
for entry in entries.flatten() {
if entry.path().extension().is_some_and(|ext| ext == "json") {
let _ = fs::remove_file(entry.path());
}
}
}
fs::create_dir_all(&dir)
.with_context(|| format!("Failed to create {}", dir.display()))?;
for item in items {
let tid = generate_tid();
let record = build_memory_record(cfg.did(), &tid, item);
let path = dir.join(format!("{}.json", tid));
let json_str = serde_json::to_string_pretty(&record)?;
fs::write(&path, json_str)
.with_context(|| format!("Failed to write {}", path.display()))?;
}
Ok(())
}