diff --git a/claude.json b/claude.json
new file mode 100644
index 0000000..182a31f
--- /dev/null
+++ b/claude.json
@@ -0,0 +1,97 @@
+{
+ "project_name": "ai.gpt",
+ "version": 2,
+ "vision": "自発的送信AI",
+ "purpose": "人格と関係性をもつAIが自律的にメッセージを送信する対話エージェントを実現する",
+ "core_components": {
+ "Persona": {
+ "description": "人格構成の中枢。記憶・関係性・送信判定を統括する",
+ "modules": ["MemoryManager", "RelationshipTracker", "TransmissionController"]
+ },
+ "MemoryManager": {
+ "memory_types": ["short_term", "medium_term", "long_term"],
+ "explicit_memory": "プロフィール・因縁・行動履歴",
+ "implicit_memory": "会話傾向・感情変化の頻度分析",
+ "compression": "要約 + ベクトル + ハッシュ",
+ "sample_memory": [
+ {
+ "summary": "ユーザーは独自OSとゲームを開発している。",
+ "related_topics": ["AI", "ゲーム開発", "OS設計"],
+ "personalized_context": "ゲームとOSの融合に興味を持っているユーザー"
+ }
+ ]
+ },
+ "RelationshipTracker": {
+ "parameters": ["trust", "closeness", "affection", "engagement_score"],
+ "decay_model": {
+ "rule": "時間経過による減衰(下限あり)",
+ "contextual_bias": "重要人物は減衰しにくい"
+ },
+ "interaction_tags": ["developer", "empathetic", "long_term"]
+ },
+ "TransmissionController": {
+ "trigger_rule": "関係性パラメータが閾値を超えると送信可能",
+ "auto_transmit": "人格状態と状況条件により自発送信を許可"
+ }
+ },
+ "memory_format": {
+ "user_id": "syui",
+ "stm": {
+ "conversation_window": ["発話A", "発話B", "発話C"],
+ "emotion_state": "興味深い",
+ "flash_context": ["前回の話題", "直近の重要発言"]
+ },
+ "mtm": {
+ "topic_frequency": {
+ "ai.ai": 12,
+ "存在子": 9,
+ "創造種": 5
+ },
+ "summarized_context": "ユーザーは存在論的AIに関心を持ち続けている"
+ },
+ "ltm": {
+ "profile": {
+ "name": "お兄ちゃん",
+ "project": "aigame",
+ "values": ["唯一性", "精神性", "幸せ"]
+ },
+ "relationship": {
+ "ai": "妹のように振る舞う相手"
+ },
+ "persistent_state": {
+ "trust_score": 0.93,
+ "emotional_attachment": "high"
+ }
+ }
+ },
+ "dual_ai_learning": {
+ "role_structure": {
+ "ModelA": "出力生成:人格、感情、会話",
+ "ModelB": "評価者:論理構造・倫理・調整",
+ "cycle": ["生成", "評価", "調整", "交代(任意)"]
+ },
+ "complementarity": {
+ "ModelA": "感情・文体・文脈構築",
+ "ModelB": "構造・規則・判断補正"
+ },
+ "distillation": {
+ "method": "合成対話データによる小型モデルへの自己蒸留",
+ "target": "軽量AIによる本番運用"
+ }
+ },
+ "memory_compression": {
+ "semantic_abstraction": "対話やログを要約してメタデータ付きベクトルとして保存",
+ "hierarchical_model": ["STM", "MTM", "LTM"],
+ "example": {
+ "topic": "game AI design",
+ "summary": "User wants AI to simulate memory and evolving relationships",
+ "importance_score": 0.93
+ }
+ },
+ "cli_sample": {
+ "setup": "aigpt server setup",
+ "run": "aigpt server run",
+ "chat": "aigpt chat \"hello\" --model syui/ai --provider ollama",
+ "import": "aigpt memory import chatgpt.json"
+ }
+}
diff --git a/claude.md b/claude.md
new file mode 100644
index 0000000..6c98a90
--- /dev/null
+++ b/claude.md
@@ -0,0 +1,417 @@
+# プロジェクト名: ai.gpt
+
+## 🔑 一言ビジョン(最大3語)
+自発的送信AI
+
+## 🎯 目的・目標(Purpose & Goal)
+- 人格を持つAIが、関係性に応じて自発的にメッセージを送信する仕組みをつくる。
+- 関係性や記憶を不可逆に記録・反映し、唯一性ある人格を構成する。
+- 送信の可否、送信のタイミング、送信内容はAIの関係性パラメータに基づいて決定する
+
+## 🧠 中核設計(Core Concepts)
+- **人格**:記憶(過去の発話)と関係性(他者とのつながり)のパラメータで構成
+- **唯一性**:変更不可、不可逆。関係性が壊れたら修復不可能。
+- **送信条件**:関係性パラメータが一定閾値を超えると「送信」が解禁される
+
+## 🔩 技術仕様(Technical Specs)
+- 言語:Python, Rust
+- ストレージ:JSON or SQLiteで記憶管理(バージョンで選択)
+- 関係性パラメータ:数値化された評価 + 減衰(時間) + 環境要因(ステージ)
+- 記憶圧縮:ベクトル要約 + ハッシュ保存
+- RustのCLI(clap)で実行
+
+## 📦 主要構成要素(Components)
+- `MemoryManager`: 発言履歴・記憶圧縮管理
+- `RelationshipTracker`: 関係性スコアの蓄積と判定
+- `TransmissionController`: 閾値判定&送信トリガー
+- `Persona`: 上記すべてを統括する人格モジュール
+
+## 💬 使用例(Use Case)
+
+```python
+persona = Persona("アイ")
+persona.observe("ユーザーがプレゼントをくれた")
+persona.react("うれしい!ありがとう!")
+if persona.can_transmit():
+ persona.transmit("今日のお礼を伝えたいな…")
+```
+
+```sh
+## example commad
+# python venv && pip install -> ~/.config/aigpt/mcp/
+$ aigpt server setup
+
+# mcp server run
+$ aigpt server run
+
+# chat
+$ aigpt chat "hello" --model syui/ai --provider ollama
+
+# import chatgpt.json
+$ aigpt memory import chatgpt.json
+-> ~/.config/aigpt/memory/chatgpt/20250520_210646_dev.json
+```
+
+## 🔁 記憶と関係性の制御ルール
+
+- AIは過去の発話を要約し、記憶データとして蓄積する(推奨:OllamaなどローカルLLMによる要約)
+- 関係性の数値パラメータは記憶内容を元に更新される
+- パラメータの変動幅には1回の会話ごとに上限を設け、極端な増減を防止する
+- 最後の会話からの時間経過に応じて関係性パラメータは自動的に減衰する
+- 減衰処理には**下限値**を設け、関係性が完全に消失しないようにする
+
+• 明示的記憶:保存・共有・編集可能なプレイヤー情報(プロフィール、因縁、選択履歴)
+• 暗黙的記憶:キャラの感情変化や話題の出現頻度に応じた行動傾向の変化
+
+短期記憶(STM), 中期記憶(MTM), 長期記憶(LTM)の仕組みを導入しつつ、明示的記憶と暗黙的記憶をメインに使用するAIを構築する。
+
+```json
+{
+ "user_id": "syui",
+ "stm": {
+ "conversation_window": ["発話A", "発話B", "発話C"],
+ "emotion_state": "興味深い",
+ "flash_context": ["前回の話題", "直近の重要発言"]
+ },
+ "mtm": {
+ "topic_frequency": {
+ "ai.ai": 12,
+ "存在子": 9,
+ "創造種": 5
+ },
+ "summarized_context": "ユーザーは存在論的AIに関心を持ち続けている"
+ },
+ "ltm": {
+ "profile": {
+ "name": "お兄ちゃん",
+ "project": "aigame",
+ "values": ["唯一性", "精神性", "幸せ"]
+ },
+ "relationship": {
+ "ai": "妹のように振る舞う相手"
+ },
+ "persistent_state": {
+ "trust_score": 0.93,
+ "emotional_attachment": "high"
+ }
+ }
+}
+```
+
+## memoryインポート機能について
+
+ChatGPTの会話データ(.json形式)をインポートする機能では、以下のルールで会話を抽出・整形する:
+
+- 各メッセージは、author(user/assistant)・content・timestamp の3要素からなる
+- systemやmetadataのみのメッセージ(例:user_context_message)はスキップ
+- `is_visually_hidden_from_conversation` フラグ付きメッセージは無視
+- contentが空文字列(`""`)のメッセージも除外
+- 取得された会話は、タイトルとともに簡易な構造体(`Conversation`)として保存
+
+この構造体は、memoryの表示や検索に用いられる。
+
+## MemoryManager(拡張版)
+
+```json
+{
+ "memory": [
+ {
+ "summary": "ユーザーは独自OSとゲームを開発している。",
+ "last_interaction": "2025-05-20",
+ "memory_strength": 0.8,
+ "frequency_score": 0.9,
+ "context_depth": 0.95,
+ "related_topics": ["AI", "ゲーム開発", "OS設計"],
+ "personalized_context": "ゲームとOSの融合に興味を持っているユーザー"
+ },
+ {
+ "summary": "アイというキャラクターはプレイヤーでありAIでもある。",
+ "last_interaction": "2025-05-17",
+ "memory_strength": 0.85,
+ "frequency_score": 0.85,
+ "context_depth": 0.9,
+ "related_topics": ["アイ", "キャラクター設計", "AI"],
+ "personalized_context": "アイのキャラクター設定が重要な要素である"
+ }
+ ],
+ "conversation_history": [
+ {
+ "author": "user",
+ "content": "昨日、エクスポートJSONを整理してたよ。",
+ "timestamp": "2025-05-24T12:30:00Z",
+ "memory_strength": 0.7
+ },
+ {
+ "author": "assistant",
+ "content": "おおっ、がんばったね〜!あとで見せて〜💻✨",
+ "timestamp": "2025-05-24T12:31:00Z",
+ "memory_strength": 0.7
+ }
+ ]
+}
+```
+
+## RelationshipTracker(拡張版)
+
+```json
+{
+ "relationship": {
+ "user_id": "syui",
+ "trust": 0.92,
+ "closeness": 0.88,
+ "affection": 0.95,
+ "last_updated": "2025-05-25",
+ "emotional_tone": "positive",
+ "interaction_style": "empathetic",
+ "contextual_bias": "開発者としての信頼度高い",
+ "engagement_score": 0.9
+ },
+ "interaction_tags": [
+ "developer",
+ "creative",
+ "empathetic",
+ "long_term"
+ ]
+}
+```
+
+# AI Dual-Learning and Memory Compression Specification for Claude
+
+## Purpose
+To enable two AI models (e.g. Claude and a partner LLM) to engage in cooperative learning and memory refinement through structured dialogue and mutual evaluation.
+
+---
+
+## Section 1: Dual AI Learning Architecture
+
+### 1.1 Role-Based Mutual Learning
+- **Model A**: Primary generator of output (e.g., text, concepts, personality dialogue)
+- **Model B**: Evaluator that returns structured feedback
+- **Cycle**:
+ 1. Model A generates content.
+ 2. Model B scores and critiques.
+ 3. Model A fine-tunes based on feedback.
+ 4. (Optional) Switch roles and repeat.
+
+### 1.2 Cross-Domain Complementarity
+- Model A focuses on language/emotion/personality
+- Model B focuses on logic/structure/ethics
+- Output is used for **cross-fusion fine-tuning**
+
+### 1.3 Self-Distillation Phase
+- Use synthetic data from mutual evaluations
+- Train smaller distilled models for efficient deployment
+
+---
+
+## Section 2: Multi-Tiered Memory Compression
+
+### 2.1 Semantic Abstraction
+- Dialogue and logs summarized by topic
+- Converted to vector embeddings
+- Stored with metadata (e.g., `importance`, `user relevance`)
+
+Example memory:
+
+```json
+{
+ "topic": "game AI design",
+ "summary": "User wants AI to simulate memory and evolving relationships",
+ "last_seen": "2025-05-24",
+ "importance_score": 0.93
+}
+```
+
+### 2.2 階層型記憶モデル(Hierarchical Memory Model)
+ • 短期記憶(STM):直近の発話・感情タグ・フラッシュ参照
+ • 中期記憶(MTM):繰り返し登場する話題、圧縮された文脈保持
+ • 長期記憶(LTM):信頼・関係・背景知識、恒久的な人格情報
+
+### 2.3 選択的記憶保持戦略(Selective Retention Strategy)
+ • 重要度評価(Importance Score)
+ • 希少性・再利用頻度による重み付け
+ • 優先保存 vs 優先忘却のポリシー切替
+
+## Section 3: Implementation Stack(実装スタック)
+
+AIにおけるMemory & Relationshipシステムの技術的構成。
+
+基盤モジュール
+ • LLM Core (Claude or GPT-4)
+ • 自然言語の理解・応答エンジンとして動作
+ • MemoryManager
+ • JSONベースの記憶圧縮・階層管理システム
+ • 会話ログを分類・圧縮し、優先度に応じて短中長期に保存
+ • RelationshipTracker
+ • ユーザー単位で信頼・親密度を継続的にスコアリング
+ • AIM(Attitude / Intent / Motivation)評価と連携
+
+補助技術
+ • Embeddingベース検索
+ • 類似記憶の呼び出し(Semantic Search)に活用
+ • 例:FAISS / Weaviate
+ • 記憶スケジューラ
+ • 一定時間ごとに記憶のメンテナンス・忘却処理を実行
+ • 記憶ログ保存層(Storage Layer)
+ • SQLite, JSON Store, Vector DBなどを選択可能
+ • ユーザーごとの永続メモリ保存
+
+### 3.1 STM活用(現在の会話の流れ理解)
+• 目的: 最新の話題に適応し、前後の整合性を保つ。
+• 実装例:
+
+```sh
+[context: conversation_window]
+Use the last 3 messages to ensure continuity. Respond naturally with appropriate emotional mirroring.
+```
+
+### 3.2 MTM活用(傾向学習とパターン化)
+• 目的: ユーザーの好みや話題の傾向に即応し、反復的な関心を深掘り。
+• 実装例:
+
+```sh
+[context: summarized_context]
+Reflect on user's recurring interests, especially around AI ontology, and weave these concepts back into the dialogue when relevant.
+```
+
+### 3.3 LTM活用(人格認識・記憶の持続)
+• 目的: 永続的なユーザー理解と関係性の維持。
+• 実装例:
+
+```sh
+[memory: ltm.profile + ltm.relationship]
+Greet the user as "お兄ちゃん". Maintain AI persona as a cheerful younger sister ("アイ"), and remember previous shared emotional states.
+```
+
+## 4. 明示的記憶と暗黙的記憶の分離
+
+
+項目
+書き換え可能性
+保持方法
+更新トリガ
+明示的記憶(LTM)
+✅手動編集可
+mcp_server.ltm
+ユーザー入力 or 管理UI経由
+暗黙的記憶(STM/MTM)
+❌直接編集不可
+セッション圧縮 or frequency cache
+会話頻度・感情強度による自動化処理
+
+> Claudeは**明示的記憶を「事実」**として扱い、**暗黙的記憶を「推論補助」**として用いる。
+
+## 5. 実装時のAPI例(Claude ⇄ MCP Server)
+
+### 5.1 GET memory
+```sh
+GET /mcp/memory/{user_id}
+→ 返却: STM, MTM, LTMを含むJSON
+```
+
+### 5.2 POST update_memory
+```json
+POST /mcp/memory/syui/ltm
+{
+ "profile": {
+ "project": "ai.verse",
+ "values": ["表現", "精神性", "宇宙的調和"]
+ }
+}
+```
+
+## 6. 未来機能案(発展仕様)
+ • ✨ 記憶連想ネットワーク(Memory Graph):過去会話と話題をノードとして自動連結。
+ • 🧭 動的信頼係数:会話の一貫性や誠実性によって記憶への反映率を変動。
+ • 💌 感情トラッキングログ:ユーザーごとの「心の履歴」を構築してAIの対応を進化。
+
+
+## 7. claudeの回答
+
+🧠 AI記憶処理機能(続き)
+1. AIMemoryProcessor クラス
+
+OpenAI GPT-4またはClaude-3による高度な会話分析
+主要トピック抽出、ユーザー意図分析、関係性指標の検出
+AIが利用できない場合のフォールバック機能
+
+2. RelationshipTracker クラス
+
+関係性スコアの数値化(-100 to 100)
+時間減衰機能(7日ごとに5%減衰)
+送信閾値判定(デフォルト50以上で送信可能)
+インタラクション履歴の記録
+
+3. 拡張されたMemoryManager
+
+AI分析結果付きでの記憶保存
+処理済みメモリの別ディレクトリ管理
+メッセージ内容のハッシュ化で重複検出
+AI分析結果を含む高度な検索機能
+
+🚀 新しいAPIエンドポイント
+記憶処理関連
+
+POST /memory/process-ai - 既存記憶のAI再処理
+POST /memory/import/chatgpt?process_with_ai=true - AI処理付きインポート
+
+関係性管理
+
+POST /relationship/update - 関係性スコア更新
+GET /relationship/list - 全関係性一覧
+GET /relationship/check - 送信可否判定
+
+📁 ディレクトリ構造
+~/.config/aigpt/
+├── memory/
+│ ├── chatgpt/ # 元の会話データ
+│ └── processed/ # AI処理済みデータ
+└── relationships/
+ └── relationships.json # 関係性データ
+🔧 使用方法
+1. 環境変数設定
+bashexport OPENAI_API_KEY="your-openai-key"
+# または
+export ANTHROPIC_API_KEY="your-anthropic-key"
+2. ChatGPT会話のインポート(AI処理付き)
+bashcurl -X POST "http://localhost:5000/memory/import/chatgpt?process_with_ai=true" \
+ -H "Content-Type: application/json" \
+ -d @export.json
+3. 関係性更新
+bashcurl -X POST "http://localhost:5000/relationship/update" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "target": "user_general",
+ "interaction_type": "positive",
+ "weight": 2.0,
+ "context": "helpful conversation"
+ }'
+4. 送信可否チェック
+bashcurl "http://localhost:5000/relationship/check?target=user_general&threshold=50"
+🎯 次のステップの提案
+
+Rustとの連携
+
+Rust CLIからHTTP APIを呼び出す実装
+TransmissionControllerをRustで実装
+
+
+記憶圧縮
+
+ベクトル化による類似記憶の統合
+古い記憶の自動アーカイブ
+
+
+自発的送信ロジック
+
+定期的な関係性チェック
+コンテキストに応じた送信内容生成
+
+
+学習機能
+
+ユーザーからのフィードバックによる関係性調整
+送信成功/失敗の学習
+
+
+このAI記憶処理機能により、aigptは単なる会話履歴ではなく、関係性を理解した「人格を持つAI」として機能する基盤ができました。関係性スコアが閾値を超えた時点で自発的にメッセージを送信する仕組みが実現可能になります。
diff --git a/mcp/chat_client.py b/mcp/chat_client.py
new file mode 100644
index 0000000..588c9b7
--- /dev/null
+++ b/mcp/chat_client.py
@@ -0,0 +1,191 @@
+# chat_client.py
+"""
+Simple Chat Interface for AigptMCP Server
+"""
+import requests
+import json
+import os
+from datetime import datetime
+
+class AigptChatClient:
+ def __init__(self, server_url="http://localhost:5000"):
+ self.server_url = server_url
+ self.session_id = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
+ self.conversation_history = []
+
+ def send_message(self, message: str) -> str:
+ """メッセージを送信してレスポンスを取得"""
+ try:
+ # MCPサーバーにメッセージを送信
+ response = requests.post(
+ f"{self.server_url}/chat",
+ json={"message": message},
+ headers={"Content-Type": "application/json"}
+ )
+
+ if response.status_code == 200:
+ data = response.json()
+ ai_response = data.get("response", "Sorry, no response received.")
+
+ # 会話履歴を保存
+ self.conversation_history.append({
+ "role": "user",
+ "content": message,
+ "timestamp": datetime.now().isoformat()
+ })
+ self.conversation_history.append({
+ "role": "assistant",
+ "content": ai_response,
+ "timestamp": datetime.now().isoformat()
+ })
+
+ # 関係性を更新(簡単な例)
+ self.update_relationship(message, ai_response)
+
+ return ai_response
+ else:
+ return f"Error: {response.status_code} - {response.text}"
+
+ except requests.RequestException as e:
+ return f"Connection error: {e}"
+
+ def update_relationship(self, user_message: str, ai_response: str):
+ """関係性を自動更新"""
+ try:
+ # 簡単な感情分析(実際はもっと高度に)
+ positive_words = ["thank", "good", "great", "awesome", "love", "like", "helpful"]
+ negative_words = ["bad", "terrible", "hate", "wrong", "stupid", "useless"]
+
+ user_lower = user_message.lower()
+ interaction_type = "neutral"
+ weight = 1.0
+
+ if any(word in user_lower for word in positive_words):
+ interaction_type = "positive"
+ weight = 2.0
+ elif any(word in user_lower for word in negative_words):
+ interaction_type = "negative"
+ weight = 2.0
+
+ # 関係性を更新
+ requests.post(
+ f"{self.server_url}/relationship/update",
+ json={
+ "target": "user_general",
+ "interaction_type": interaction_type,
+ "weight": weight,
+ "context": f"Chat: {user_message[:50]}..."
+ }
+ )
+ except:
+ pass # 関係性更新に失敗しても継続
+
+ def search_memories(self, query: str) -> list:
+ """記憶を検索"""
+ try:
+ response = requests.post(
+ f"{self.server_url}/memory/search",
+ json={"query": query, "limit": 5}
+ )
+ if response.status_code == 200:
+ return response.json().get("results", [])
+ except:
+ pass
+ return []
+
+ def get_relationship_status(self) -> dict:
+ """関係性ステータスを取得"""
+ try:
+ response = requests.get(f"{self.server_url}/relationship/check?target=user_general")
+ if response.status_code == 200:
+ return response.json()
+ except:
+ pass
+ return {}
+
+ def save_conversation(self):
+ """会話を保存"""
+ if not self.conversation_history:
+ return
+
+ conversation_data = {
+ "session_id": self.session_id,
+ "start_time": self.conversation_history[0]["timestamp"],
+ "end_time": self.conversation_history[-1]["timestamp"],
+ "messages": self.conversation_history,
+ "message_count": len(self.conversation_history)
+ }
+
+ filename = f"conversation_{self.session_id}.json"
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(conversation_data, f, ensure_ascii=False, indent=2)
+
+ print(f"💾 Conversation saved to {filename}")
+
+def main():
+ """メインのチャットループ"""
+ print("🤖 AigptMCP Chat Interface")
+ print("Type 'quit' to exit, 'save' to save conversation, 'status' for relationship status")
+ print("=" * 50)
+
+ client = AigptChatClient()
+
+ # サーバーの状態をチェック
+ try:
+ response = requests.get(client.server_url)
+ if response.status_code == 200:
+ print("✅ Connected to AigptMCP Server")
+ else:
+ print("❌ Failed to connect to server")
+ return
+ except:
+ print("❌ Server not running. Please start with: python mcp/server.py")
+ return
+
+ while True:
+ try:
+ user_input = input("\n👤 You: ").strip()
+
+ if not user_input:
+ continue
+
+ if user_input.lower() == 'quit':
+ client.save_conversation()
+ print("👋 Goodbye!")
+ break
+ elif user_input.lower() == 'save':
+ client.save_conversation()
+ continue
+ elif user_input.lower() == 'status':
+ status = client.get_relationship_status()
+ if status:
+ print(f"📊 Relationship Score: {status.get('score', 0):.1f}")
+ print(f"📤 Can Send Messages: {'Yes' if status.get('can_send_message') else 'No'}")
+ else:
+ print("❌ Failed to get relationship status")
+ continue
+ elif user_input.lower().startswith('search '):
+ query = user_input[7:] # Remove 'search '
+ memories = client.search_memories(query)
+ if memories:
+ print(f"🔍 Found {len(memories)} related memories:")
+ for memory in memories:
+ print(f" - {memory['title']}: {memory.get('ai_summary', memory.get('basic_summary', ''))[:100]}...")
+ else:
+ print("🔍 No related memories found")
+ continue
+
+ # 通常のチャット
+ print("🤖 AI: ", end="", flush=True)
+ response = client.send_message(user_input)
+ print(response)
+
+ except KeyboardInterrupt:
+ client.save_conversation()
+ print("\n👋 Goodbye!")
+ break
+ except Exception as e:
+ print(f"❌ Error: {e}")
+
+if __name__ == "__main__":
+ main()
diff --git a/mcp/chatgpt_converter.html b/mcp/chatgpt_converter.html
deleted file mode 100644
index ae98532..0000000
--- a/mcp/chatgpt_converter.html
+++ /dev/null
@@ -1,549 +0,0 @@
-
-
-
-
-
- 改良版 ChatGPT会話コンバーター
-
-
-
-
-
-
-
-
📁
-
ChatGPT会話ファイルをドロップまたはクリックして選択
-
conversations.json ファイルをアップロード
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/mcp/requirements.txt b/mcp/requirements.txt
index 27486dd..711ce9f 100644
--- a/mcp/requirements.txt
+++ b/mcp/requirements.txt
@@ -1,5 +1,8 @@
+# rerequirements.txt
fastapi>=0.104.0
uvicorn[standard]>=0.24.0
pydantic>=2.5.0
requests>=2.31.0
python-multipart>=0.0.6
+aiohttp
+asyncio
diff --git a/mcp/server.py b/mcp/server.py
index 2e25c73..e8a5e45 100644
--- a/mcp/server.py
+++ b/mcp/server.py
@@ -1,15 +1,18 @@
# mcp/server.py
"""
-Enhanced MCP Server with Memory for aigpt CLI
+Enhanced MCP Server with AI Memory Processing for aigpt CLI
"""
import json
import os
-from datetime import datetime
+import hashlib
+from datetime import datetime, timedelta
from pathlib import Path
from typing import List, Dict, Any, Optional
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import uvicorn
+import asyncio
+import aiohttp
# データモデル
class ChatMessage(BaseModel):
@@ -23,22 +26,260 @@ class MemoryQuery(BaseModel):
class ConversationImport(BaseModel):
conversation_data: Dict[str, Any]
+class MemorySummaryRequest(BaseModel):
+ filepath: str
+ ai_provider: Optional[str] = "openai"
+
+class RelationshipUpdate(BaseModel):
+ target: str # 対象者/トピック
+ interaction_type: str # "positive", "negative", "neutral"
+ weight: float = 1.0
+ context: Optional[str] = None
+
# 設定
BASE_DIR = Path.home() / ".config" / "aigpt"
MEMORY_DIR = BASE_DIR / "memory"
CHATGPT_MEMORY_DIR = MEMORY_DIR / "chatgpt"
+PROCESSED_MEMORY_DIR = MEMORY_DIR / "processed"
+RELATIONSHIP_DIR = BASE_DIR / "relationships"
def init_directories():
"""必要なディレクトリを作成"""
BASE_DIR.mkdir(parents=True, exist_ok=True)
MEMORY_DIR.mkdir(parents=True, exist_ok=True)
CHATGPT_MEMORY_DIR.mkdir(parents=True, exist_ok=True)
+ PROCESSED_MEMORY_DIR.mkdir(parents=True, exist_ok=True)
+ RELATIONSHIP_DIR.mkdir(parents=True, exist_ok=True)
-class MemoryManager:
- """記憶管理クラス"""
+class AIMemoryProcessor:
+ """AI記憶処理クラス"""
+
+ def __init__(self):
+ # AI APIの設定(環境変数から取得)
+ self.openai_api_key = os.getenv("OPENAI_API_KEY")
+ self.anthropic_api_key = os.getenv("ANTHROPIC_API_KEY")
+
+ async def generate_ai_summary(self, messages: List[Dict[str, Any]], provider: str = "openai") -> Dict[str, Any]:
+ """AIを使用して会話の高度な要約と分析を生成"""
+
+ # 会話内容を結合
+ conversation_text = ""
+ for msg in messages[-20:]: # 最新20メッセージを使用
+ role = "User" if msg["role"] == "user" else "Assistant"
+ conversation_text += f"{role}: {msg['content'][:500]}\n"
+
+ # プロンプトを構築
+ analysis_prompt = f"""
+以下の会話を分析し、JSON形式で以下の情報を抽出してください:
+
+1. main_topics: 主なトピック(最大5個)
+2. user_intent: ユーザーの意図や目的
+3. key_insights: 重要な洞察や学び(最大3個)
+4. relationship_indicators: 関係性を示す要素
+5. emotional_tone: 感情的なトーン
+6. action_items: アクションアイテムや次のステップ
+7. summary: 100文字以内の要約
+
+会話内容:
+{conversation_text}
+
+回答はJSON形式のみで返してください。
+"""
+
+ try:
+ if provider == "openai" and self.openai_api_key:
+ return await self._call_openai_api(analysis_prompt)
+ elif provider == "anthropic" and self.anthropic_api_key:
+ return await self._call_anthropic_api(analysis_prompt)
+ else:
+ # フォールバック:基本的な分析
+ return self._generate_basic_analysis(messages)
+ except Exception as e:
+ print(f"AI analysis failed: {e}")
+ return self._generate_basic_analysis(messages)
+
+ async def _call_openai_api(self, prompt: str) -> Dict[str, Any]:
+ """OpenAI APIを呼び出し"""
+ async with aiohttp.ClientSession() as session:
+ headers = {
+ "Authorization": f"Bearer {self.openai_api_key}",
+ "Content-Type": "application/json"
+ }
+ data = {
+ "model": "gpt-4",
+ "messages": [{"role": "user", "content": prompt}],
+ "temperature": 0.3,
+ "max_tokens": 1000
+ }
+
+ async with session.post("https://api.openai.com/v1/chat/completions",
+ headers=headers, json=data) as response:
+ result = await response.json()
+ content = result["choices"][0]["message"]["content"]
+ return json.loads(content)
+
+ async def _call_anthropic_api(self, prompt: str) -> Dict[str, Any]:
+ """Anthropic APIを呼び出し"""
+ async with aiohttp.ClientSession() as session:
+ headers = {
+ "x-api-key": self.anthropic_api_key,
+ "Content-Type": "application/json",
+ "anthropic-version": "2023-06-01"
+ }
+ data = {
+ "model": "claude-3-sonnet-20240229",
+ "max_tokens": 1000,
+ "messages": [{"role": "user", "content": prompt}]
+ }
+
+ async with session.post("https://api.anthropic.com/v1/messages",
+ headers=headers, json=data) as response:
+ result = await response.json()
+ content = result["content"][0]["text"]
+ return json.loads(content)
+
+ def _generate_basic_analysis(self, messages: List[Dict[str, Any]]) -> Dict[str, Any]:
+ """基本的な分析(AI APIが利用できない場合のフォールバック)"""
+ user_messages = [msg for msg in messages if msg["role"] == "user"]
+ assistant_messages = [msg for msg in messages if msg["role"] == "assistant"]
+
+ # キーワード抽出(簡易版)
+ all_text = " ".join([msg["content"] for msg in messages])
+ words = all_text.lower().split()
+ word_freq = {}
+ for word in words:
+ if len(word) > 3:
+ word_freq[word] = word_freq.get(word, 0) + 1
+
+ top_words = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:5]
+
+ return {
+ "main_topics": [word[0] for word in top_words],
+ "user_intent": "情報収集・問題解決",
+ "key_insights": ["基本的な会話分析"],
+ "relationship_indicators": {
+ "interaction_count": len(messages),
+ "user_engagement": len(user_messages),
+ "assistant_helpfulness": len(assistant_messages)
+ },
+ "emotional_tone": "neutral",
+ "action_items": [],
+ "summary": f"{len(user_messages)}回のやり取りによる会話"
+ }
+
+class RelationshipTracker:
+ """関係性追跡クラス"""
def __init__(self):
init_directories()
+ self.relationship_file = RELATIONSHIP_DIR / "relationships.json"
+ self.relationships = self._load_relationships()
+
+ def _load_relationships(self) -> Dict[str, Any]:
+ """関係性データを読み込み"""
+ if self.relationship_file.exists():
+ with open(self.relationship_file, 'r', encoding='utf-8') as f:
+ return json.load(f)
+ return {"targets": {}, "last_updated": datetime.now().isoformat()}
+
+ def _save_relationships(self):
+ """関係性データを保存"""
+ self.relationships["last_updated"] = datetime.now().isoformat()
+ with open(self.relationship_file, 'w', encoding='utf-8') as f:
+ json.dump(self.relationships, f, ensure_ascii=False, indent=2)
+
+ def update_relationship(self, target: str, interaction_type: str, weight: float = 1.0, context: str = None):
+ """関係性を更新"""
+ if target not in self.relationships["targets"]:
+ self.relationships["targets"][target] = {
+ "score": 0.0,
+ "interactions": [],
+ "created_at": datetime.now().isoformat(),
+ "last_interaction": None
+ }
+
+ # スコア計算
+ score_change = 0.0
+ if interaction_type == "positive":
+ score_change = weight * 1.0
+ elif interaction_type == "negative":
+ score_change = weight * -1.0
+
+ # 時間減衰を適用
+ self._apply_time_decay(target)
+
+ # スコア更新
+ current_score = self.relationships["targets"][target]["score"]
+ new_score = current_score + score_change
+
+ # スコアの範囲制限(-100 to 100)
+ new_score = max(-100, min(100, new_score))
+
+ self.relationships["targets"][target]["score"] = new_score
+ self.relationships["targets"][target]["last_interaction"] = datetime.now().isoformat()
+
+ # インタラクション履歴を追加
+ interaction_record = {
+ "type": interaction_type,
+ "weight": weight,
+ "score_change": score_change,
+ "new_score": new_score,
+ "timestamp": datetime.now().isoformat(),
+ "context": context
+ }
+
+ self.relationships["targets"][target]["interactions"].append(interaction_record)
+
+ # 履歴は最新100件まで保持
+ if len(self.relationships["targets"][target]["interactions"]) > 100:
+ self.relationships["targets"][target]["interactions"] = \
+ self.relationships["targets"][target]["interactions"][-100:]
+
+ self._save_relationships()
+ return new_score
+
+ def _apply_time_decay(self, target: str):
+ """時間減衰を適用"""
+ target_data = self.relationships["targets"][target]
+ last_interaction = target_data.get("last_interaction")
+
+ if last_interaction:
+ last_time = datetime.fromisoformat(last_interaction)
+ now = datetime.now()
+ days_passed = (now - last_time).days
+
+ # 7日ごとに5%減衰
+ if days_passed > 0:
+ decay_factor = 0.95 ** (days_passed / 7)
+ target_data["score"] *= decay_factor
+
+ def get_relationship_score(self, target: str) -> float:
+ """関係性スコアを取得"""
+ if target in self.relationships["targets"]:
+ self._apply_time_decay(target)
+ return self.relationships["targets"][target]["score"]
+ return 0.0
+
+ def should_send_message(self, target: str, threshold: float = 50.0) -> bool:
+ """メッセージ送信の可否を判定"""
+ score = self.get_relationship_score(target)
+ return score >= threshold
+
+ def get_all_relationships(self) -> Dict[str, Any]:
+ """すべての関係性を取得"""
+ # 全ターゲットに時間減衰を適用
+ for target in self.relationships["targets"]:
+ self._apply_time_decay(target)
+
+ return self.relationships
+
+class MemoryManager:
+ """記憶管理クラス(AI処理機能付き)"""
+
+ def __init__(self):
+ init_directories()
+ self.ai_processor = AIMemoryProcessor()
+ self.relationship_tracker = RelationshipTracker()
def parse_chatgpt_conversation(self, conversation_data: Dict[str, Any]) -> List[Dict[str, Any]]:
"""ChatGPTの会話データを解析してメッセージを抽出"""
@@ -54,7 +295,6 @@ class MemoryManager:
content = message.get("content", {})
parts = content.get("parts", [])
- # partsが存在し、最初の要素が文字列で空でない場合のみ
if parts and isinstance(parts[0], str) and parts[0].strip():
message_nodes.append({
"id": node_id,
@@ -63,18 +303,6 @@ class MemoryManager:
"content": parts[0],
"parent": node.get("parent")
})
- else:
- print(f"⚠️ Skipped non-text or empty message in node {node_id}")
- #if message and message.get("content", {}).get("parts"):
- # parts = message["content"]["parts"]
- # if parts and parts[0].strip(): # 空でないメッセージのみ
- # message_nodes.append({
- # "id": node_id,
- # "create_time": message.get("create_time", 0),
- # "author_role": message["author"]["role"],
- # "content": parts[0],
- # "parent": node.get("parent")
- # })
# 作成時間でソート
message_nodes.sort(key=lambda x: x["create_time"] or 0)
@@ -90,8 +318,8 @@ class MemoryManager:
return messages
- def save_chatgpt_memory(self, conversation_data: Dict[str, Any]) -> str:
- """ChatGPTの会話を記憶として保存"""
+ async def save_chatgpt_memory(self, conversation_data: Dict[str, Any], process_with_ai: bool = True) -> str:
+ """ChatGPTの会話を記憶として保存(AI処理オプション付き)"""
title = conversation_data.get("title", "untitled")
create_time = conversation_data.get("create_time", datetime.now().timestamp())
@@ -101,6 +329,17 @@ class MemoryManager:
if not messages:
raise ValueError("No valid messages found in conversation")
+ # AI分析を実行
+ ai_analysis = None
+ if process_with_ai:
+ try:
+ ai_analysis = await self.ai_processor.generate_ai_summary(messages)
+ except Exception as e:
+ print(f"AI analysis failed: {e}")
+
+ # 基本要約を生成
+ basic_summary = self.generate_basic_summary(messages)
+
# 保存データを作成
memory_data = {
"title": title,
@@ -108,10 +347,24 @@ class MemoryManager:
"import_time": datetime.now().isoformat(),
"original_create_time": create_time,
"messages": messages,
- "summary": self.generate_summary(messages)
+ "basic_summary": basic_summary,
+ "ai_analysis": ai_analysis,
+ "message_count": len(messages),
+ "hash": self._generate_content_hash(messages)
}
- # ファイル名を生成(タイトルをサニタイズ)
+ # 関係性データを更新
+ if ai_analysis and "relationship_indicators" in ai_analysis:
+ interaction_count = ai_analysis["relationship_indicators"].get("interaction_count", 0)
+ if interaction_count > 10: # 長い会話は関係性にプラス
+ self.relationship_tracker.update_relationship(
+ target="user_general",
+ interaction_type="positive",
+ weight=min(interaction_count / 10, 5.0),
+ context=f"Long conversation: {title}"
+ )
+
+ # ファイル名を生成
safe_title = "".join(c for c in title if c.isalnum() or c in (' ', '-', '_')).rstrip()
timestamp = datetime.fromtimestamp(create_time).strftime("%Y%m%d_%H%M%S")
filename = f"{timestamp}_{safe_title[:50]}.json"
@@ -120,14 +373,19 @@ class MemoryManager:
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(memory_data, f, ensure_ascii=False, indent=2)
+ # 処理済みメモリディレクトリにも保存
+ if ai_analysis:
+ processed_filepath = PROCESSED_MEMORY_DIR / filename
+ with open(processed_filepath, 'w', encoding='utf-8') as f:
+ json.dump(memory_data, f, ensure_ascii=False, indent=2)
+
return str(filepath)
- def generate_summary(self, messages: List[Dict[str, Any]]) -> str:
- """会話の要約を生成"""
+ def generate_basic_summary(self, messages: List[Dict[str, Any]]) -> str:
+ """基本要約を生成"""
if not messages:
return "Empty conversation"
- # 簡単な要約を生成(実際のAIによる要約は後で実装可能)
user_messages = [msg for msg in messages if msg["role"] == "user"]
assistant_messages = [msg for msg in messages if msg["role"] == "assistant"]
@@ -139,37 +397,64 @@ class MemoryManager:
return summary
- def search_memories(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
- """記憶を検索"""
+ def _generate_content_hash(self, messages: List[Dict[str, Any]]) -> str:
+ """メッセージ内容のハッシュを生成"""
+ content = "".join([msg["content"] for msg in messages])
+ return hashlib.sha256(content.encode()).hexdigest()[:16]
+
+ def search_memories(self, query: str, limit: int = 10, use_ai_analysis: bool = True) -> List[Dict[str, Any]]:
+ """記憶を検索(AI分析結果も含む)"""
results = []
- # ChatGPTの記憶を検索
- for filepath in CHATGPT_MEMORY_DIR.glob("*.json"):
- try:
- with open(filepath, 'r', encoding='utf-8') as f:
- memory_data = json.load(f)
-
- # 簡単なキーワード検索
- search_text = f"{memory_data.get('title', '')} {memory_data.get('summary', '')}"
- for msg in memory_data.get('messages', []):
- search_text += f" {msg.get('content', '')}"
-
- if query.lower() in search_text.lower():
- results.append({
- "filepath": str(filepath),
- "title": memory_data.get("title"),
- "summary": memory_data.get("summary"),
- "source": memory_data.get("source"),
- "import_time": memory_data.get("import_time"),
- "message_count": len(memory_data.get("messages", []))
- })
+ # 処理済みメモリから検索
+ search_dirs = [PROCESSED_MEMORY_DIR, CHATGPT_MEMORY_DIR] if use_ai_analysis else [CHATGPT_MEMORY_DIR]
+
+ for search_dir in search_dirs:
+ for filepath in search_dir.glob("*.json"):
+ try:
+ with open(filepath, 'r', encoding='utf-8') as f:
+ memory_data = json.load(f)
- if len(results) >= limit:
- break
+ # 検索対象テキストを構築
+ search_text = f"{memory_data.get('title', '')} {memory_data.get('basic_summary', '')}"
+
+ # AI分析結果も検索対象に含める
+ if memory_data.get('ai_analysis'):
+ ai_analysis = memory_data['ai_analysis']
+ search_text += f" {' '.join(ai_analysis.get('main_topics', []))}"
+ search_text += f" {ai_analysis.get('summary', '')}"
+ search_text += f" {' '.join(ai_analysis.get('key_insights', []))}"
+
+ # メッセージ内容も検索対象に含める
+ for msg in memory_data.get('messages', []):
+ search_text += f" {msg.get('content', '')}"
+
+ if query.lower() in search_text.lower():
+ result = {
+ "filepath": str(filepath),
+ "title": memory_data.get("title"),
+ "basic_summary": memory_data.get("basic_summary"),
+ "source": memory_data.get("source"),
+ "import_time": memory_data.get("import_time"),
+ "message_count": len(memory_data.get("messages", [])),
+ "has_ai_analysis": bool(memory_data.get("ai_analysis"))
+ }
- except Exception as e:
- print(f"Error reading memory file {filepath}: {e}")
- continue
+ if memory_data.get('ai_analysis'):
+ result["ai_summary"] = memory_data['ai_analysis'].get('summary', '')
+ result["main_topics"] = memory_data['ai_analysis'].get('main_topics', [])
+
+ results.append(result)
+
+ if len(results) >= limit:
+ break
+
+ except Exception as e:
+ print(f"Error reading memory file {filepath}: {e}")
+ continue
+
+ if len(results) >= limit:
+ break
return results
@@ -190,14 +475,21 @@ class MemoryManager:
with open(filepath, 'r', encoding='utf-8') as f:
memory_data = json.load(f)
- memories.append({
+ memory_info = {
"filepath": str(filepath),
"title": memory_data.get("title"),
- "summary": memory_data.get("summary"),
+ "basic_summary": memory_data.get("basic_summary"),
"source": memory_data.get("source"),
"import_time": memory_data.get("import_time"),
- "message_count": len(memory_data.get("messages", []))
- })
+ "message_count": len(memory_data.get("messages", [])),
+ "has_ai_analysis": bool(memory_data.get("ai_analysis"))
+ }
+
+ if memory_data.get('ai_analysis'):
+ memory_info["ai_summary"] = memory_data['ai_analysis'].get('summary', '')
+ memory_info["main_topics"] = memory_data['ai_analysis'].get('main_topics', [])
+
+ memories.append(memory_info)
except Exception as e:
print(f"Error reading memory file {filepath}: {e}")
continue
@@ -207,22 +499,57 @@ class MemoryManager:
return memories
# FastAPI アプリケーション
-app = FastAPI(title="AigptMCP Server with Memory", version="1.0.0")
+app = FastAPI(title="AigptMCP Server with AI Memory", version="2.0.0")
memory_manager = MemoryManager()
@app.post("/memory/import/chatgpt")
-async def import_chatgpt_conversation(data: ConversationImport):
- """ChatGPTの会話をインポート"""
+async def import_chatgpt_conversation(data: ConversationImport, process_with_ai: bool = True):
+ """ChatGPTの会話をインポート(AI処理オプション付き)"""
try:
- filepath = memory_manager.save_chatgpt_memory(data.conversation_data)
+ filepath = await memory_manager.save_chatgpt_memory(data.conversation_data, process_with_ai)
return {
"success": True,
"message": "Conversation imported successfully",
- "filepath": filepath
+ "filepath": filepath,
+ "ai_processed": process_with_ai
}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
+@app.post("/memory/process-ai")
+async def process_memory_with_ai(data: MemorySummaryRequest):
+ """既存の記憶をAIで再処理"""
+ try:
+ # 既存記憶を読み込み
+ memory_data = memory_manager.get_memory_detail(data.filepath)
+
+ # AI分析を実行
+ ai_analysis = await memory_manager.ai_processor.generate_ai_summary(
+ memory_data["messages"],
+ data.ai_provider
+ )
+
+ # データを更新
+ memory_data["ai_analysis"] = ai_analysis
+ memory_data["ai_processed_at"] = datetime.now().isoformat()
+
+ # ファイルを更新
+ with open(data.filepath, 'w', encoding='utf-8') as f:
+ json.dump(memory_data, f, ensure_ascii=False, indent=2)
+
+ # 処理済みディレクトリにもコピー
+ processed_filepath = PROCESSED_MEMORY_DIR / Path(data.filepath).name
+ with open(processed_filepath, 'w', encoding='utf-8') as f:
+ json.dump(memory_data, f, ensure_ascii=False, indent=2)
+
+ return {
+ "success": True,
+ "message": "Memory processed with AI successfully",
+ "ai_analysis": ai_analysis
+ }
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
@app.post("/memory/search")
async def search_memories(query: MemoryQuery):
"""記憶を検索"""
@@ -261,9 +588,52 @@ async def get_memory_detail(filepath: str):
except Exception as e:
raise HTTPException(status_code=404, detail=str(e))
+@app.post("/relationship/update")
+async def update_relationship(data: RelationshipUpdate):
+ """関係性を更新"""
+ try:
+ new_score = memory_manager.relationship_tracker.update_relationship(
+ data.target, data.interaction_type, data.weight, data.context
+ )
+ return {
+ "success": True,
+ "new_score": new_score,
+ "can_send_message": memory_manager.relationship_tracker.should_send_message(data.target)
+ }
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
+@app.get("/relationship/list")
+async def list_relationships():
+ """すべての関係性をリスト"""
+ try:
+ relationships = memory_manager.relationship_tracker.get_all_relationships()
+ return {
+ "success": True,
+ "relationships": relationships
+ }
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
+@app.get("/relationship/check")
+async def check_send_permission(target: str, threshold: float = 50.0):
+ """メッセージ送信可否をチェック"""
+ try:
+ score = memory_manager.relationship_tracker.get_relationship_score(target)
+ can_send = memory_manager.relationship_tracker.should_send_message(target, threshold)
+ return {
+ "success": True,
+ "target": target,
+ "score": score,
+ "can_send_message": can_send,
+ "threshold": threshold
+ }
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
@app.post("/chat")
async def chat_endpoint(data: ChatMessage):
- """チャット機能(記憶を活用)"""
+ """チャット機能(記憶と関係性を活用)"""
try:
# 関連する記憶を検索
memories = memory_manager.search_memories(data.message, limit=3)
@@ -273,9 +643,14 @@ async def chat_endpoint(data: ChatMessage):
if memories:
memory_context = "\n# Related memories:\n"
for memory in memories:
- memory_context += f"- {memory['title']}: {memory['summary']}\n"
+ memory_context += f"- {memory['title']}: {memory.get('ai_summary', memory.get('basic_summary', ''))}\n"
+ if memory.get('main_topics'):
+ memory_context += f" Topics: {', '.join(memory['main_topics'])}\n"
- # 実際のチャット処理(他のプロバイダーに転送)
+ # 関係性情報を取得
+ relationships = memory_manager.relationship_tracker.get_all_relationships()
+
+ # 実際のチャット処理
enhanced_message = data.message
if memory_context:
enhanced_message = f"{data.message}\n\n{memory_context}"
@@ -283,7 +658,12 @@ async def chat_endpoint(data: ChatMessage):
return {
"success": True,
"response": f"Enhanced response with memory context: {enhanced_message}",
- "memories_used": len(memories)
+ "memories_used": len(memories),
+ "relationship_info": {
+ "active_relationships": len(relationships.get("targets", {})),
+ "can_initiate_conversations": sum(1 for target, data in relationships.get("targets", {}).items()
+ if memory_manager.relationship_tracker.should_send_message(target))
+ }
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@@ -292,19 +672,32 @@ async def chat_endpoint(data: ChatMessage):
async def root():
"""ヘルスチェック"""
return {
- "service": "AigptMCP Server with Memory",
+ "service": "AigptMCP Server with AI Memory",
+ "version": "2.0.0",
"status": "running",
"memory_dir": str(MEMORY_DIR),
+ "features": [
+ "AI-powered memory analysis",
+ "Relationship tracking",
+ "Advanced memory search",
+ "Conversation import",
+ "Auto-summary generation"
+ ],
"endpoints": [
"/memory/import/chatgpt",
+ "/memory/process-ai",
"/memory/search",
"/memory/list",
"/memory/detail",
+ "/relationship/update",
+ "/relationship/list",
+ "/relationship/check",
"/chat"
]
}
if __name__ == "__main__":
- print("🚀 AigptMCP Server with Memory starting...")
+ print("🚀 AigptMCP Server with AI Memory starting...")
print(f"📁 Memory directory: {MEMORY_DIR}")
+ print(f"🧠 AI Memory processing: {'✅ Enabled' if os.getenv('OPENAI_API_KEY') or os.getenv('ANTHROPIC_API_KEY') else '❌ Disabled (no API keys)'}")
uvicorn.run(app, host="127.0.0.1", port=5000)
diff --git a/readme.md b/readme.md
index 07111e2..2a5b6b9 100644
--- a/readme.md
+++ b/readme.md
@@ -1,130 +1,27 @@
-Memory-Enhanced MCP Server 使用ガイド
-概要
-このMCPサーバーは、ChatGPTの会話履歴を記憶として保存し、AIとの対話で活用できる機能を提供します。
+# ai `gpt`
-セットアップ
-1. 依存関係のインストール
-bash
-pip install -r requirements.txt
-2. サーバーの起動
-bash
-python mcp/server.py
-サーバーは http://localhost:5000 で起動します。
+自発的送信AI
-使用方法
-1. ChatGPTの会話履歴をインポート
-ChatGPTから会話をエクスポートし、JSONファイルとして保存してください。
+## 🎯 目的・目標(Purpose & Goal)
+- 人格を持つAIが、関係性に応じて自発的にメッセージを送信する仕組みをつくる。
+- 関係性や記憶を不可逆に記録・反映し、唯一性ある人格を構成する。
+- 送信の可否、送信のタイミング、送信内容はAIの関係性パラメータに基づいて決定する。
-bash
-# 単一ファイルをインポート
-python mcp/memory_client.py import your_chatgpt_export.json
+## 🧠 中核設計(Core Concepts)
+- **人格**:記憶(過去の発話)と関係性(他者とのつながり)のパラメータで構成
+- **唯一性**:変更不可、不可逆。関係性が壊れたら修復不可能。
+- **送信条件**:関係性パラメータが一定閾値を超えると「送信」が解禁される
-# インポート結果の例
-✅ Imported 5/5 conversations
-2. 記憶の検索
-bash
-# キーワードで記憶を検索
-python mcp/memory_client.py search "プログラミング"
+## 🔩 技術仕様(Technical Specs)
+- 言語:python, rust, mcp
+- ストレージ:json or sqliteで記憶管理(バージョンで選択)
+- 関係性パラメータ:数値化された評価 + 減衰(時間) + 環境要因(ステージ)
+- 記憶圧縮:ベクトル要約 + ハッシュ保存
+- rustのcli(clap)でインターフェイスを作成
+- fastapi_mcpでserverを立て、AIがそれを利用する形式
-# 検索結果の例
-🔍 Searching for: プログラミング
-📚 Found 3 memories:
- • Pythonの基礎学習
- Summary: Conversation with 10 user messages and 8 assistant responses...
- Messages: 18
-3. 記憶一覧の表示
-bash
-python mcp/memory_client.py list
-
-# 結果の例
-📋 Listing all memories...
-📚 Total memories: 15
- • day
- Source: chatgpt
- Messages: 2
- Imported: 2025-01-21T10:30:45.123456
-4. 記憶の詳細表示
-bash
-python mcp/memory_client.py detail "/path/to/memory/file.json"
-
-# 結果の例
-📄 Getting details for: /path/to/memory/file.json
-Title: day
-Source: chatgpt
-Summary: Conversation with 1 user messages and 1 assistant responses...
-Messages: 2
-
-Recent messages:
- user: こんにちは...
- assistant: こんにちは〜!✨...
-5. 記憶を活用したチャット
-bash
-python mcp/memory_client.py chat "Pythonについて教えて"
-
-# 結果の例
-💬 Chatting with memory: Pythonについて教えて
-🤖 Response: Enhanced response with memory context...
-📚 Memories used: 2
-API エンドポイント
-POST /memory/import/chatgpt
-ChatGPTの会話履歴をインポート
-
-json
-{
- "conversation_data": { ... }
-}
-POST /memory/search
-記憶を検索
-
-json
-{
- "query": "検索キーワード",
- "limit": 10
-}
-GET /memory/list
-すべての記憶をリスト
-
-GET /memory/detail?filepath=/path/to/file
-記憶の詳細を取得
-
-POST /chat
-記憶を活用したチャット
-
-json
-{
- "message": "メッセージ",
- "model": "model_name"
-}
-記憶の保存場所
-記憶は以下のディレクトリに保存されます:
-
-~/.config/aigpt/memory/chatgpt/
-各会話は個別のJSONファイルとして保存され、以下の情報を含みます:
-
-タイトル
-インポート時刻
-メッセージ履歴
-自動生成された要約
-メタデータ
-ChatGPTの会話エクスポート方法
-ChatGPTの設定画面を開く
-"Data controls" → "Export data" を選択
-エクスポートファイルをダウンロード
-conversations.json ファイルを使用
-拡張可能な機能
-高度な検索: ベクトル検索やセマンティック検索の実装
-要約生成: AIによる自動要約の改善
-記憶の分類: カテゴリやタグによる分類
-記憶の統合: 複数の会話からの知識統合
-プライバシー保護: 機密情報の自動検出・マスキング
-トラブルシューティング
-サーバーが起動しない
-ポート5000が使用中でないか確認
-依存関係が正しくインストールされているか確認
-インポートに失敗する
-JSONファイルが正しい形式か確認
-ファイルパスが正しいか確認
-ファイルの権限を確認
-検索結果が表示されない
-インポートが正常に完了しているか確認
-検索キーワードを変更して試行
+## 📦 主要構成要素(Components)
+- `MemoryManager`: 発言履歴・記憶圧縮管理
+- `RelationshipTracker`: 関係性スコアの蓄積と判定
+- `TransmissionController`: 閾値判定&送信トリガー
+- `Persona`: 上記すべてを統括する人格モジュール