semantic_logic_server.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. 语义逻辑审查 — 前端测试服务器
  5. 提供独立HTTP API,直接调用 SemanticLogicReviewer,无需文件上传流程
  6. """
  7. import sys
  8. import os
  9. import json
  10. import time
  11. import asyncio
  12. import threading
  13. from http.server import HTTPServer, SimpleHTTPRequestHandler
  14. from urllib.parse import parse_qs, urlparse
  15. # 添加项目根目录到路径
  16. PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  17. sys.path.insert(0, PROJECT_ROOT)
  18. os.chdir(PROJECT_ROOT)
  19. from foundation.observability.logger.loggering import review_logger as logger
  20. from core.construction_review.component.reviewers.semantic_logic import SemanticLogicReviewer
  21. # ─── 异步工具 ──────────────────────────────────────────────────────────────────
  22. def run_async(coro):
  23. """在同步上下文中运行异步协程"""
  24. try:
  25. loop = asyncio.get_running_loop()
  26. import concurrent.futures
  27. with concurrent.futures.ThreadPoolExecutor() as executor:
  28. future = executor.submit(asyncio.run, coro)
  29. return future.result()
  30. except RuntimeError:
  31. return asyncio.run(coro)
  32. # ─── 审查逻辑 ──────────────────────────────────────────────────────────────────
  33. async def do_semantic_logic_check(review_content: str) -> dict:
  34. """
  35. 执行语义逻辑审查
  36. 直接调用 SemanticLogicReviewer.check_semantic_logic
  37. """
  38. trace_id = f"semantic_logic_web_{int(time.time() * 1000)}"
  39. reviewer = SemanticLogicReviewer()
  40. logger.info(f"[语义逻辑Web测试] trace_id={trace_id}, content_length={len(review_content)}")
  41. start = time.time()
  42. result = await reviewer.check_semantic_logic(
  43. trace_id=trace_id,
  44. review_content=review_content,
  45. state=None,
  46. stage_name=None,
  47. )
  48. wall_time = time.time() - start
  49. return {
  50. "trace_id": trace_id,
  51. "success": result.success,
  52. "details": result.details,
  53. "error_message": result.error_message,
  54. "model_execution_time": result.execution_time,
  55. "wall_time": round(wall_time, 3),
  56. "content_length": len(review_content),
  57. }
  58. # ─── HTTP Handler ──────────────────────────────────────────────────────────────
  59. class SemanticLogicHandler(SimpleHTTPRequestHandler):
  60. """HTTP请求处理器"""
  61. def do_GET(self):
  62. parsed = urlparse(self.path)
  63. if parsed.path == '/api/health':
  64. self.send_json_response({"status": "ok"})
  65. elif parsed.path in ('', '/', '/index.html'):
  66. # 返回前端页面
  67. index_path = os.path.join(os.path.dirname(__file__), 'index.html')
  68. self.serve_file(index_path, 'text/html')
  69. else:
  70. # 静态文件服务
  71. super().do_GET()
  72. def do_POST(self):
  73. parsed = urlparse(self.path)
  74. if parsed.path == '/api/semantic_logic':
  75. content_length = int(self.headers.get('Content-Length', 0))
  76. post_data = self.rfile.read(content_length)
  77. try:
  78. body = json.loads(post_data.decode('utf-8'))
  79. review_content = body.get('content', '')
  80. if not review_content:
  81. self.send_json_response({"error": "请提供 content 参数"}, 400)
  82. return
  83. print(f"\n[语义逻辑Web测试] 收到请求, content_length={len(review_content)}")
  84. result = run_async(do_semantic_logic_check(review_content))
  85. print(f"[语义逻辑Web测试] 完成, success={result['success']}, wall_time={result['wall_time']}s")
  86. self.send_json_response(result)
  87. except json.JSONDecodeError:
  88. self.send_json_response({"error": "JSON解析失败"}, 400)
  89. except Exception as e:
  90. logger.error(f"[语义逻辑Web测试] 处理失败: {e}", exc_info=True)
  91. self.send_json_response({"error": str(e)}, 500)
  92. else:
  93. self.send_json_response({"error": "Not Found"}, 404)
  94. def do_OPTIONS(self):
  95. self.send_response(200)
  96. self.send_header('Access-Control-Allow-Origin', '*')
  97. self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
  98. self.send_header('Access-Control-Allow-Headers', 'Content-Type')
  99. self.end_headers()
  100. def send_json_response(self, data, status=200):
  101. self.send_response(status)
  102. self.send_header('Content-Type', 'application/json; charset=utf-8')
  103. self.send_header('Access-Control-Allow-Origin', '*')
  104. self.end_headers()
  105. self.wfile.write(json.dumps(data, ensure_ascii=False, indent=2).encode('utf-8'))
  106. def serve_file(self, filepath: str, content_type: str):
  107. if os.path.exists(filepath):
  108. self.send_response(200)
  109. self.send_header('Content-Type', f'{content_type}; charset=utf-8')
  110. self.end_headers()
  111. with open(filepath, 'rb') as f:
  112. self.wfile.write(f.read())
  113. else:
  114. self.send_json_response({"error": f"文件不存在: {filepath}"}, 404)
  115. def end_headers(self):
  116. self.send_header('Access-Control-Allow-Origin', '*')
  117. super().end_headers()
  118. # ─── 启动服务器 ────────────────────────────────────────────────────────────────
  119. def run_server(port=8766):
  120. server = HTTPServer(('0.0.0.0', port), SemanticLogicHandler)
  121. print(f"\n{'='*70}")
  122. print(f" 语义逻辑审查 — 前端测试服务器")
  123. print(f"{'='*70}")
  124. print(f" 访问地址: http://localhost:{port}")
  125. print(f" API端点: POST /api/semantic_logic")
  126. print(f"{'='*70}\n")
  127. server.serve_forever()
  128. if __name__ == "__main__":
  129. import argparse
  130. parser = argparse.ArgumentParser(description='语义逻辑审查前端测试服务器')
  131. parser.add_argument('--port', type=int, default=8766, help='服务端口 (默认: 8766)')
  132. args = parser.parse_args()
  133. run_server(args.port)