""" 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/", 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/", 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/", 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)