fix mcp
This commit is contained in:
parent
d57c4b10c7
commit
0ee4739aef
@ -2,8 +2,37 @@
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
from datetime import datetime
|
|
||||||
from config import load_config
|
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):
|
def build_payload_mcp(message: str):
|
||||||
return {
|
return {
|
||||||
@ -30,15 +59,73 @@ def call_mcp(cfg, message: str):
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json().get("output", {}).get("response", "❓ 応答が取得できませんでした")
|
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):
|
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 = {
|
headers = {
|
||||||
"Authorization": f"Bearer {cfg['api_key']}",
|
"Authorization": f"Bearer {cfg['api_key']}",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
||||||
response = requests.post(cfg["url"], headers=headers, json=payload)
|
response = requests.post(cfg["url"], headers=headers, json=payload)
|
||||||
response.raise_for_status()
|
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():
|
def main():
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
@ -79,7 +166,7 @@ def save_log(user_msg, ai_msg):
|
|||||||
else:
|
else:
|
||||||
logs = []
|
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": "user", "message": user_msg})
|
||||||
logs.append({"timestamp": now, "sender": "ai", "message": ai_msg})
|
logs.append({"timestamp": now, "sender": "ai", "message": ai_msg})
|
||||||
|
|
||||||
|
@ -1,37 +1,74 @@
|
|||||||
# scripts/memory_store.py
|
# scripts/memory_store.py
|
||||||
from pathlib import Path
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from pathlib import Path
|
||||||
|
from config import MEMORY_DIR
|
||||||
MEMORY_DIR = Path.home() / ".config" / "aigpt" / "memory"
|
from datetime import datetime, timezone
|
||||||
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 = []
|
|
||||||
|
|
||||||
|
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():
|
if path.exists():
|
||||||
with open(path, "r") as f:
|
with open(path, "r") as f:
|
||||||
data = json.load(f)
|
return 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 []
|
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:
|
with open(path, "r") as f:
|
||||||
return json.load(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件を返す
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi_mcp import FastApiMCP
|
from fastapi_mcp import FastApiMCP
|
||||||
from pydantic import BaseModel
|
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()
|
app = FastAPI()
|
||||||
mcp = FastApiMCP(app, name="aigpt-agent", description="MCP Server for AI memory")
|
mcp = FastApiMCP(app, name="aigpt-agent", description="MCP Server for AI memory")
|
||||||
@ -15,6 +16,9 @@ class MemoryInput(BaseModel):
|
|||||||
sender: str
|
sender: str
|
||||||
message: str
|
message: str
|
||||||
|
|
||||||
|
class MemoryQuery(BaseModel):
|
||||||
|
query: str
|
||||||
|
|
||||||
# --- ツール(エンドポイント)定義 ---
|
# --- ツール(エンドポイント)定義 ---
|
||||||
@app.post("/chat", operation_id="chat")
|
@app.post("/chat", operation_id="chat")
|
||||||
async def chat(input: ChatInput):
|
async def chat(input: ChatInput):
|
||||||
@ -32,6 +36,19 @@ async def memory_post(input: MemoryInput):
|
|||||||
async def memory_get():
|
async def memory_get():
|
||||||
return {"messages": load_messages()}
|
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 初期化 ---
|
||||||
mcp.mount()
|
mcp.mount()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user