This commit is contained in:
syui 2025-05-23 15:07:48 +09:00
parent d57c4b10c7
commit 0ee4739aef
Signed by: syui
GPG Key ID: 5417CFEBAD92DF56
3 changed files with 175 additions and 34 deletions

View File

@ -2,8 +2,37 @@
import sys
import json
import requests
from datetime import datetime
from config import load_config
from datetime import datetime, timezone
def build_payload_openai(cfg, message: str):
return {
"model": cfg["model"],
"tools": [
{
"type": "function",
"function": {
"name": "ask_message",
"description": "過去の記憶を検索します",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "検索したい語句"
}
},
"required": ["query"]
}
}
}
],
"tool_choice": "auto",
"messages": [
{"role": "system", "content": "あなたは親しみやすいAIで、必要に応じて記憶から情報を検索して応答します。"},
{"role": "user", "content": message}
]
}
def build_payload_mcp(message: str):
return {
@ -30,15 +59,73 @@ def call_mcp(cfg, message: str):
response.raise_for_status()
return response.json().get("output", {}).get("response", "❓ 応答が取得できませんでした")
#def call_openai(cfg, message: str):
# payload = build_payload_openai(cfg, message)
# headers = {
# "Authorization": f"Bearer {cfg['api_key']}",
# "Content-Type": "application/json",
# }
# response = requests.post(cfg["url"], headers=headers, json=payload)
# response.raise_for_status()
# return response.json()["choices"][0]["message"]["content"]
def call_openai(cfg, message: str):
payload = build_payload_openai(cfg, message)
tools = [
{
"type": "function",
"function": {
"name": "memory", # MCPツール名と一致させる
"description": "AIが記憶ログを参照するツールです",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "探している記憶に関するキーワードや質問"
}
},
"required": ["query"]
}
}
}
]
payload = {
"model": cfg["model"],
"messages": [
{"role": "system", "content": "あなたはAIで、必要に応じて記憶検索ツールmemoryを使って過去の会話を参照することができます。"},
{"role": "user", "content": message}
],
"temperature": 0.7,
"tool_choice": "auto", # AIが自律的にツールを選ぶ
"tools": tools
}
headers = {
"Authorization": f"Bearer {cfg['api_key']}",
"Content-Type": "application/json",
}
response = requests.post(cfg["url"], headers=headers, json=payload)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
result = response.json()
# AIがtool_callしたかチェック
if "tool_calls" in result["choices"][0]["message"]:
tool_call = result["choices"][0]["message"]["tool_calls"][0]
if tool_call["function"]["name"] == "memory":
args = json.loads(tool_call["function"]["arguments"])
query = args.get("query", "")
# ここでMCP serverにPOSTする
memory_response = requests.post(
"http://127.0.0.1:5000/memory/search", # あらかじめ実装されたmemory検索用API
json={"query": query}
).json()
return f"[Memory Tool]: {memory_response.get('result', 'なし')}"
# 通常のテキスト応答
return result["choices"][0]["message"]["content"]
def main():
if len(sys.argv) < 2:
@ -79,7 +166,7 @@ def save_log(user_msg, ai_msg):
else:
logs = []
now = datetime.utcnow().isoformat() + "Z"
now = datetime.now(timezone.utc).isoformat()
logs.append({"timestamp": now, "sender": "user", "message": user_msg})
logs.append({"timestamp": now, "sender": "ai", "message": ai_msg})

View File

@ -1,37 +1,74 @@
# scripts/memory_store.py
from pathlib import Path
import json
from datetime import datetime
MEMORY_DIR = Path.home() / ".config" / "aigpt" / "memory"
MEMORY_DIR.mkdir(parents=True, exist_ok=True)
def get_today_path():
today = datetime.utcnow().strftime("%Y-%m-%d")
return MEMORY_DIR / f"{today}.json"
def save_message(sender: str, message: str):
entry = {
"timestamp": datetime.utcnow().isoformat(),
"sender": sender,
"message": message
}
path = get_today_path()
data = []
from pathlib import Path
from config import MEMORY_DIR
from datetime import datetime, timezone
def load_logs(date_str=None):
if date_str is None:
date_str = datetime.now().strftime("%Y-%m-%d")
path = MEMORY_DIR / f"{date_str}.json"
if path.exists():
with open(path, "r") as f:
data = json.load(f)
data.append(entry)
with open(path, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
def load_messages():
path = get_today_path()
if not path.exists():
return json.load(f)
return []
def save_message(sender, message):
date_str = datetime.now().strftime("%Y-%m-%d")
path = MEMORY_DIR / f"{date_str}.json"
logs = load_logs(date_str)
now = datetime.now(timezone.utc).isoformat()
logs.append({"timestamp": now, "sender": sender, "message": message})
with open(path, "w") as f:
json.dump(logs, f, indent=2, ensure_ascii=False)
def search_memory(query: str):
from glob import glob
all_logs = []
for file_path in sorted(MEMORY_DIR.glob("*.json")):
with open(file_path, "r") as f:
logs = json.load(f)
matched = [entry for entry in logs if query in entry["message"]]
all_logs.extend(matched)
return all_logs[-5:] # 最新5件だけ返す
# scripts/memory_store.py
import json
from datetime import datetime
from pathlib import Path
from config import MEMORY_DIR
# ログを読み込む(指定日または当日)
def load_logs(date_str=None):
if date_str is None:
date_str = datetime.now().strftime("%Y-%m-%d")
path = MEMORY_DIR / f"{date_str}.json"
if path.exists():
with open(path, "r") as f:
return json.load(f)
return []
# メッセージを保存する
def save_message(sender, message):
date_str = datetime.now().strftime("%Y-%m-%d")
path = MEMORY_DIR / f"{date_str}.json"
logs = load_logs(date_str)
#now = datetime.utcnow().isoformat() + "Z"
now = datetime.now(timezone.utc).isoformat()
logs.append({"timestamp": now, "sender": sender, "message": message})
with open(path, "w") as f:
json.dump(logs, f, indent=2, ensure_ascii=False)
# キーワードで過去のメモリを検索する最新5件を返す
def search_memory(query: str):
all_logs = []
for file_path in sorted(MEMORY_DIR.glob("*.json")):
try:
with open(file_path, "r") as f:
logs = json.load(f)
matched = [entry for entry in logs if query.lower() in entry["message"].lower()]
all_logs.extend(matched)
except Exception as e:
print(f"⚠️ 読み込み失敗: {file_path} ({e})")
return all_logs[-5:] # 最新5件を返す

View File

@ -2,7 +2,8 @@
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
from pydantic import BaseModel
from memory_store import save_message, load_messages
#from memory_store import save_message, load_messages, search_memory
from memory_store import save_message, load_logs, search_memory
app = FastAPI()
mcp = FastApiMCP(app, name="aigpt-agent", description="MCP Server for AI memory")
@ -15,6 +16,9 @@ class MemoryInput(BaseModel):
sender: str
message: str
class MemoryQuery(BaseModel):
query: str
# --- ツール(エンドポイント)定義 ---
@app.post("/chat", operation_id="chat")
async def chat(input: ChatInput):
@ -32,6 +36,19 @@ async def memory_post(input: MemoryInput):
async def memory_get():
return {"messages": load_messages()}
@app.post("/ask_message", operation_id="ask_message")
async def ask_message(input: MemoryQuery):
results = search_memory(input.query)
return {
"response": f"🔎 記憶から {len(results)} 件ヒット:\n" + "\n".join([f"{r['sender']}: {r['message']}" for r in results])
}
@app.post("/memory/search", operation_id="memory")
async def search_memory(input: dict):
query = input.get("query", "")
# 適当なキーワード検索ロジックを追加(例: logs.jsonを検索
return {"result": f"記憶の中から「{query}」に関するデータを返しました"}
# --- MCP 初期化 ---
mcp.mount()