261 lines
6.9 KiB
Python
261 lines
6.9 KiB
Python
"""
|
|||
|
|
Journal Organizer Agent HTTP 服务器
|
||
|
|
|
||
|
|
提供 REST API 接口,供 Obsidian 插件调用
|
||
|
|
"""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import logging
|
||
|
|
from datetime import datetime
|
||
|
|
from typing import Dict, List, Any
|
||
|
|
from flask import Flask, request, jsonify
|
||
|
|
from flask_cors import CORS
|
||
|
|
from .conversation.conversational_agent import ConversationalAgent
|
||
|
|
from .config import Config
|
||
|
|
|
||
|
|
# 配置日志
|
||
|
|
logging.basicConfig(
|
||
|
|
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||
|
|
)
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
# 创建 Flask 应用
|
||
|
|
app = Flask(__name__)
|
||
|
|
CORS(app) # 启用 CORS 支持
|
||
|
|
|
||
|
|
# 初始化 Agent
|
||
|
|
config = Config()
|
||
|
|
agent = ConversationalAgent(config)
|
||
|
|
|
||
|
|
# 存储对话历史
|
||
|
|
conversations: Dict[str, List[Dict[str, Any]]] = {}
|
||
|
|
|
||
|
|
|
||
|
|
@app.route("/health", methods=["GET"])
|
||
|
|
def health_check():
|
||
|
|
"""
|
||
|
|
健康检查端点
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
JSON: { "status": "ok", "timestamp": "ISO 8601 时间戳" }
|
||
|
|
"""
|
||
|
|
return jsonify(
|
||
|
|
{"status": "ok", "timestamp": datetime.now().isoformat(), "agent": "ready"}
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@app.route("/api/chat", methods=["POST"])
|
||
|
|
def chat():
|
||
|
|
"""
|
||
|
|
对话端点
|
||
|
|
|
||
|
|
Request JSON:
|
||
|
|
{
|
||
|
|
"message": "用户消息",
|
||
|
|
"conversation_id": "对话 ID",
|
||
|
|
"timestamp": "ISO 8601 时间戳"
|
||
|
|
}
|
||
|
|
|
||
|
|
Response JSON:
|
||
|
|
{
|
||
|
|
"message": "Agent 响应",
|
||
|
|
"suggestions": ["建议1", "建议2"],
|
||
|
|
"status": "success|error|waiting_input",
|
||
|
|
"conversation_id": "对话 ID",
|
||
|
|
"timestamp": "ISO 8601 时间戳"
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
data = request.get_json()
|
||
|
|
|
||
|
|
if not data or "message" not in data:
|
||
|
|
return jsonify({"message": "错误:缺少 'message' 字段", "status": "error"}), 400
|
||
|
|
|
||
|
|
user_message = data["message"]
|
||
|
|
conversation_id = data.get("conversation_id", "default")
|
||
|
|
|
||
|
|
logger.info(f"[{conversation_id}] 用户消息: {user_message}")
|
||
|
|
|
||
|
|
# 初始化对话历史
|
||
|
|
if conversation_id not in conversations:
|
||
|
|
conversations[conversation_id] = []
|
||
|
|
|
||
|
|
# 添加用户消息到历史
|
||
|
|
conversations[conversation_id].append(
|
||
|
|
{
|
||
|
|
"role": "user",
|
||
|
|
"content": user_message,
|
||
|
|
"timestamp": datetime.now().isoformat(),
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
# 调用 Agent 处理消息
|
||
|
|
response = agent.process_message(
|
||
|
|
user_message, conversation_id, conversations[conversation_id]
|
||
|
|
)
|
||
|
|
|
||
|
|
# 添加 Agent 响应到历史
|
||
|
|
conversations[conversation_id].append(
|
||
|
|
{
|
||
|
|
"role": "assistant",
|
||
|
|
"content": response.get("message", ""),
|
||
|
|
"timestamp": datetime.now().isoformat(),
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
logger.info(f"[{conversation_id}] Agent 响应: {response['message'][:100]}...")
|
||
|
|
|
||
|
|
return jsonify(
|
||
|
|
{
|
||
|
|
"message": response.get("message", ""),
|
||
|
|
"suggestions": response.get("suggestions", []),
|
||
|
|
"status": response.get("status", "success"),
|
||
|
|
"conversation_id": conversation_id,
|
||
|
|
"timestamp": datetime.now().isoformat(),
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
logger.error(f"Chat 端点错误: {e}", exc_info=True)
|
||
|
|
return jsonify({"message": f"服务器错误: {str(e)}", "status": "error"}), 500
|
||
|
|
|
||
|
|
|
||
|
|
@app.route("/api/history/<conversation_id>", methods=["GET"])
|
||
|
|
def get_history(conversation_id: str):
|
||
|
|
"""
|
||
|
|
获取对话历史
|
||
|
|
|
||
|
|
Args:
|
||
|
|
conversation_id: 对话 ID
|
||
|
|
|
||
|
|
Response JSON:
|
||
|
|
{
|
||
|
|
"messages": [
|
||
|
|
{ "role": "user", "content": "...", "timestamp": "..." },
|
||
|
|
{ "role": "assistant", "content": "...", "timestamp": "..." }
|
||
|
|
],
|
||
|
|
"conversation_id": "对话 ID"
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
messages = conversations.get(conversation_id, [])
|
||
|
|
|
||
|
|
return jsonify(
|
||
|
|
{
|
||
|
|
"messages": messages,
|
||
|
|
"conversation_id": conversation_id,
|
||
|
|
"count": len(messages),
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
logger.error(f"获取历史错误: {e}")
|
||
|
|
return jsonify({"message": f"错误: {str(e)}", "status": "error"}), 500
|
||
|
|
|
||
|
|
|
||
|
|
@app.route("/api/history/<conversation_id>", methods=["DELETE"])
|
||
|
|
def clear_history(conversation_id: str):
|
||
|
|
"""
|
||
|
|
清除对话历史
|
||
|
|
|
||
|
|
Args:
|
||
|
|
conversation_id: 对话 ID
|
||
|
|
|
||
|
|
Response JSON:
|
||
|
|
{ "status": "success", "conversation_id": "对话 ID" }
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
if conversation_id in conversations:
|
||
|
|
del conversations[conversation_id]
|
||
|
|
|
||
|
|
logger.info(f"已清除对话历史: {conversation_id}")
|
||
|
|
|
||
|
|
return jsonify({"status": "success", "conversation_id": conversation_id})
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
logger.error(f"清除历史错误: {e}")
|
||
|
|
return jsonify({"message": f"错误: {str(e)}", "status": "error"}), 500
|
||
|
|
|
||
|
|
|
||
|
|
@app.route("/api/suggestions/<conversation_id>", methods=["GET"])
|
||
|
|
def get_suggestions(conversation_id: str):
|
||
|
|
"""
|
||
|
|
获取建议
|
||
|
|
|
||
|
|
Args:
|
||
|
|
conversation_id: 对话 ID
|
||
|
|
|
||
|
|
Response JSON:
|
||
|
|
{
|
||
|
|
"suggestions": ["建议1", "建议2"],
|
||
|
|
"conversation_id": "对话 ID"
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
history = conversations.get(conversation_id, [])
|
||
|
|
|
||
|
|
# 调用 Agent 生成建议
|
||
|
|
suggestions = agent.generate_suggestions(history)
|
||
|
|
|
||
|
|
return jsonify({"suggestions": suggestions, "conversation_id": conversation_id})
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
logger.error(f"获取建议错误: {e}")
|
||
|
|
return jsonify({"suggestions": [], "status": "error"}), 500
|
||
|
|
|
||
|
|
|
||
|
|
@app.route("/api/status", methods=["GET"])
|
||
|
|
def get_status():
|
||
|
|
"""
|
||
|
|
获取 Agent 状态
|
||
|
|
|
||
|
|
Response JSON:
|
||
|
|
{
|
||
|
|
"status": "ready",
|
||
|
|
"conversations": 对话数量,
|
||
|
|
"uptime": "运行时间",
|
||
|
|
"version": "版本号"
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
return jsonify(
|
||
|
|
{
|
||
|
|
"status": "ready",
|
||
|
|
"conversations": len(conversations),
|
||
|
|
"timestamp": datetime.now().isoformat(),
|
||
|
|
"version": "1.0.0",
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@app.errorhandler(404)
|
||
|
|
def not_found(error):
|
||
|
|
"""处理 404 错误"""
|
||
|
|
return jsonify({"message": "端点不存在", "status": "error"}), 404
|
||
|
|
|
||
|
|
|
||
|
|
@app.errorhandler(500)
|
||
|
|
def internal_error(error):
|
||
|
|
"""处理 500 错误"""
|
||
|
|
logger.error(f"内部服务器错误: {error}")
|
||
|
|
return jsonify({"message": "内部服务器错误", "status": "error"}), 500
|
||
|
|
|
||
|
|
|
||
|
|
def run_server(host: str = "0.0.0.0", port: int = 5000, debug: bool = False):
|
||
|
|
"""
|
||
|
|
启动 HTTP 服务器
|
||
|
|
|
||
|
|
Args:
|
||
|
|
host: 绑定的主机地址
|
||
|
|
port: 绑定的端口
|
||
|
|
debug: 是否启用调试模式
|
||
|
|
"""
|
||
|
|
logger.info(f"启动 Journal Organizer Agent 服务器...")
|
||
|
|
logger.info(f"监听地址: {host}:{port}")
|
||
|
|
logger.info(f"调试模式: {debug}")
|
||
|
|
|
||
|
|
app.run(host=host, port=port, debug=debug, threaded=True)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
run_server(debug=True)
|