Skip to main content

fur_cli/frs/
avatars.rs

1use serde_json::{json, Value};
2use std::fs;
3use std::path::Path;
4use rand::prelude::IndexedRandom;
5
6pub fn load_avatars() -> Value {
7    let path = Path::new(".fur/avatars.json");
8    if path.exists() {
9        let content = fs::read_to_string(path).unwrap_or_default();
10        serde_json::from_str(&content).unwrap_or_else(|_| json!({}))
11    } else {
12        json!({})
13    }
14}
15
16pub fn save_avatars(avatars: &Value) {
17    let path = Path::new(".fur/avatars.json");
18    if let Ok(serialized) = serde_json::to_string_pretty(avatars) {
19        let _ = fs::write(path, serialized);
20    }
21}
22
23pub fn resolve_avatar(avatars: &Value, key: &str) -> (String, String) {
24    // If key matches a known avatar name → return (name, emoji)
25    if let Some(emoji) = avatars.get(key).and_then(|v| v.as_str()) {
26        return (key.to_string(), emoji.to_string());
27    }
28
29    // If key looks like an emoji already → reverse-lookup name
30    if let Some((name, _)) = avatars.as_object()
31        .and_then(|map| map.iter().find(|(_, v)| v.as_str() == Some(key)))
32    {
33        return (name.clone(), key.to_string());
34    }
35
36    (key.to_string(), "🐾".to_string()) // fallback
37}
38
39
40/// Return true if the name clearly looks like a bot/LLM.
41fn is_bot_name(name: &str) -> bool {
42    let n = name.to_lowercase();
43
44    // lean markers (substring is fine for most)
45    const MARKERS: [&str; 8] = [
46        "gpt", "claude", "gemini", "bard", "grok", "bot", "ai", "llm",
47    ];
48
49    // fast path: any simple substring marker
50    if MARKERS.iter().any(|m| n.contains(m)) {
51        return true;
52    }
53
54    // safer whole-word match for "agent" (avoid hitting "management")
55    if n.split(|c: char| !c.is_alphanumeric())
56        .any(|tok| tok == "agent")
57    {
58        return true;
59    }
60
61    false
62}
63
64/// Emoji selection for new/unknown avatars:
65/// - Fox stays reserved for main via your `save_avatars_with_main`
66/// - Bots → 🤖
67pub fn get_random_emoji_for_name(name: &str) -> String {
68    if is_bot_name(name) {
69        return "🤖".to_string();
70    }
71    let pool = ["👤"];
72    pool.choose(&mut rand::rng()).unwrap_or(&"👔").to_string()
73}
74