Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,888 changes: 125 additions & 3,763 deletions README.md
100755 β†’ 100644

Large diffs are not rendered by default.

74 changes: 69 additions & 5 deletions install.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,70 @@
#!/bin/bash
# This script is used to install the app dependencies and run the app using the virtual environment
python -m venv ./venv
source ./venv/bin/activate
pip install -r requirements.txt
python3 run.py "$@"
# PyGPT Enhanced - Install Script
# Installs Avatar RPM plugin + MCP Memory Server

set -e

COLOR_GREEN='\033[0;32m'
COLOR_YELLOW='\033[1;33m'
COLOR_BLUE='\033[0;34m'
COLOR_RED='\033[0;31m'
NC='\033[0m'

echo -e "${COLOR_BLUE}"
echo " ____ ____ ____ _____ _____ _"
echo " | _ \ _ _/ ___| _ \_ _| | ____|_ __ | |__ __ _ _ __ ___ ___ __| |"
echo " | |_) | | | | | | |_) || | | _| | '_ \| '_ \ / _' | '_ \ / __/ _ \/ _' |"
echo " | __/| |_| | |__| __/ | | | |___| | | | | | | (_| | | | | (_| __/ (_| |"
echo " |_| \__, |\____|_| |_| |_____|_| |_|_| |_|\__,_|_| |_|\___\___|\__,_|"
echo " |___/"
echo -e "${NC}"
echo -e "${COLOR_GREEN}Avatar RPM + MCP Memory Cloud for PyGPT${NC}"
echo ""

# 1. Check Python
if ! command -v python3 &> /dev/null; then
echo -e "${COLOR_RED}Python3 not found. Please install Python 3.10+${NC}"
exit 1
fi

PY_VERSION=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")
echo -e "${COLOR_GREEN}Python $PY_VERSION detected${NC}"

# 2. Install MCP Memory Server deps
echo -e "\n${COLOR_YELLOW}Installing MCP Memory Server dependencies...${NC}"
pip3 install firebase-admin sentence-transformers numpy textblob

# 3. Install Avatar RPM deps
echo -e "\n${COLOR_YELLOW}Installing Avatar RPM dependencies...${NC}"
pip3 install textblob numpy

# 4. Copy plugins to PyGPT
PYGPT_PLUGIN_DIR="src/pygpt_net/plugin"

if [ -d "$PYGPT_PLUGIN_DIR" ]; then
echo -e "\n${COLOR_YELLOW}Copying plugins to PyGPT...${NC}"
cp -r src/pygpt_net/plugin/avatar_rpm "$PYGPT_PLUGIN_DIR/"
cp -r src/pygpt_net/plugin/mcp_memory "$PYGPT_PLUGIN_DIR/"
echo -e "${COLOR_GREEN}Plugins installed!${NC}"
else
echo -e "${COLOR_YELLOW}PyGPT directory not found at $PYGPT_PLUGIN_DIR"
echo -e "Copy plugins manually from src/pygpt_net/plugin/ to your PyGPT installation${NC}"
fi

# 5. Config example
echo -e "\n${COLOR_YELLOW}Creating config from example...${NC}"
if [ ! -f "mcp-memory-server/config.json" ]; then
cp mcp-memory-server/config.example.json mcp-memory-server/config.json
echo -e "${COLOR_GREEN}Config created at mcp-memory-server/config.json${NC}"
echo -e "${COLOR_YELLOW}Edit it with your Firebase credentials!${NC}"
fi

echo -e "\n${COLOR_GREEN}Installation complete!${NC}"
echo ""
echo "Next steps:"
echo " 1. Create Firebase project at https://console.firebase.google.com"
echo " 2. Download service account JSON"
echo " 3. Edit mcp-memory-server/config.json"
echo " 4. Create RPM avatar at https://demo.readyplayer.me/avatar"
echo " 5. Open PyGPT > Plugins > Enable 'Avatar RPM' + 'Memory Cloud'"
echo ""
Empty file added mcp-memory-server/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions mcp-memory-server/config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"firebase": {
"project_id": "your-firebase-project-id",
"credentials_path": "/path/to/serviceAccountKey.json"
},
"memory": {
"user_id": "default",
"embedding_model": "local",
"ttl_days": 90
},
"server": {
"transport": "stdio",
"port": 8080
}
}
Empty file.
112 changes: 112 additions & 0 deletions mcp-memory-server/firebase/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
"""
Firebase Firestore client wrapper.
Handles connection, CRUD and queries for memory storage.
"""
import os
from datetime import datetime, timezone
from typing import Optional, List, Dict, Any

try:
import firebase_admin
from firebase_admin import credentials, firestore
FIREBASE_AVAILABLE = True
except ImportError:
FIREBASE_AVAILABLE = False


class FirebaseClient:
def __init__(self, project_id: str, credentials_path: str):
self.project_id = project_id
self.credentials_path = credentials_path
self.db = None
self._connect()

def _connect(self):
if not FIREBASE_AVAILABLE:
print("[MCP Memory] firebase-admin not installed. Run: pip install firebase-admin",
flush=True)
return
if not self.project_id or not self.credentials_path:
print("[MCP Memory] Firebase credentials not configured.", flush=True)
return
try:
if not firebase_admin._apps:
cred = credentials.Certificate(self.credentials_path)
firebase_admin.initialize_app(cred, {"projectId": self.project_id})
self.db = firestore.client()
print(f"[MCP Memory] Connected to Firebase project: {self.project_id}", flush=True)
except Exception as e:
print(f"[MCP Memory] Firebase connection error: {e}", flush=True)

def is_connected(self) -> bool:
return self.db is not None

# ---- Memory CRUD ----

def save_memory(self, user_id: str, memory: Dict[str, Any]) -> str:
"""Save a memory document. Returns the document ID."""
if not self.is_connected():
return "offline"
memory["created_at"] = datetime.now(timezone.utc)
memory["updated_at"] = datetime.now(timezone.utc)
ref = self.db.collection("users").document(user_id).collection("memory").add(memory)
return ref[1].id

def get_memories(self, user_id: str, category: Optional[str] = None,
limit: int = 20) -> List[Dict]:
"""Retrieve memories, optionally filtered by category."""
if not self.is_connected():
return []
ref = self.db.collection("users").document(user_id).collection("memory")
if category:
ref = ref.where("category", "==", category)
ref = ref.order_by("importance", direction=firestore.Query.DESCENDING).limit(limit)
return [{"id": doc.id, **doc.to_dict()} for doc in ref.stream()]

def search_memories_by_tag(self, user_id: str, tags: List[str]) -> List[Dict]:
"""Search memories by tags."""
if not self.is_connected():
return []
ref = (self.db.collection("users").document(user_id)
.collection("memory")
.where("tags", "array_contains_any", tags)
.limit(10))
return [{"id": doc.id, **doc.to_dict()} for doc in ref.stream()]

def save_conversation(self, user_id: str, conv: Dict[str, Any]) -> str:
"""Save a conversation summary."""
if not self.is_connected():
return "offline"
conv["timestamp"] = datetime.now(timezone.utc)
ref = (self.db.collection("users").document(user_id)
.collection("conversations").add(conv))
return ref[1].id

def get_recent_conversations(self, user_id: str, limit: int = 10) -> List[Dict]:
"""Get most recent conversations."""
if not self.is_connected():
return []
ref = (self.db.collection("users").document(user_id)
.collection("conversations")
.order_by("timestamp", direction=firestore.Query.DESCENDING)
.limit(limit))
return [{"id": doc.id, **doc.to_dict()} for doc in ref.stream()]

def update_device_sync(self, user_id: str, device_id: str, state: Dict) -> None:
"""Update sync state for a device."""
if not self.is_connected():
return
(self.db.collection("users").document(user_id)
.collection("devices").document(device_id).set({
**state,
"last_seen": datetime.now(timezone.utc)
}, merge=True))

def get_all_device_states(self, user_id: str) -> List[Dict]:
"""Get sync state of all known devices."""
if not self.is_connected():
return []
ref = (self.db.collection("users").document(user_id)
.collection("devices"))
return [{"device_id": doc.id, **doc.to_dict()} for doc in ref.stream()]
4 changes: 4 additions & 0 deletions mcp-memory-server/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
firebase-admin>=6.0.0
sentence-transformers>=2.2.0
numpy>=1.24.0
textblob>=0.17.0
Loading