system-overview-zh.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  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>Simple Knowledge Base - 系统概览</title>
  7. <style>
  8. :root {
  9. --primary: #6366f1;
  10. --primary-light: #818cf8;
  11. --primary-dark: #4f46e5;
  12. --bg: #0f172a;
  13. --bg-card: #1e293b;
  14. --bg-code: #0d1117;
  15. --text: #e2e8f0;
  16. --text-muted: #94a3b8;
  17. --border: #334155;
  18. --accent-green: #34d399;
  19. --accent-blue: #38bdf8;
  20. --accent-orange: #fb923c;
  21. --accent-pink: #f472b6;
  22. }
  23. * { margin: 0; padding: 0; box-sizing: border-box; }
  24. body {
  25. font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif;
  26. background: var(--bg);
  27. color: var(--text);
  28. line-height: 1.8;
  29. }
  30. .hero {
  31. background: linear-gradient(135deg, #1e1b4b 0%, #312e81 30%, #0f172a 70%, #0c0a09 100%);
  32. padding: 80px 20px 60px;
  33. text-align: center;
  34. position: relative;
  35. overflow: hidden;
  36. }
  37. .hero::before {
  38. content: '';
  39. position: absolute;
  40. top: -50%;
  41. left: -50%;
  42. width: 200%;
  43. height: 200%;
  44. background: radial-gradient(circle at 30% 50%, rgba(99, 102, 241, 0.15) 0%, transparent 50%),
  45. radial-gradient(circle at 70% 50%, rgba(56, 189, 248, 0.1) 0%, transparent 50%);
  46. animation: pulse 8s ease-in-out infinite;
  47. }
  48. @keyframes pulse {
  49. 0%, 100% { opacity: 0.6; }
  50. 50% { opacity: 1; }
  51. }
  52. .hero h1 {
  53. font-size: 2.8rem;
  54. font-weight: 800;
  55. background: linear-gradient(135deg, #c7d2fe, #818cf8, #38bdf8);
  56. -webkit-background-clip: text;
  57. -webkit-text-fill-color: transparent;
  58. background-clip: text;
  59. position: relative;
  60. margin-bottom: 12px;
  61. }
  62. .hero .subtitle {
  63. font-size: 1.15rem;
  64. color: var(--text-muted);
  65. position: relative;
  66. max-width: 700px;
  67. margin: 0 auto;
  68. }
  69. .badge-row {
  70. display: flex;
  71. gap: 10px;
  72. justify-content: center;
  73. flex-wrap: wrap;
  74. margin-top: 24px;
  75. position: relative;
  76. }
  77. .badge {
  78. display: inline-flex;
  79. align-items: center;
  80. gap: 6px;
  81. padding: 5px 14px;
  82. border-radius: 999px;
  83. font-size: 0.82rem;
  84. font-weight: 600;
  85. border: 1px solid;
  86. }
  87. .badge.react { color: #61dafb; border-color: #61dafb33; background: #61dafb10; }
  88. .badge.nest { color: #e0234e; border-color: #e0234e33; background: #e0234e10; }
  89. .badge.rag { color: var(--accent-green); border-color: #34d39933; background: #34d39910; }
  90. .badge.ts { color: #3178c6; border-color: #3178c633; background: #3178c610; }
  91. .container {
  92. max-width: 1100px;
  93. margin: 0 auto;
  94. padding: 0 20px;
  95. }
  96. .features-grid {
  97. display: grid;
  98. grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  99. gap: 20px;
  100. margin: -40px auto 60px;
  101. position: relative;
  102. z-index: 1;
  103. }
  104. .feature-card {
  105. background: var(--bg-card);
  106. border: 1px solid var(--border);
  107. border-radius: 16px;
  108. padding: 28px;
  109. transition: transform 0.2s, border-color 0.2s;
  110. }
  111. .feature-card:hover {
  112. transform: translateY(-3px);
  113. border-color: var(--primary);
  114. }
  115. .feature-card .icon {
  116. width: 44px;
  117. height: 44px;
  118. border-radius: 12px;
  119. display: flex;
  120. align-items: center;
  121. justify-content: center;
  122. font-size: 1.3rem;
  123. margin-bottom: 16px;
  124. }
  125. .feature-card h3 {
  126. font-size: 1.05rem;
  127. margin-bottom: 8px;
  128. color: #f1f5f9;
  129. }
  130. .feature-card p {
  131. font-size: 0.9rem;
  132. color: var(--text-muted);
  133. }
  134. .icon-blue { background: #38bdf818; }
  135. .icon-green { background: #34d39918; }
  136. .icon-orange { background: #fb923c18; }
  137. .icon-pink { background: #f472b618; }
  138. .icon-purple { background: #a78bfa18; }
  139. .icon-yellow { background: #fbbf2418; }
  140. section {
  141. margin-bottom: 56px;
  142. }
  143. .section-title {
  144. font-size: 1.5rem;
  145. font-weight: 700;
  146. margin-bottom: 24px;
  147. padding-bottom: 12px;
  148. border-bottom: 2px solid var(--border);
  149. display: flex;
  150. align-items: center;
  151. gap: 10px;
  152. }
  153. .section-title .num {
  154. display: inline-flex;
  155. align-items: center;
  156. justify-content: center;
  157. width: 32px;
  158. height: 32px;
  159. border-radius: 8px;
  160. background: var(--primary);
  161. font-size: 0.85rem;
  162. font-weight: 700;
  163. flex-shrink: 0;
  164. }
  165. /* Architecture Diagram */
  166. .arch-diagram {
  167. background: var(--bg-card);
  168. border: 1px solid var(--border);
  169. border-radius: 16px;
  170. padding: 32px;
  171. overflow-x: auto;
  172. }
  173. .arch-row {
  174. display: flex;
  175. justify-content: center;
  176. gap: 16px;
  177. margin-bottom: 16px;
  178. flex-wrap: wrap;
  179. }
  180. .arch-box {
  181. padding: 14px 22px;
  182. border-radius: 10px;
  183. font-size: 0.85rem;
  184. font-weight: 600;
  185. text-align: center;
  186. min-width: 140px;
  187. border: 1px solid;
  188. }
  189. .arch-box.frontend { background: #61dafb12; border-color: #61dafb33; color: #61dafb; }
  190. .arch-box.backend { background: #e0234e12; border-color: #e0234e33; color: #e0234e; }
  191. .arch-box.infra { background: #34d39912; border-color: #34d39933; color: #34d399; }
  192. .arch-box.ai { background: #a78bfa12; border-color: #a78bfa33; color: #a78bfa; }
  193. .arch-box.data { background: #fb923c12; border-color: #fb923c33; color: #fb923c; }
  194. .arch-arrow {
  195. text-align: center;
  196. color: var(--text-muted);
  197. font-size: 1.2rem;
  198. margin-bottom: 16px;
  199. }
  200. .arch-label {
  201. text-align: center;
  202. font-size: 0.78rem;
  203. color: var(--text-muted);
  204. letter-spacing: 1.5px;
  205. margin-bottom: 10px;
  206. }
  207. /* File Tree */
  208. .file-tree {
  209. background: var(--bg-code);
  210. border: 1px solid var(--border);
  211. border-radius: 12px;
  212. padding: 24px 28px;
  213. font-family: 'Cascadia Code', 'Fira Code', monospace;
  214. font-size: 0.85rem;
  215. line-height: 1.9;
  216. overflow-x: auto;
  217. }
  218. .file-tree .dir { color: var(--accent-blue); font-weight: 600; }
  219. .file-tree .comment { color: #64748b; font-style: italic; }
  220. .file-tree .file { color: var(--text); }
  221. /* Pipeline */
  222. .pipeline {
  223. display: flex;
  224. align-items: center;
  225. gap: 0;
  226. flex-wrap: wrap;
  227. justify-content: center;
  228. margin: 20px 0;
  229. }
  230. .pipeline-step {
  231. padding: 12px 20px;
  232. border-radius: 10px;
  233. font-size: 0.85rem;
  234. font-weight: 600;
  235. text-align: center;
  236. border: 1px solid var(--border);
  237. background: var(--bg-card);
  238. }
  239. .pipeline-arrow {
  240. color: var(--text-muted);
  241. font-size: 1.1rem;
  242. padding: 0 6px;
  243. }
  244. .pipeline-step.active {
  245. border-color: var(--primary);
  246. background: #6366f118;
  247. color: var(--primary-light);
  248. }
  249. /* Tables */
  250. .info-table {
  251. width: 100%;
  252. border-collapse: collapse;
  253. margin: 12px 0;
  254. }
  255. .info-table th, .info-table td {
  256. padding: 10px 16px;
  257. text-align: left;
  258. border-bottom: 1px solid var(--border);
  259. font-size: 0.9rem;
  260. }
  261. .info-table th {
  262. color: var(--text-muted);
  263. font-weight: 600;
  264. font-size: 0.82rem;
  265. letter-spacing: 0.5px;
  266. }
  267. .info-table .port {
  268. font-family: 'Cascadia Code', monospace;
  269. color: var(--accent-orange);
  270. font-weight: 600;
  271. }
  272. .info-table .env-key {
  273. font-family: 'Cascadia Code', monospace;
  274. color: var(--accent-green);
  275. font-size: 0.83rem;
  276. }
  277. /* Code Block */
  278. .code-block {
  279. background: var(--bg-code);
  280. border: 1px solid var(--border);
  281. border-radius: 10px;
  282. padding: 18px 22px;
  283. font-family: 'Cascadia Code', 'Fira Code', monospace;
  284. font-size: 0.83rem;
  285. line-height: 1.8;
  286. overflow-x: auto;
  287. margin: 12px 0;
  288. }
  289. .code-block .cmd { color: var(--accent-green); }
  290. .code-block .comment { color: #64748b; }
  291. /* Two Column Layout */
  292. .two-col {
  293. display: grid;
  294. grid-template-columns: 1fr 1fr;
  295. gap: 24px;
  296. }
  297. @media (max-width: 768px) {
  298. .two-col { grid-template-columns: 1fr; }
  299. .hero h1 { font-size: 2rem; }
  300. .features-grid { grid-template-columns: 1fr; }
  301. }
  302. .card {
  303. background: var(--bg-card);
  304. border: 1px solid var(--border);
  305. border-radius: 14px;
  306. padding: 24px;
  307. }
  308. .card h4 {
  309. font-size: 1rem;
  310. margin-bottom: 14px;
  311. color: #f1f5f9;
  312. }
  313. .card ul {
  314. list-style: none;
  315. padding: 0;
  316. }
  317. .card ul li {
  318. padding: 6px 0;
  319. font-size: 0.88rem;
  320. color: var(--text-muted);
  321. display: flex;
  322. align-items: flex-start;
  323. gap: 8px;
  324. }
  325. .card ul li::before {
  326. content: '›';
  327. color: var(--primary-light);
  328. font-weight: 700;
  329. flex-shrink: 0;
  330. }
  331. .step-list {
  332. list-style: none;
  333. padding: 0;
  334. counter-reset: step;
  335. }
  336. .step-list li {
  337. counter-increment: step;
  338. padding: 8px 0;
  339. font-size: 0.88rem;
  340. color: var(--text-muted);
  341. display: flex;
  342. align-items: flex-start;
  343. gap: 10px;
  344. }
  345. .step-list li::before {
  346. content: counter(step);
  347. display: inline-flex;
  348. align-items: center;
  349. justify-content: center;
  350. width: 22px;
  351. height: 22px;
  352. border-radius: 6px;
  353. background: var(--primary);
  354. color: white;
  355. font-size: 0.72rem;
  356. font-weight: 700;
  357. flex-shrink: 0;
  358. }
  359. .troubleshoot-item {
  360. background: var(--bg-card);
  361. border: 1px solid var(--border);
  362. border-radius: 10px;
  363. padding: 16px 20px;
  364. margin-bottom: 10px;
  365. }
  366. .troubleshoot-item strong {
  367. color: #f1f5f9;
  368. font-size: 0.92rem;
  369. }
  370. .troubleshoot-item p {
  371. color: var(--text-muted);
  372. font-size: 0.85rem;
  373. margin-top: 4px;
  374. }
  375. footer {
  376. text-align: center;
  377. padding: 40px 20px;
  378. color: var(--text-muted);
  379. font-size: 0.82rem;
  380. border-top: 1px solid var(--border);
  381. }
  382. </style>
  383. </head>
  384. <body>
  385. <!-- Hero -->
  386. <div class="hero">
  387. <h1>Simple Knowledge Base</h1>
  388. <p class="subtitle">全栈 RAG 问答系统 &mdash; 基于 React 19 + NestJS 的检索增强生成技术</p>
  389. <div class="badge-row">
  390. <span class="badge react">React 19</span>
  391. <span class="badge nest">NestJS</span>
  392. <span class="badge rag">RAG 系统</span>
  393. <span class="badge ts">TypeScript</span>
  394. </div>
  395. </div>
  396. <div class="container">
  397. <!-- 核心特性 -->
  398. <div class="features-grid">
  399. <div class="feature-card">
  400. <div class="icon icon-purple"> </div>
  401. <h3>多模型支持</h3>
  402. <p>兼容 OpenAI API(OpenAI、DeepSeek、Claude 等)+ Google Gemini 原生 SDK,可配置 LLM、Embedding 和 Rerank 模型。</p>
  403. </div>
  404. <div class="feature-card">
  405. <div class="icon icon-blue">⚡</div>
  406. <h3>双处理模式</h3>
  407. <p>快速模式通过 Apache Tika 提取文本,高精度模式通过视觉管线处理图文混合文档。</p>
  408. </div>
  409. <div class="feature-card">
  410. <div class="icon icon-green"> </div>
  411. <h3>混合检索</h3>
  412. <p>基于 Elasticsearch 的向量 + 关键词混合搜索,支持来源引用、相似度评分,可配置分块大小与重叠。</p>
  413. </div>
  414. <div class="feature-card">
  415. <div class="icon icon-orange"> </div>
  416. <h3>用户隔离</h3>
  417. <p>JWT 认证 + 每用户独立知识库,数据与配置完全隔离,保障隐私安全。</p>
  418. </div>
  419. <div class="feature-card">
  420. <div class="icon icon-pink"> </div>
  421. <h3>流式响应</h3>
  422. <p>基于 Server-Sent Events (SSE) 的实时流式输出,提供流畅低延迟的对话体验。</p>
  423. </div>
  424. <div class="feature-card">
  425. <div class="icon icon-yellow"> </div>
  426. <h3>多语言支持</h3>
  427. <p>界面支持日语、中文和英文,错误信息和 API 响应消息全面国际化。</p>
  428. </div>
  429. </div>
  430. <!-- 系统架构 -->
  431. <section>
  432. <h2 class="section-title"><span class="num">1</span> 系统架构概览</h2>
  433. <div class="arch-diagram">
  434. <div class="arch-label">前端层</div>
  435. <div class="arch-row">
  436. <div class="arch-box frontend">React 19 + Vite<br><small style="opacity:0.7">端口 13001(开发)/ 80(生产)</small></div>
  437. </div>
  438. <div class="arch-arrow">↕</div>
  439. <div class="arch-label">后端层</div>
  440. <div class="arch-row">
  441. <div class="arch-box backend">NestJS API<br><small style="opacity:0.7">端口 3001</small></div>
  442. <div class="arch-box backend">JWT 认证</div>
  443. <div class="arch-box backend">对话 / RAG</div>
  444. <div class="arch-box backend">视觉管线</div>
  445. </div>
  446. <div class="arch-arrow">↕</div>
  447. <div class="arch-label">AI 与数据层</div>
  448. <div class="arch-row">
  449. <div class="arch-box ai">OpenAI / Gemini<br><small style="opacity:0.7">LLM + 向量嵌入</small></div>
  450. <div class="arch-box infra">Elasticsearch<br><small style="opacity:0.7">端口 9200</small></div>
  451. <div class="arch-box infra">Apache Tika<br><small style="opacity:0.7">端口 9998</small></div>
  452. <div class="arch-box infra">LibreOffice<br><small style="opacity:0.7">端口 8100</small></div>
  453. <div class="arch-box data">SQLite<br><small style="opacity:0.7">元数据存储</small></div>
  454. </div>
  455. </div>
  456. <!-- 处理管线 -->
  457. <h4 style="margin-top:28px; margin-bottom:14px; color:#f1f5f9;">双处理管线</h4>
  458. <div class="two-col">
  459. <div class="card">
  460. <h4>快速模式(Tika)</h4>
  461. <div class="pipeline">
  462. <div class="pipeline-step active">上传</div>
  463. <span class="pipeline-arrow">→</span>
  464. <div class="pipeline-step active">Tika 提取</div>
  465. <span class="pipeline-arrow">→</span>
  466. <div class="pipeline-step active">向量化</div>
  467. <span class="pipeline-arrow">→</span>
  468. <div class="pipeline-step active">存储</div>
  469. </div>
  470. <p style="font-size:0.85rem; color:var(--text-muted); text-align:center;">快速文本提取,无 API 调用成本</p>
  471. </div>
  472. <div class="card">
  473. <h4>高精度模式(视觉管线)</h4>
  474. <div class="pipeline">
  475. <div class="pipeline-step active">上传</div>
  476. <span class="pipeline-arrow">→</span>
  477. <div class="pipeline-step">LibreOffice</div>
  478. <span class="pipeline-arrow">→</span>
  479. <div class="pipeline-step">PDF 转图片</div>
  480. <span class="pipeline-arrow">→</span>
  481. <div class="pipeline-step">视觉模型</div>
  482. </div>
  483. <p style="font-size:0.85rem; color:var(--text-muted); text-align:center;">保留原始排版、图表和图片信息</p>
  484. </div>
  485. </div>
  486. </section>
  487. <!-- 项目结构 -->
  488. <section>
  489. <h2 class="section-title"><span class="num">2</span> 项目结构</h2>
  490. <div class="file-tree">
  491. <span class="dir">simple-kb/</span><br>
  492. ├── <span class="dir">web/</span> <span class="comment"># React 前端(Vite)</span><br>
  493. │ ├── <span class="dir">components/</span> <span class="comment"># UI 组件(ChatInterface, ConfigPanel 等)</span><br>
  494. │ ├── <span class="dir">contexts/</span> <span class="comment"># React Context 提供者</span><br>
  495. │ ├── <span class="dir">services/</span> <span class="comment"># API 客户端服务</span><br>
  496. │ └── <span class="dir">utils/</span> <span class="comment"># 工具函数</span><br>
  497. ├── <span class="dir">server/</span> <span class="comment"># NestJS 后端</span><br>
  498. │ ├── <span class="dir">src/</span><br>
  499. │ │ ├── <span class="dir">ai/</span> <span class="comment"># AI 服务(向量嵌入等)</span><br>
  500. │ │ ├── <span class="dir">api/</span> <span class="comment"># API 模块</span><br>
  501. │ │ ├── <span class="dir">auth/</span> <span class="comment"># JWT 认证</span><br>
  502. │ │ ├── <span class="dir">chat/</span> <span class="comment"># 对话 / RAG 模块</span><br>
  503. │ │ ├── <span class="dir">elasticsearch/</span> <span class="comment"># Elasticsearch 集成</span><br>
  504. │ │ ├── <span class="dir">import-task/</span> <span class="comment"># 导入任务管理</span><br>
  505. │ │ ├── <span class="dir">knowledge-base/</span> <span class="comment"># 知识库管理</span><br>
  506. │ │ ├── <span class="dir">libreoffice/</span> <span class="comment"># LibreOffice 集成</span><br>
  507. │ │ ├── <span class="dir">model-config/</span> <span class="comment"># 模型配置管理</span><br>
  508. │ │ ├── <span class="dir">vision/</span> <span class="comment"># 视觉模型集成</span><br>
  509. │ │ └── <span class="dir">vision-pipeline/</span> <span class="comment"># 视觉管线编排</span><br>
  510. │ ├── <span class="dir">data/</span> <span class="comment"># SQLite 数据库存储</span><br>
  511. │ ├── <span class="dir">uploads/</span> <span class="comment"># 上传文件存储</span><br>
  512. │ └── <span class="dir">temp/</span> <span class="comment"># 临时文件</span><br>
  513. ├── <span class="dir">docs/</span> <span class="comment"># 项目文档</span><br>
  514. ├── <span class="dir">nginx/</span> <span class="comment"># Nginx 配置</span><br>
  515. ├── <span class="dir">libreoffice-server/</span> <span class="comment"># LibreOffice 转换服务(Python/FastAPI)</span><br>
  516. └── <span class="file">docker-compose.yml</span> <span class="comment"># Docker 编排配置</span>
  517. </div>
  518. </section>
  519. <!-- 开发环境搭建 -->
  520. <section>
  521. <h2 class="section-title"><span class="num">3</span> 开发环境搭建</h2>
  522. <h4 style="margin-bottom:10px; color:#f1f5f9;">前置条件</h4>
  523. <div class="card" style="margin-bottom:20px;">
  524. <ul>
  525. <li>Node.js 18+</li>
  526. <li>Yarn 包管理器</li>
  527. <li>Docker &amp; Docker Compose</li>
  528. </ul>
  529. </div>
  530. <h4 style="margin-bottom:10px; color:#f1f5f9;">快速启动</h4>
  531. <div class="code-block">
  532. <span class="comment"># 安装依赖</span><br>
  533. <span class="cmd">yarn install</span><br><br>
  534. <span class="comment"># 启动基础设施服务</span><br>
  535. <span class="cmd">docker-compose up -d elasticsearch tika libreoffice</span><br><br>
  536. <span class="comment"># 配置环境变量</span><br>
  537. <span class="cmd">cp server/.env.sample server/.env</span><br><br>
  538. <span class="comment"># 同时启动前后端</span><br>
  539. <span class="cmd">yarn dev</span>
  540. </div>
  541. <h4 style="margin:20px 0 10px; color:#f1f5f9;">开发命令</h4>
  542. <div class="code-block">
  543. <span class="comment"># 仅启动前端(端口 13001)</span><br>
  544. <span class="cmd">cd web && yarn dev</span><br><br>
  545. <span class="comment"># 仅启动后端(端口 3001)</span><br>
  546. <span class="cmd">cd server && yarn start:dev</span><br><br>
  547. <span class="comment"># 运行测试</span><br>
  548. <span class="cmd">cd server && yarn test</span><br>
  549. <span class="cmd">cd server && yarn test:e2e</span><br><br>
  550. <span class="comment"># 代码检查和格式化</span><br>
  551. <span class="cmd">cd server && yarn lint</span><br>
  552. <span class="cmd">cd server && yarn format</span>
  553. </div>
  554. </section>
  555. <!-- Docker 服务 -->
  556. <section>
  557. <h2 class="section-title"><span class="num">4</span> Docker 服务与端口</h2>
  558. <div class="card">
  559. <table class="info-table">
  560. <thead>
  561. <tr><th>服务</th><th>端口</th><th>用途</th></tr>
  562. </thead>
  563. <tbody>
  564. <tr><td>Elasticsearch</td><td class="port">9200</td><td>向量存储与混合检索</td></tr>
  565. <tr><td>Apache Tika</td><td class="port">9998</td><td>文档文本提取</td></tr>
  566. <tr><td>LibreOffice Server</td><td class="port">8100</td><td>文档格式转换</td></tr>
  567. <tr><td>后端 API</td><td class="port">3001</td><td>NestJS REST API</td></tr>
  568. <tr><td>前端(开发)</td><td class="port">13001</td><td>Vite 开发服务器</td></tr>
  569. <tr><td>前端(生产)</td><td class="port">80 / 443</td><td>Nginx 反向代理</td></tr>
  570. </tbody>
  571. </table>
  572. </div>
  573. </section>
  574. <!-- 环境配置 -->
  575. <section>
  576. <h2 class="section-title"><span class="num">5</span> 环境配置</h2>
  577. <div class="card">
  578. <p style="font-size:0.88rem; color:var(--text-muted); margin-bottom:14px;">关键环境变量,配置于 <code style="color:var(--accent-green); background:#0d1117; padding:2px 8px; border-radius:4px; font-size:0.83rem;">server/.env</code></p>
  579. <table class="info-table">
  580. <thead>
  581. <tr><th>变量名</th><th>默认值</th><th>说明</th></tr>
  582. </thead>
  583. <tbody>
  584. <tr><td class="env-key">OPENAI_API_KEY</td><td>&mdash;</td><td>OpenAI 兼容 API 密钥</td></tr>
  585. <tr><td class="env-key">GEMINI_API_KEY</td><td>&mdash;</td><td>Google Gemini API 密钥</td></tr>
  586. <tr><td class="env-key">ELASTICSEARCH_HOST</td><td>http://localhost:9200</td><td>Elasticsearch 地址</td></tr>
  587. <tr><td class="env-key">TIKA_HOST</td><td>http://localhost:9998</td><td>Apache Tika 地址</td></tr>
  588. <tr><td class="env-key">LIBREOFFICE_URL</td><td>http://localhost:8100</td><td>LibreOffice 服务器地址</td></tr>
  589. <tr><td class="env-key">JWT_SECRET</td><td>&mdash;</td><td>JWT 签名密钥</td></tr>
  590. </tbody>
  591. </table>
  592. </div>
  593. </section>
  594. <!-- 代码规范 -->
  595. <section>
  596. <h2 class="section-title"><span class="num">6</span> 代码规范</h2>
  597. <div class="two-col">
  598. <div class="card">
  599. <h4>语言要求</h4>
  600. <ul>
  601. <li>代码注释必须使用英文</li>
  602. <li>日志消息必须使用英文</li>
  603. <li>错误消息必须支持国际化</li>
  604. <li>API 响应消息必须支持国际化</li>
  605. <li>界面支持日语、中文和英文</li>
  606. </ul>
  607. </div>
  608. <div class="card">
  609. <h4>代码质量</h4>
  610. <ul>
  611. <li>后端使用 Jest 进行单元测试和端到端测试</li>
  612. <li>后端已配置 ESLint 和 Prettier</li>
  613. <li>格式化:<code style="color:var(--accent-green);">cd server && yarn format</code></li>
  614. <li>检查:<code style="color:var(--accent-green);">cd server && yarn lint</code></li>
  615. </ul>
  616. </div>
  617. </div>
  618. </section>
  619. <!-- 常见开发任务 -->
  620. <section>
  621. <h2 class="section-title"><span class="num">7</span> 常见开发任务</h2>
  622. <div class="two-col">
  623. <div class="card">
  624. <h4>添加新的 API 端点</h4>
  625. <ol class="step-list">
  626. <li>在 <code style="color:var(--accent-blue);">server/src/</code> 对应模块下创建 Controller</li>
  627. <li>添加 Service 方法,使用英文注释</li>
  628. <li>更新 DTO 和参数校验</li>
  629. <li>在 <code style="color:var(--accent-blue);">*.spec.ts</code> 文件中添加测试</li>
  630. </ol>
  631. </div>
  632. <div class="card">
  633. <h4>添加新的前端组件</h4>
  634. <ol class="step-list">
  635. <li>在 <code style="color:var(--accent-blue);">web/components/</code> 下创建组件</li>
  636. <li>在 <code style="color:var(--accent-blue);">web/types.ts</code> 中添加 TypeScript 接口</li>
  637. <li>使用 Tailwind CSS 进行样式开发</li>
  638. <li>在 <code style="color:var(--accent-blue);">web/services/</code> 中连接后端服务</li>
  639. </ol>
  640. </div>
  641. </div>
  642. </section>
  643. <!-- 部署 -->
  644. <section>
  645. <h2 class="section-title"><span class="num">8</span> 部署</h2>
  646. <div class="two-col">
  647. <div class="card">
  648. <h4>开发环境</h4>
  649. <div class="code-block">
  650. <span class="cmd">docker-compose up -d elasticsearch tika libreoffice</span><br>
  651. <span class="cmd">yarn dev</span>
  652. </div>
  653. </div>
  654. <div class="card">
  655. <h4>生产环境</h4>
  656. <div class="code-block">
  657. <span class="comment"># 构建并启动所有服务</span><br>
  658. <span class="cmd">docker-compose up -d</span>
  659. </div>
  660. </div>
  661. </div>
  662. </section>
  663. <!-- 故障排查 -->
  664. <section>
  665. <h2 class="section-title"><span class="num">9</span> 故障排查</h2>
  666. <div class="troubleshoot-item">
  667. <strong>Elasticsearch 无法启动</strong>
  668. <p>检查 docker-compose.yml 中的内存限制配置</p>
  669. </div>
  670. <div class="troubleshoot-item">
  671. <strong>文件上传失败</strong>
  672. <p>确保 <code style="color:var(--accent-green);">uploads/</code> 和 <code style="color:var(--accent-green);">temp/</code> 目录存在且具有正确的读写权限</p>
  673. </div>
  674. <div class="troubleshoot-item">
  675. <strong>视觉管线报错</strong>
  676. <p>确认 LibreOffice 服务正在运行且 8100 端口可访问</p>
  677. </div>
  678. <div class="troubleshoot-item">
  679. <strong>API 密钥错误</strong>
  680. <p>检查 <code style="color:var(--accent-green);">server/.env</code> 中的环境变量配置</p>
  681. </div>
  682. <div class="troubleshoot-item">
  683. <strong>数据库重置</strong>
  684. <p>删除 <code style="color:var(--accent-green);">server/data/metadata.db</code> 及 Elasticsearch 数据卷</p>
  685. </div>
  686. </section>
  687. <!-- 调试 -->
  688. <section>
  689. <h2 class="section-title"><span class="num">10</span> 调试与健康检查</h2>
  690. <div class="code-block">
  691. <span class="comment"># 检查 Elasticsearch 状态</span><br>
  692. <span class="cmd">curl http://localhost:9200/_cat/indices</span><br><br>
  693. <span class="comment"># 检查 Tika 状态</span><br>
  694. <span class="cmd">curl http://localhost:9998/tika</span><br><br>
  695. <span class="comment"># 检查 LibreOffice 状态</span><br>
  696. <span class="cmd">curl http://localhost:8100/health</span>
  697. </div>
  698. </section>
  699. </div>
  700. <footer>
  701. Simple Knowledge Base &mdash; 全栈 RAG 问答系统 &mdash; React 19 + NestJS + Elasticsearch
  702. </footer>
  703. </body>
  704. </html>