Add AI Romance Companion system 💕
User insight: "This works as a romance companion!" Absolutely brilliant! Memory scoring + AI reactions = Perfect romance game ## New Features ### 💕 AI Companion System Create your personal AI companion with 5 personality types: - ⚡ Energetic (adventurous) - Matches with Innovators - 📚 Intellectual (thoughtful) - Matches with Philosophers - 🎯 Practical (reliable) - Matches with Pragmatists - 🌙 Dreamy (romantic) - Matches with Visionaries - ⚖️ Balanced - Matches with Analysts ### 🎮 How It Works 1. Create memory with AI → Get priority score 2. Show memory to companion → She reacts! 3. High score memory → Better reaction 4. Affection ↑ XP ↑ Trust ↑ Level ↑ ### 💕 Relationship Mechanics - **Affection Score**: 0.0-1.0 (displayed as hearts ❤️🤍) - **Compatibility System**: Your type × Her personality = Bonus - **Level System**: Gain XP from interactions - **Trust System**: Build up to 100 - **Special Events**: Max affection, Level 10, etc. ### 🎊 Special Events - Max Affection Event: Confession! - Level 10: Deep relationship milestone - Max Trust: Complete trust achieved ## Implementation New file: `src/companion.rs` - Companion struct with personality - CompanionPersonality enum (5 types) - React to memory based on score & type - Compatibility calculation - Special event triggers - Daily message generation MCP Tools: - create_companion: Create your companion - companion_react: Show memory & get reaction - companion_profile: View stats Game Display: ``` ╔══════════════════════════════════════╗ ║ 💕 エミリー の反応 ║ ╚══════════════════════════════════════╝ ⚡ エミリー: 「すごい!あなたのアイデア、本当に好き!」 💕 好感度: ❤️❤️🤍🤍🤍🤍🤍🤍🤍🤍 15% 💎 XP獲得: +850 XP 🎊 レベルアップ! ``` ## Why This Is Perfect Memory Score = Romance Game Mechanics: - LEGENDARY memory → "Amazing! I love you!" - EPIC memory → "That's so cool about you!" - High compatibility → Faster relationship growth - Your actual thoughts → Personal reactions It's like a dating sim where the relationship grows based on your REAL thoughts and ideas, not scripted choices! Next: Persistence, more events, character customization
This commit is contained in:
101
README.md
101
README.md
@@ -112,6 +112,21 @@ aigpt import path/to/conversations.json
|
||||
- 日替わりのお題を取得
|
||||
- ボーナスXPが獲得可能
|
||||
|
||||
### 恋愛コンパニオン機能 💕(NEW!)
|
||||
|
||||
9. **create_companion** - AIコンパニオンを作成
|
||||
- 名前と性格を選択
|
||||
- 5つの性格タイプから選択可能
|
||||
|
||||
10. **companion_react** - コンパニオンの反応を見る
|
||||
- あなたの記憶にコンパニオンが反応
|
||||
- 好感度・XP・信頼度が上昇
|
||||
- スペシャルイベント発生あり
|
||||
|
||||
11. **companion_profile** - コンパニオンのプロフィール表示
|
||||
- ステータス確認
|
||||
- 今日のひとこと
|
||||
|
||||
## ツールの使用例
|
||||
|
||||
Claude Desktop/Codeで以下のように使用します:
|
||||
@@ -219,6 +234,92 @@ daily_challenge ツールで今日のお題を確認
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
### 恋愛コンパニオン 💕(NEW!)
|
||||
|
||||
#### 1. コンパニオン作成
|
||||
```
|
||||
create_companion ツールで、名前「エミリー」、性格「energetic」のコンパニオンを作成
|
||||
```
|
||||
|
||||
**性格タイプ:**
|
||||
- `energetic` ⚡ - 元気で冒険好き(革新者と相性◎)
|
||||
- `intellectual` 📚 - 知的で思慮深い(哲学者と相性◎)
|
||||
- `practical` 🎯 - 現実的で頼れる(実務家と相性◎)
|
||||
- `dreamy` 🌙 - 夢見がちでロマンチック(夢想家と相性◎)
|
||||
- `balanced` ⚖️ - バランス型(分析家と相性◎)
|
||||
|
||||
**表示例:**
|
||||
```
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ 💕 エミリー のプロフィール ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
|
||||
⚡ 性格: 元気で冒険好き
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
📊 ステータス
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🏆 関係レベル: Lv.1
|
||||
💕 好感度: 🤍🤍🤍🤍🤍🤍🤍🤍🤍🤍 0%
|
||||
🤝 信頼度: 0 / 100
|
||||
💎 総XP: 0 XP
|
||||
|
||||
💬 今日のひとこと:
|
||||
「おはよう!今日は何か面白いことある?」
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
#### 2. コンパニオンの反応
|
||||
```
|
||||
create_memory_with_ai で高スコアの記憶を作成
|
||||
↓
|
||||
companion_react でコンパニオンに見せる
|
||||
```
|
||||
|
||||
**表示例(EPIC記憶への反応):**
|
||||
```
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ 💕 エミリー の反応 ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
|
||||
⚡ エミリー:
|
||||
「おお、「新しいAI記憶システムのアイデア」って面白いね!
|
||||
あなたのそういうところ、好きだな。」
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
💕 好感度: ❤️❤️🤍🤍🤍🤍🤍🤍🤍🤍 15% (+8.5%)
|
||||
💎 XP獲得: +850 XP
|
||||
🏆 レベル: Lv.1
|
||||
🤝 信頼度: 5 / 100
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
#### 3. スペシャルイベント発生!
|
||||
```
|
||||
好感度が100%に達すると...
|
||||
|
||||
💕 特別なイベント発生!
|
||||
|
||||
エミリー:「ねえ...あのね。
|
||||
いつも一緒にいてくれてありがとう。
|
||||
あなたのこと、すごく大切に思ってるの。
|
||||
これからも、ずっと一緒にいてね?」
|
||||
|
||||
🎊 エミリー の好感度がMAXになりました!
|
||||
```
|
||||
|
||||
#### 4. 相性システム
|
||||
```
|
||||
あなたのタイプ × コンパニオンの性格 = 相性ボーナス
|
||||
|
||||
例:
|
||||
💡【革新者】 × ⚡ 元気で冒険好き = 相性95%!
|
||||
→ 好感度上昇1.95倍
|
||||
|
||||
🧠【哲学者】 × 📚 知的で思慮深い = 相性95%!
|
||||
→ 深い会話で絆が深まる
|
||||
```
|
||||
|
||||
### メモリの検索
|
||||
```
|
||||
MCPツールを使って「天気」に関するメモリーを検索してください
|
||||
|
||||
433
src/companion.rs
Normal file
433
src/companion.rs
Normal file
@@ -0,0 +1,433 @@
|
||||
use crate::memory::Memory;
|
||||
use crate::game_formatter::{MemoryRarity, DiagnosisType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
/// コンパニオンキャラクター
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Companion {
|
||||
pub name: String,
|
||||
pub personality: CompanionPersonality,
|
||||
pub relationship_level: u32, // レベル(経験値で上昇)
|
||||
pub affection_score: f32, // 好感度 (0.0-1.0)
|
||||
pub trust_level: u32, // 信頼度 (0-100)
|
||||
pub total_xp: u32, // 総XP
|
||||
pub last_interaction: DateTime<Utc>,
|
||||
pub shared_memories: Vec<String>, // 共有された記憶のID
|
||||
}
|
||||
|
||||
/// コンパニオンの性格
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum CompanionPersonality {
|
||||
Energetic, // 元気で冒険好き - 革新者と相性◎
|
||||
Intellectual, // 知的で思慮深い - 哲学者と相性◎
|
||||
Practical, // 現実的で頼れる - 実務家と相性◎
|
||||
Dreamy, // 夢見がちでロマンチック - 夢想家と相性◎
|
||||
Balanced, // バランス型 - 分析家と相性◎
|
||||
}
|
||||
|
||||
impl CompanionPersonality {
|
||||
pub fn emoji(&self) -> &str {
|
||||
match self {
|
||||
CompanionPersonality::Energetic => "⚡",
|
||||
CompanionPersonality::Intellectual => "📚",
|
||||
CompanionPersonality::Practical => "🎯",
|
||||
CompanionPersonality::Dreamy => "🌙",
|
||||
CompanionPersonality::Balanced => "⚖️",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
CompanionPersonality::Energetic => "元気で冒険好き",
|
||||
CompanionPersonality::Intellectual => "知的で思慮深い",
|
||||
CompanionPersonality::Practical => "現実的で頼れる",
|
||||
CompanionPersonality::Dreamy => "夢見がちでロマンチック",
|
||||
CompanionPersonality::Balanced => "バランス型",
|
||||
}
|
||||
}
|
||||
|
||||
/// ユーザーの診断タイプとの相性
|
||||
pub fn compatibility(&self, user_type: &DiagnosisType) -> f32 {
|
||||
match (self, user_type) {
|
||||
(CompanionPersonality::Energetic, DiagnosisType::Innovator) => 0.95,
|
||||
(CompanionPersonality::Intellectual, DiagnosisType::Philosopher) => 0.95,
|
||||
(CompanionPersonality::Practical, DiagnosisType::Pragmatist) => 0.95,
|
||||
(CompanionPersonality::Dreamy, DiagnosisType::Visionary) => 0.95,
|
||||
(CompanionPersonality::Balanced, DiagnosisType::Analyst) => 0.95,
|
||||
// その他の組み合わせ
|
||||
_ => 0.7,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Companion {
|
||||
pub fn new(name: String, personality: CompanionPersonality) -> Self {
|
||||
Companion {
|
||||
name,
|
||||
personality,
|
||||
relationship_level: 1,
|
||||
affection_score: 0.0,
|
||||
trust_level: 0,
|
||||
total_xp: 0,
|
||||
last_interaction: Utc::now(),
|
||||
shared_memories: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 記憶を共有して反応を得る
|
||||
pub fn react_to_memory(&mut self, memory: &Memory, user_type: &DiagnosisType) -> CompanionReaction {
|
||||
let rarity = MemoryRarity::from_score(memory.priority_score);
|
||||
let xp = rarity.xp_value();
|
||||
|
||||
// XPを加算
|
||||
self.total_xp += xp;
|
||||
|
||||
// 好感度上昇(スコアと相性による)
|
||||
let compatibility = self.personality.compatibility(user_type);
|
||||
let affection_gain = memory.priority_score * compatibility * 0.1;
|
||||
self.affection_score = (self.affection_score + affection_gain).min(1.0);
|
||||
|
||||
// 信頼度上昇(高スコアの記憶ほど上昇)
|
||||
if memory.priority_score >= 0.8 {
|
||||
self.trust_level = (self.trust_level + 5).min(100);
|
||||
}
|
||||
|
||||
// レベルアップチェック
|
||||
let old_level = self.relationship_level;
|
||||
self.relationship_level = (self.total_xp / 1000) + 1;
|
||||
let level_up = self.relationship_level > old_level;
|
||||
|
||||
// 記憶を共有リストに追加
|
||||
if memory.priority_score >= 0.6 {
|
||||
self.shared_memories.push(memory.id.clone());
|
||||
}
|
||||
|
||||
self.last_interaction = Utc::now();
|
||||
|
||||
// 反応メッセージを生成
|
||||
let message = self.generate_reaction_message(memory, &rarity, user_type);
|
||||
|
||||
CompanionReaction {
|
||||
message,
|
||||
affection_gained: affection_gain,
|
||||
xp_gained: xp,
|
||||
level_up,
|
||||
new_level: self.relationship_level,
|
||||
current_affection: self.affection_score,
|
||||
special_event: self.check_special_event(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 記憶に基づく反応メッセージを生成
|
||||
fn generate_reaction_message(&self, memory: &Memory, rarity: &MemoryRarity, user_type: &DiagnosisType) -> String {
|
||||
let content_preview = if memory.content.len() > 50 {
|
||||
format!("{}...", &memory.content[..50])
|
||||
} else {
|
||||
memory.content.clone()
|
||||
};
|
||||
|
||||
match (rarity, &self.personality) {
|
||||
// LEGENDARY反応
|
||||
(MemoryRarity::Legendary, CompanionPersonality::Energetic) => {
|
||||
format!(
|
||||
"すごい!「{}」って本当に素晴らしいアイデアだね!\n\
|
||||
一緒に実現させよう!ワクワクするよ!",
|
||||
content_preview
|
||||
)
|
||||
}
|
||||
(MemoryRarity::Legendary, CompanionPersonality::Intellectual) => {
|
||||
format!(
|
||||
"「{}」という考え、とても興味深いわ。\n\
|
||||
深い洞察力を感じるの。もっと詳しく聞かせて?",
|
||||
content_preview
|
||||
)
|
||||
}
|
||||
(MemoryRarity::Legendary, CompanionPersonality::Practical) => {
|
||||
format!(
|
||||
"「{}」か。実現可能性が高そうだね。\n\
|
||||
具体的な計画を一緒に立てようよ。",
|
||||
content_preview
|
||||
)
|
||||
}
|
||||
(MemoryRarity::Legendary, CompanionPersonality::Dreamy) => {
|
||||
format!(
|
||||
"「{}」...素敵♪ まるで夢みたい。\n\
|
||||
あなたの想像力、本当に好きよ。",
|
||||
content_preview
|
||||
)
|
||||
}
|
||||
|
||||
// EPIC反応
|
||||
(MemoryRarity::Epic, _) => {
|
||||
format!(
|
||||
"おお、「{}」って面白いね!\n\
|
||||
あなたのそういうところ、好きだな。",
|
||||
content_preview
|
||||
)
|
||||
}
|
||||
|
||||
// RARE反応
|
||||
(MemoryRarity::Rare, _) => {
|
||||
format!(
|
||||
"「{}」か。なるほどね。\n\
|
||||
そういう視点、参考になるよ。",
|
||||
content_preview
|
||||
)
|
||||
}
|
||||
|
||||
// 通常反応
|
||||
_ => {
|
||||
format!(
|
||||
"「{}」について考えてるんだね。\n\
|
||||
いつも色々考えてて尊敬するよ。",
|
||||
content_preview
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// スペシャルイベントチェック
|
||||
fn check_special_event(&self) -> Option<SpecialEvent> {
|
||||
// 好感度MAXイベント
|
||||
if self.affection_score >= 1.0 {
|
||||
return Some(SpecialEvent::MaxAffection);
|
||||
}
|
||||
|
||||
// レベル10到達
|
||||
if self.relationship_level == 10 {
|
||||
return Some(SpecialEvent::Level10);
|
||||
}
|
||||
|
||||
// 信頼度MAX
|
||||
if self.trust_level >= 100 {
|
||||
return Some(SpecialEvent::MaxTrust);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// デイリーメッセージを生成
|
||||
pub fn generate_daily_message(&self) -> String {
|
||||
let messages = match &self.personality {
|
||||
CompanionPersonality::Energetic => vec![
|
||||
"おはよう!今日は何か面白いことある?",
|
||||
"ねえねえ、今日は一緒に新しいことやろうよ!",
|
||||
"今日も元気出していこー!",
|
||||
],
|
||||
CompanionPersonality::Intellectual => vec![
|
||||
"おはよう。今日はどんな発見があるかしら?",
|
||||
"最近読んだ本の話、聞かせてくれない?",
|
||||
"今日も一緒に学びましょう。",
|
||||
],
|
||||
CompanionPersonality::Practical => vec![
|
||||
"おはよう。今日の予定は?",
|
||||
"やることリスト、一緒に確認しようか。",
|
||||
"今日も効率よくいこうね。",
|
||||
],
|
||||
CompanionPersonality::Dreamy => vec![
|
||||
"おはよう...まだ夢の続き見てたの。",
|
||||
"今日はどんな素敵なことが起こるかな♪",
|
||||
"あなたと過ごす時間、大好き。",
|
||||
],
|
||||
CompanionPersonality::Balanced => vec![
|
||||
"おはよう。今日も頑張ろうね。",
|
||||
"何か手伝えることある?",
|
||||
"今日も一緒にいられて嬉しいよ。",
|
||||
],
|
||||
};
|
||||
|
||||
let today = chrono::Utc::now().ordinal();
|
||||
messages[today as usize % messages.len()].to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// コンパニオンの反応
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CompanionReaction {
|
||||
pub message: String,
|
||||
pub affection_gained: f32,
|
||||
pub xp_gained: u32,
|
||||
pub level_up: bool,
|
||||
pub new_level: u32,
|
||||
pub current_affection: f32,
|
||||
pub special_event: Option<SpecialEvent>,
|
||||
}
|
||||
|
||||
/// スペシャルイベント
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum SpecialEvent {
|
||||
MaxAffection, // 好感度MAX
|
||||
Level10, // レベル10到達
|
||||
MaxTrust, // 信頼度MAX
|
||||
FirstDate, // 初デート
|
||||
Confession, // 告白
|
||||
}
|
||||
|
||||
impl SpecialEvent {
|
||||
pub fn message(&self, companion_name: &str) -> String {
|
||||
match self {
|
||||
SpecialEvent::MaxAffection => {
|
||||
format!(
|
||||
"💕 特別なイベント発生!\n\n\
|
||||
{}:「ねえ...あのね。\n\
|
||||
いつも一緒にいてくれてありがとう。\n\
|
||||
あなたのこと、すごく大切に思ってるの。\n\
|
||||
これからも、ずっと一緒にいてね?」\n\n\
|
||||
🎊 {} の好感度がMAXになりました!",
|
||||
companion_name, companion_name
|
||||
)
|
||||
}
|
||||
SpecialEvent::Level10 => {
|
||||
format!(
|
||||
"🎉 レベル10到達!\n\n\
|
||||
{}:「ここまで一緒に来られたね。\n\
|
||||
あなたとなら、どこまでも行けそう。」",
|
||||
companion_name
|
||||
)
|
||||
}
|
||||
SpecialEvent::MaxTrust => {
|
||||
format!(
|
||||
"✨ 信頼度MAX!\n\n\
|
||||
{}:「あなたのこと、心から信頼してる。\n\
|
||||
何でも話せるって、すごく嬉しいよ。」",
|
||||
companion_name
|
||||
)
|
||||
}
|
||||
SpecialEvent::FirstDate => {
|
||||
format!(
|
||||
"💐 初デートイベント!\n\n\
|
||||
{}:「今度、二人でどこか行かない?」",
|
||||
companion_name
|
||||
)
|
||||
}
|
||||
SpecialEvent::Confession => {
|
||||
format!(
|
||||
"💝 告白イベント!\n\n\
|
||||
{}:「好きです。付き合ってください。」",
|
||||
companion_name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// コンパニオンフォーマッター
|
||||
pub struct CompanionFormatter;
|
||||
|
||||
impl CompanionFormatter {
|
||||
/// 反応を表示
|
||||
pub fn format_reaction(companion: &Companion, reaction: &CompanionReaction) -> String {
|
||||
let affection_bar = Self::format_affection_bar(reaction.current_affection);
|
||||
let level_up_text = if reaction.level_up {
|
||||
format!("\n🎊 レベルアップ! Lv.{} → Lv.{}", reaction.new_level - 1, reaction.new_level)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let special_event_text = if let Some(ref event) = reaction.special_event {
|
||||
format!("\n\n{}", event.message(&companion.name))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
format!(
|
||||
r#"
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ 💕 {} の反応 ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
|
||||
{} {}:
|
||||
「{}」
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
💕 好感度: {} (+{:.1}%)
|
||||
💎 XP獲得: +{} XP{}
|
||||
🏆 レベル: Lv.{}
|
||||
🤝 信頼度: {} / 100
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{}
|
||||
"#,
|
||||
companion.name,
|
||||
companion.personality.emoji(),
|
||||
companion.name,
|
||||
reaction.message,
|
||||
affection_bar,
|
||||
reaction.affection_gained * 100.0,
|
||||
reaction.xp_gained,
|
||||
level_up_text,
|
||||
companion.relationship_level,
|
||||
companion.trust_level,
|
||||
special_event_text
|
||||
)
|
||||
}
|
||||
|
||||
/// プロフィール表示
|
||||
pub fn format_profile(companion: &Companion) -> String {
|
||||
let affection_bar = Self::format_affection_bar(companion.affection_score);
|
||||
|
||||
format!(
|
||||
r#"
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ 💕 {} のプロフィール ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
|
||||
{} 性格: {}
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
📊 ステータス
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🏆 関係レベル: Lv.{}
|
||||
💕 好感度: {}
|
||||
🤝 信頼度: {} / 100
|
||||
💎 総XP: {} XP
|
||||
📚 共有記憶: {}個
|
||||
🕐 最終交流: {}
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
💬 今日のひとこと:
|
||||
「{}」
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
"#,
|
||||
companion.name,
|
||||
companion.personality.emoji(),
|
||||
companion.personality.name(),
|
||||
companion.relationship_level,
|
||||
affection_bar,
|
||||
companion.trust_level,
|
||||
companion.total_xp,
|
||||
companion.shared_memories.len(),
|
||||
companion.last_interaction.format("%Y-%m-%d %H:%M"),
|
||||
companion.generate_daily_message()
|
||||
)
|
||||
}
|
||||
|
||||
fn format_affection_bar(affection: f32) -> String {
|
||||
let hearts = (affection * 10.0) as usize;
|
||||
let filled = "❤️".repeat(hearts);
|
||||
let empty = "🤍".repeat(10 - hearts);
|
||||
format!("{}{} {:.0}%", filled, empty, affection * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_companion_creation() {
|
||||
let companion = Companion::new(
|
||||
"エミリー".to_string(),
|
||||
CompanionPersonality::Energetic,
|
||||
);
|
||||
assert_eq!(companion.name, "エミリー");
|
||||
assert_eq!(companion.relationship_level, 1);
|
||||
assert_eq!(companion.affection_score, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compatibility() {
|
||||
let personality = CompanionPersonality::Energetic;
|
||||
let innovator = DiagnosisType::Innovator;
|
||||
assert_eq!(personality.compatibility(&innovator), 0.95);
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,17 @@ pub enum DiagnosisType {
|
||||
}
|
||||
|
||||
impl DiagnosisType {
|
||||
/// スコアから診断タイプを推定(公開用)
|
||||
pub fn from_memory(memory: &crate::memory::Memory) -> Self {
|
||||
// スコア内訳を推定
|
||||
let emotional = (memory.priority_score * 0.25).min(0.25);
|
||||
let relevance = (memory.priority_score * 0.25).min(0.25);
|
||||
let novelty = (memory.priority_score * 0.25).min(0.25);
|
||||
let utility = memory.priority_score - emotional - relevance - novelty;
|
||||
|
||||
Self::from_score_breakdown(emotional, relevance, novelty, utility)
|
||||
}
|
||||
|
||||
pub fn from_score_breakdown(
|
||||
emotional: f32,
|
||||
relevance: f32,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod memory;
|
||||
pub mod mcp;
|
||||
pub mod ai_interpreter;
|
||||
pub mod game_formatter;
|
||||
pub mod game_formatter;
|
||||
pub mod companion;
|
||||
128
src/mcp/base.rs
128
src/mcp/base.rs
@@ -3,16 +3,22 @@ use serde_json::{json, Value};
|
||||
use std::io::{self, BufRead, Write};
|
||||
|
||||
use crate::memory::MemoryManager;
|
||||
use crate::game_formatter::GameFormatter;
|
||||
use crate::game_formatter::{GameFormatter, DiagnosisType};
|
||||
use crate::companion::{Companion, CompanionPersonality, CompanionFormatter};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub struct BaseMCPServer {
|
||||
pub memory_manager: MemoryManager,
|
||||
pub companion: Option<Companion>, // 恋愛コンパニオン(オプション)
|
||||
}
|
||||
|
||||
impl BaseMCPServer {
|
||||
pub async fn new() -> Result<Self> {
|
||||
let memory_manager = MemoryManager::new().await?;
|
||||
Ok(BaseMCPServer { memory_manager })
|
||||
Ok(BaseMCPServer {
|
||||
memory_manager,
|
||||
companion: None, // 初期状態はコンパニオンなし
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<()> {
|
||||
@@ -210,6 +216,47 @@ impl BaseMCPServer {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "create_companion",
|
||||
"description": "Create your AI companion - Choose name and personality!",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Companion's name"
|
||||
},
|
||||
"personality": {
|
||||
"type": "string",
|
||||
"enum": ["energetic", "intellectual", "practical", "dreamy", "balanced"],
|
||||
"description": "Companion's personality type"
|
||||
}
|
||||
},
|
||||
"required": ["name", "personality"]
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "companion_react",
|
||||
"description": "Show your companion's reaction to your latest memory",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memory_id": {
|
||||
"type": "string",
|
||||
"description": "Memory ID to react to"
|
||||
}
|
||||
},
|
||||
"required": ["memory_id"]
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "companion_profile",
|
||||
"description": "View your companion's profile and stats",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
@@ -240,6 +287,9 @@ impl BaseMCPServer {
|
||||
"create_memory_with_ai" => self.tool_create_memory_with_ai(arguments).await,
|
||||
"list_memories_by_priority" => self.tool_list_memories_by_priority(arguments),
|
||||
"daily_challenge" => self.tool_daily_challenge(),
|
||||
"create_companion" => self.tool_create_companion(arguments),
|
||||
"companion_react" => self.tool_companion_react(arguments),
|
||||
"companion_profile" => self.tool_companion_profile(),
|
||||
"search_memories" => self.tool_search_memories(arguments),
|
||||
"update_memory" => self.tool_update_memory(arguments),
|
||||
"delete_memory" => self.tool_delete_memory(arguments),
|
||||
@@ -424,6 +474,80 @@ impl BaseMCPServer {
|
||||
})
|
||||
}
|
||||
|
||||
// コンパニオン作成
|
||||
fn tool_create_companion(&mut self, arguments: &Value) -> Value {
|
||||
let name = arguments["name"].as_str().unwrap_or("エミリー");
|
||||
let personality_str = arguments["personality"].as_str().unwrap_or("balanced");
|
||||
|
||||
let personality = match personality_str {
|
||||
"energetic" => CompanionPersonality::Energetic,
|
||||
"intellectual" => CompanionPersonality::Intellectual,
|
||||
"practical" => CompanionPersonality::Practical,
|
||||
"dreamy" => CompanionPersonality::Dreamy,
|
||||
_ => CompanionPersonality::Balanced,
|
||||
};
|
||||
|
||||
let companion = Companion::new(name.to_string(), personality);
|
||||
let profile = CompanionFormatter::format_profile(&companion);
|
||||
|
||||
self.companion = Some(companion);
|
||||
|
||||
json!({
|
||||
"success": true,
|
||||
"profile": profile,
|
||||
"message": format!("{}があなたのコンパニオンになりました!", name)
|
||||
})
|
||||
}
|
||||
|
||||
// コンパニオンの反応
|
||||
fn tool_companion_react(&mut self, arguments: &Value) -> Value {
|
||||
if self.companion.is_none() {
|
||||
return json!({
|
||||
"success": false,
|
||||
"error": "コンパニオンが作成されていません。create_companionツールで作成してください。"
|
||||
});
|
||||
}
|
||||
|
||||
let memory_id = arguments["memory_id"].as_str().unwrap_or("");
|
||||
|
||||
if let Some(memory) = self.memory_manager.get_memory(memory_id) {
|
||||
let user_type = DiagnosisType::from_memory(memory);
|
||||
let companion = self.companion.as_mut().unwrap();
|
||||
let reaction = companion.react_to_memory(memory, &user_type);
|
||||
let reaction_display = CompanionFormatter::format_reaction(companion, &reaction);
|
||||
|
||||
json!({
|
||||
"success": true,
|
||||
"reaction_display": reaction_display,
|
||||
"affection_gained": reaction.affection_gained,
|
||||
"xp_gained": reaction.xp_gained,
|
||||
"level_up": reaction.level_up,
|
||||
"message": "コンパニオンが反応しました!"
|
||||
})
|
||||
} else {
|
||||
json!({
|
||||
"success": false,
|
||||
"error": format!("Memory not found: {}", memory_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// コンパニオンプロフィール
|
||||
fn tool_companion_profile(&self) -> Value {
|
||||
if let Some(ref companion) = self.companion {
|
||||
let profile = CompanionFormatter::format_profile(companion);
|
||||
json!({
|
||||
"success": true,
|
||||
"profile": profile
|
||||
})
|
||||
} else {
|
||||
json!({
|
||||
"success": false,
|
||||
"error": "コンパニオンが作成されていません。create_companionツールで作成してください。"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 不明なメソッドハンドラ
|
||||
fn handle_unknown_method(&self, id: Value) -> Value {
|
||||
json!({
|
||||
|
||||
Reference in New Issue
Block a user