grammar_check_server.py 5.5 KB

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