grammar_check_test.html 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>词句语法审查测试</title>
  7. <style>
  8. * { margin: 0; padding: 0; box-sizing: border-box; }
  9. body {
  10. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  11. background: #f5f7fa;
  12. color: #333;
  13. line-height: 1.6;
  14. }
  15. .container {
  16. max-width: 1000px;
  17. margin: 0 auto;
  18. padding: 20px;
  19. }
  20. header {
  21. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  22. color: white;
  23. padding: 24px;
  24. border-radius: 12px;
  25. margin-bottom: 20px;
  26. }
  27. header h1 { font-size: 24px; margin-bottom: 6px; }
  28. header p { opacity: 0.9; font-size: 13px; }
  29. .panel {
  30. background: white;
  31. border-radius: 12px;
  32. padding: 20px;
  33. margin-bottom: 16px;
  34. box-shadow: 0 2px 8px rgba(0,0,0,0.06);
  35. }
  36. .panel h2 {
  37. font-size: 16px;
  38. margin-bottom: 12px;
  39. padding-bottom: 10px;
  40. border-bottom: 2px solid #f0f0f0;
  41. }
  42. textarea {
  43. width: 100%;
  44. min-height: 160px;
  45. padding: 12px;
  46. border: 1.5px solid #e0e0e0;
  47. border-radius: 8px;
  48. font-size: 14px;
  49. font-family: inherit;
  50. resize: vertical;
  51. }
  52. textarea:focus { outline: none; border-color: #667eea; }
  53. .btn {
  54. display: inline-flex;
  55. align-items: center;
  56. gap: 8px;
  57. padding: 10px 24px;
  58. border: none;
  59. border-radius: 8px;
  60. font-size: 14px;
  61. font-weight: 600;
  62. cursor: pointer;
  63. background: linear-gradient(135deg, #667eea, #764ba2);
  64. color: white;
  65. transition: all 0.2s;
  66. }
  67. .btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
  68. .btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }
  69. .loading {
  70. display: inline-block;
  71. width: 14px; height: 14px;
  72. border: 2px solid rgba(255,255,255,0.3);
  73. border-top-color: white;
  74. border-radius: 50%;
  75. animation: spin 0.8s linear infinite;
  76. }
  77. @keyframes spin { to { transform: rotate(360deg); } }
  78. .result { margin-top: 16px; }
  79. .result-card {
  80. background: #fafafa;
  81. border-radius: 10px;
  82. padding: 16px;
  83. margin-bottom: 12px;
  84. border-left: 4px solid #667eea;
  85. }
  86. .result-card.success { border-left-color: #51cf66; }
  87. .result-card.error { border-left-color: #ff6b6b; }
  88. .meta {
  89. display: flex;
  90. gap: 16px;
  91. flex-wrap: wrap;
  92. font-size: 13px;
  93. color: #666;
  94. margin-bottom: 10px;
  95. }
  96. .meta span { background: #f0f0f0; padding: 4px 12px; border-radius: 12px; }
  97. .json-block {
  98. background: #1e1e1e;
  99. color: #d4d4d4;
  100. padding: 14px;
  101. border-radius: 8px;
  102. font-family: "SF Mono", Monaco, "Cascadia Code", monospace;
  103. font-size: 12px;
  104. line-height: 1.5;
  105. overflow-x: auto;
  106. max-height: 400px;
  107. overflow-y: auto;
  108. white-space: pre-wrap;
  109. word-break: break-word;
  110. }
  111. .empty {
  112. text-align: center;
  113. color: #999;
  114. padding: 40px 20px;
  115. }
  116. </style>
  117. </head>
  118. <body>
  119. <div class="container">
  120. <header>
  121. <h1>词句语法审查测试</h1>
  122. <p>调用 GrammarCheckReviewer.check_grammar() 进行错别字、标点、重复字词检查</p>
  123. </header>
  124. <div class="panel">
  125. <h2>输入文本</h2>
  126. <textarea id="content" placeholder="输入要审查的施工方案文本..."></textarea>
  127. <div style="margin-top:12px; display:flex; align-items:center; gap:16px;">
  128. <button class="btn" id="submitBtn" onclick="runCheck()">
  129. 执行审查
  130. </button>
  131. <label style="display:flex; align-items:center; gap:6px; cursor:pointer; font-size:14px;">
  132. <input type="checkbox" id="enableThinking" style="width:16px; height:16px; cursor:pointer;">
  133. 启用思考模式 (enable_thinking)
  134. </label>
  135. </div>
  136. </div>
  137. <div class="panel result" id="resultPanel">
  138. <h2>审查结果</h2>
  139. <div class="empty">输入文本并点击"执行审查"</div>
  140. </div>
  141. </div>
  142. <script>
  143. const API_BASE = window.location.origin;
  144. let isRunning = false;
  145. async function runCheck() {
  146. if (isRunning) return;
  147. const content = document.getElementById('content').value.trim();
  148. if (!content) {
  149. alert('请输入审查文本');
  150. return;
  151. }
  152. isRunning = true;
  153. const btn = document.getElementById('submitBtn');
  154. const original = btn.innerHTML;
  155. btn.innerHTML = '<span class="loading"></span> 审查中...';
  156. btn.disabled = true;
  157. const start = Date.now();
  158. let result;
  159. try {
  160. const enableThinking = document.getElementById('enableThinking').checked;
  161. const res = await fetch(`${API_BASE}/api/grammar_check`, {
  162. method: 'POST',
  163. headers: { 'Content-Type': 'application/json' },
  164. body: JSON.stringify({ content, enable_thinking: enableThinking })
  165. });
  166. result = await res.json();
  167. } catch (e) {
  168. result = { success: false, error_message: `请求失败: ${e.message}` };
  169. }
  170. const wallTime = ((Date.now() - start) / 1000).toFixed(3);
  171. renderResult(result, wallTime);
  172. btn.innerHTML = original;
  173. btn.disabled = false;
  174. isRunning = false;
  175. }
  176. function renderResult(result, wallTime) {
  177. const panel = document.getElementById('resultPanel');
  178. const isSuccess = result.success;
  179. const cardClass = isSuccess ? 'success' : 'error';
  180. const statusText = isSuccess ? '成功' : '失败';
  181. const meta = [
  182. `<span>状态: ${statusText}</span>`,
  183. `<span>总耗时: ${wallTime}s</span>`,
  184. result.model_execution_time !== undefined ? `<span>模型耗时: ${(result.model_execution_time ?? 0).toFixed?.(3) ?? result.model_execution_time}s</span>` : '',
  185. result.trace_id ? `<span>trace_id: ${result.trace_id}</span>` : ''
  186. ].filter(Boolean).join('');
  187. const responseDetail = result.details?.response
  188. ? `<div style="margin-top:10px;"><strong>模型响应:</strong></div><div class="json-block">${escapeHtml(result.details.response)}</div>`
  189. : '';
  190. const errorDetail = result.error_message
  191. ? `<div style="margin-top:10px;color:#c92a2a;"><strong>错误:</strong> ${escapeHtml(result.error_message)}</div>`
  192. : '';
  193. const rawJson = `<div style="margin-top:10px;"><strong>原始返回:</strong></div><div class="json-block">${JSON.stringify(result, null, 2)}</div>`;
  194. panel.innerHTML = `
  195. <h2>审查结果</h2>
  196. <div class="result-card ${cardClass}">
  197. <div class="meta">${meta}</div>
  198. ${responseDetail}
  199. ${errorDetail}
  200. </div>
  201. ${rawJson}
  202. `;
  203. }
  204. function escapeHtml(text) {
  205. const div = document.createElement('div');
  206. div.textContent = text;
  207. return div.innerHTML;
  208. }
  209. </script>
  210. </body>
  211. </html>