dev-yuje commited on
Commit
71c5f81
ยท
1 Parent(s): 26ff8dc

refactor: reduce chatbot width to 70% and optimize vertical margins

Browse files
Files changed (4) hide show
  1. AGENTS.md +16 -0
  2. app.py +9 -9
  3. src/utils/ui_templates.py +65 -23
  4. tests/smoke_test_rag.py +17 -17
AGENTS.md CHANGED
@@ -193,3 +193,19 @@ def test_4_core_scenarios():
193
  3. **์ €์ž‘๊ถŒ ๊ฒ€์‚ฌ(Copyright)**: ์˜์กด์„ฑ ํŒจํ‚ค์ง€๋“ค์˜ ๋ผ์ด์„ ์Šค๋ฅผ ์ „์ˆ˜ ๋ถ„์„ํ•˜์—ฌ ๋ชจ๋‘ Apache 2.0, MIT, BSD ๋“ฑ ํ—ˆ์šฉ์  ๋ผ์ด์„ ์Šค์ž„์„ ํ™•์ธํ•˜์—ฌ ๋ฒ•์  ์œ„ํ—˜ 0% ๋ณด์žฅ. ๋ฃจํŠธ์— MIT `LICENSE` ํŒŒ์ผ์„ ์ •์‹ ๋ฐฐํฌํ•˜๊ณ , `delete_zero_rel_articles.py`, `plot_keywords.py` ๋“ฑ ์‹ ๊ทœ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํŒŒ์ผ์— ํ•œ๊ธ€ ์„ค๋ช… ์ฃผ์„ ๋ฐ ์ €์ž‘๊ถŒ ๋ช…์‹œ ํ—ค๋”๋ฅผ ์™„๋ฒฝ ์ ์šฉํ•จ.
194
  4. **Git ์—…๋กœ๋“œ**: ๋ชจ๋“  ์š”๊ฑด์„ ๊ฐ–์ถ˜ ์ฝ”๋“œ๋ฅผ ์ตœ์ข… ์Šคํ…Œ์ด์ง•ํ•˜๊ณ  ์˜์–ด ์งง์€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ๊ทœ์น™ ์ค€์ˆ˜ ํ›„ `origin/main`์œผ๋กœ ์ตœ์ข… Push ์™„๋ฃŒ.
195
  5. **UI ๋””์ž์ธ ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜**: ์™ธ๋ถ€๋กœ ๋Œ์ถœ๋˜์–ด ์ฑ„ํŒ… ์ฐฝ ์˜์—ญ์„ ์นจ๋ฒ”ํ•˜๋˜ ์šฐ์ธก ์„ค๋ช… HTML์„ ์ œ๊ฑฐํ•˜๊ณ  ์ฑ—๋ด‡ ๋‚ด๋ถ€์˜ placeholder ์˜์—ญ์œผ๋กœ ์›๋ณตํ•˜์˜€์œผ๋ฉฐ, ๋Œ€์‹œ๋ณด๋“œ์™€ ์ฑ„ํŒ…์ฐฝ์˜ ๊ณจ๋“  ํ™”๋ฉด ๋น„์œจ(3:7 split)์„ ์™„๋ฒฝํ•˜๊ฒŒ ๋ณต๊ตฌํ•จ.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  3. **์ €์ž‘๊ถŒ ๊ฒ€์‚ฌ(Copyright)**: ์˜์กด์„ฑ ํŒจํ‚ค์ง€๋“ค์˜ ๋ผ์ด์„ ์Šค๋ฅผ ์ „์ˆ˜ ๋ถ„์„ํ•˜์—ฌ ๋ชจ๋‘ Apache 2.0, MIT, BSD ๋“ฑ ํ—ˆ์šฉ์  ๋ผ์ด์„ ์Šค์ž„์„ ํ™•์ธํ•˜์—ฌ ๋ฒ•์  ์œ„ํ—˜ 0% ๋ณด์žฅ. ๋ฃจํŠธ์— MIT `LICENSE` ํŒŒ์ผ์„ ์ •์‹ ๋ฐฐํฌํ•˜๊ณ , `delete_zero_rel_articles.py`, `plot_keywords.py` ๋“ฑ ์‹ ๊ทœ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํŒŒ์ผ์— ํ•œ๊ธ€ ์„ค๋ช… ์ฃผ์„ ๋ฐ ์ €์ž‘๊ถŒ ๋ช…์‹œ ํ—ค๋”๋ฅผ ์™„๋ฒฝ ์ ์šฉํ•จ.
194
  4. **Git ์—…๋กœ๋“œ**: ๋ชจ๋“  ์š”๊ฑด์„ ๊ฐ–์ถ˜ ์ฝ”๋“œ๋ฅผ ์ตœ์ข… ์Šคํ…Œ์ด์ง•ํ•˜๊ณ  ์˜์–ด ์งง์€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ๊ทœ์น™ ์ค€์ˆ˜ ํ›„ `origin/main`์œผ๋กœ ์ตœ์ข… Push ์™„๋ฃŒ.
195
  5. **UI ๋””์ž์ธ ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜**: ์™ธ๋ถ€๋กœ ๋Œ์ถœ๋˜์–ด ์ฑ„ํŒ… ์ฐฝ ์˜์—ญ์„ ์นจ๋ฒ”ํ•˜๋˜ ์šฐ์ธก ์„ค๋ช… HTML์„ ์ œ๊ฑฐํ•˜๊ณ  ์ฑ—๋ด‡ ๋‚ด๋ถ€์˜ placeholder ์˜์—ญ์œผ๋กœ ์›๋ณตํ•˜์˜€์œผ๋ฉฐ, ๋Œ€์‹œ๋ณด๋“œ์™€ ์ฑ„ํŒ…์ฐฝ์˜ ๊ณจ๋“  ํ™”๋ฉด ๋น„์œจ(3:7 split)์„ ์™„๋ฒฝํ•˜๊ฒŒ ๋ณต๊ตฌํ•จ.
196
+
197
+ - [x] **Gradio ๊ธฐ๋ณธ ์˜ˆ์‹œ ์งˆ๋ฌธ 100% GraphRAG ๋™์ž‘ ๋ณด์žฅ ๊ฐœํŽธ (2026-05-20)**:
198
+ - **ํ˜„์ƒ**: ๋ฉ”์ธ ํ™”๋ฉด์˜ ๊ธฐ๋ณธ 4๊ฐœ ์˜ˆ์‹œ ์งˆ๋ฌธ ์ค‘ ์ผ๋ถ€(LLM ๊ฐœ๋ฐœ ๊ธฐ์—…, ๊ธฐ์‚ฌ ์š”์•ฝ ๋“ฑ)๊ฐ€ ๋‹ค์†Œ ์ผ๋ฐ˜์ ์ด๊ฑฐ๋‚˜ DB ์ •๋ณด์˜ ๋ชจํ˜ธํ•จ์œผ๋กœ ์ธํ•ด GraphRAG ๊ธฐ๋ฐ˜ ๋ชจ๋“œ๊ฐ€ ์•„๋‹Œ GPT-4o-mini ์ผ๋ฐ˜(general) ์ง€์‹ ๋ชจ๋“œ๋กœ ์šฐํšŒ๋˜๋Š” ํ˜„์ƒ ํ™•์ธ.
199
+ - **์กฐ์น˜**:
200
+ 1. Neo4j AuraDB ์‹ค๋ฌผ ๊ธฐ์‚ฌ ๋ฐ ์—”ํ‹ฐํ‹ฐ ์ ์žฌ ๋ฐ์ดํ„ฐ(์‚ผ์„ฑ ๊ฐ€์šฐ์Šค 2, ์นด์นด์˜ค ์นด๋‚˜๋‚˜, AWS ํ”ผ์ง€์ปฌ AI, ๊ตฌ๊ธ€ I/O ์ œ๋ฏธ๋‚˜์ด ๋“ฑ)๋ฅผ ์ฒ ์ €ํžˆ ํ”„๋กœํŒŒ์ผ๋งํ•˜์—ฌ 100% ๋ฆฌํŠธ๋ฆฌ๋ฒ„๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•  ์ˆ˜ ์žˆ๋Š” ์ดˆ๊ณ ํ’ˆ์งˆ ์งˆ๋ฌธ 4๊ฐœ๋กœ ์˜ˆ์‹œ ์งˆ๋ฌธ์„ ์ „๊ฒฉ ๊ฐœํŽธ.
201
+ 2. `app.py`์™€ ํ†ตํ•ฉ ๊ฒ€์ฆ ์Šคํฌ๋ฆฝํŠธ์ธ `tests/smoke_test_rag.py`์— ์ ์šฉ๋œ ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค ์งˆ๋ฌธ ํ…์ŠคํŠธ ๋ฐ ๊ธฐ๋Œ€ ํ‚ค์›Œ๋“œ๋ฅผ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๋„๋ก ๋™๊ธฐํ™” ์ˆ˜์ • ์™„๋ฃŒ.
202
+ - **๊ฒ€์ฆ**: `ruff` ์ •์  ๋ฆฐํŠธ ๋ฐ `mypy` ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ๋ฌด๊ฒฐ์  ํ†ต๊ณผํ•˜์˜€์œผ๋ฉฐ, `tests/smoke_test_rag.py` ํ†ตํ•ฉ 4๋Œ€ ๊ณจ๋“œ ์‹œ๋‚˜๋ฆฌ์˜ค ์‹คํ–‰ ์‹œ ์ „ ํ•ญ๋ชฉ `โœ… PASS` ๋ฐ **100% GraphRAG (graph mode) ๊ธฐ๋ฐ˜ ์‘๋‹ต๊ณผ ์›๋ณธ URL [์ถœ์ฒ˜ ๋งํฌ] ๋…ธ์ถœ**์„ ์™„๋ฒฝํ•˜๊ฒŒ ๊ฒ€์ฆ ๋ฐ ์ž…์ฆ ์™„๋ฃŒ.
203
+
204
+ - [x] **์ฑ„ํŒ… ์˜์—ญ ๋„ˆ๋น„ 70% ์ถ•์†Œ ๋ฐ ์ƒํ•˜ ๊ฐ„๊ฒฉ(์—ฌ๋ฐฑ) ์ตœ์ ํ™” ๊ฐœ์„  (2026-05-20)**:
205
+ - **ํ˜„์ƒ**: ๋ฉ”์ธ ํ™”๋ฉด ์˜ค๋ฅธ์ชฝ ์ปฌ๋Ÿผ์—์„œ ์ฑ—๋ด‡ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ(์†Œ๊ฐœ ๋ณด๋“œ, ์˜ˆ์‹œ ์งˆ๋ฌธ ๋ฒ„ํŠผ, ๋ฉ”์‹œ์ง€ ๋ฒ„๋ธ”, ์ž…๋ ฅ์ฐฝ)๊ฐ€ ํ™”๋ฉด์„ 100% ๊ฝ‰ ์ฑ„์›Œ ๋‹ค์†Œ ์‹œ๊ฐ์ ์œผ๋กœ ํผ์ ธ ๋ณด์ด๊ณ  ๊ฐ€๋…์„ฑ์ด ์ €ํ•˜๋˜๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ. ๋˜ํ•œ ์ƒ๋‹จ GNB์™€ ์ฑ—๋ด‡ ์‚ฌ์ด์˜ ์ˆ˜์ง ์—ฌ๋ฐฑ ๋ฐ ์ฑ—๋ด‡ ๋‚ด ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ๊ฐ„๊ฒฉ์ด ๋„ˆ๋ฌด ์ปค์„œ ๊ณต๊ฐ„ ๋‚ญ๋น„ ๋ฐœ์ƒ.
206
+ - **์กฐ์น˜**:
207
+ 1. **์šฐ์ธก Column ID ์ง€์ •**: `app.py`์—์„œ ์šฐ์ธก ์ฑ—๋ด‡ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ด๋Š” Column์— `elem_id="chat-column"`์„ ๊ณ ์œ ํ•˜๊ฒŒ ์ง€์ •.
208
+ 2. **์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜ 70% ๋„ˆ๋น„ ํ†ต์ œ**: `src/utils/ui_templates.py`์˜ `CUSTOM_CSS`์—์„œ `#chat-column > div`๋ฅผ ์ง€์ •ํ•˜์—ฌ ์ฑ—๋ด‡ ์ตœ์™ธ๊ณฝ ํ”„๋ ˆ์ž„ ์ „์ฒด๋ฅผ `70%` ๋„ˆ๋น„๋กœ ์ œํ•œํ•˜๊ณ  `margin: 0 auto`๋กœ ์ค‘์•™ ์ •๋ ฌ์„ ๊ฐ•์ œ. ์ด์— ๋งž์ถฐ ๋‚ด๋ถ€ ์ž์‹ ์š”์†Œ๋“ค(`.placeholder`, `.examples-container`, `.message-wrap`, `.input-container`)์€ `width: 100%`๋กœ ๋ถ€๋ชจ ์ปจํ…Œ์ด๋„ˆ์— ๋”ฑ ๋“ค์–ด๋งž๊ฒŒ ์ •๋ ฌํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ ์–ด๊ธ‹๋‚จ ์›์ฒœ ์ œ๊ฑฐ.
209
+ 3. **์ˆ˜์ง ์—ฌ๋ฐฑ ๋Œ€ํญ ๊ธด๋ฐ€ํ™”**: GNB ์•„๋ž˜์˜ ๋ฐ”ํ…€ ๋งˆ์ง„์„ `20px`์—์„œ `6px`๋กœ ์ค„์ด๊ณ  ํŒจ๋”ฉ์„ ์••์ถ•. ์ฑ—๋ด‡ ๋‚ด๋ถ€์˜ ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ๊ฐ„๊ฒฉ(`gap` ๋ฐ `margin`)๊ณผ ๊ฐœ๋ณ„ ๋ณด๋“œ์˜ ์•ˆ์ชฝ ํŒจ๋”ฉ(`padding`)์„ ์ „์ฒด์ ์œผ๋กœ ์ค„์—ฌ(์˜ˆ: ์†Œ๊ฐœ๊ธ€ ํŒจ๋”ฉ `10px 14px`, ๋งˆ์ง„ `4px auto 6px auto` ๋“ฑ) ํ™”๋ฉด ๋‚ด์— ํ•œ๋ˆˆ์— ์™ ๋“ค์–ด์˜ค๋„๋ก ์ตœ์ ํ™”.
210
+ 4. **๋ฐ˜์‘ํ˜• ๋ชจ๋ฐ”์ผ ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ ๊ฐฑ์‹ **: ๊ฐ€๋กœ 800px ์ดํ•˜ ๋ชจ๋ฐ”์ผ ํ™”๋ฉด์—์„œ๋Š” ์ž๋™์œผ๋กœ 100% ๊ฝ‰ ์ฐจ๋„๋ก ๊ฐฑ์‹ ํ•˜์—ฌ ํ”„๋ฆฌ๋ฏธ์—„ UX๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์œ ์ง€.
211
+ - **๊ฒ€์ฆ**: `ruff`์™€ `mypy` ๊ฒ€์‚ฌ๋ฅผ ๋ฌด์˜ค๋ฅ˜ ํ†ต๊ณผํ•จ. `python -c "import app"`์œผ๋กœ Gradio ์›น์•ฑ ๋นŒ๋“œ ๋ฌด๊ฒฐ์„ฑ์„ ์ตœ์ข… ํ™•๋ณดํ•จ.
app.py CHANGED
@@ -334,10 +334,10 @@ interface_kwargs = {
334
  submit_btn="์ „์†ก",
335
  ),
336
  "examples": [
337
- "์‚ผ์„ฑ์ „์ž์˜ ์ตœ๊ทผ AI ๊ธฐ์ˆ  ํŠธ๋ Œ๋“œ๋Š”?",
338
- "์นด์นด์˜ค๊ฐ€ ๊ฐœ๋ฐœ ์ค‘์ธ AI ์„œ๋น„์Šค ๋ชฉ๋ก์„ ์•Œ๋ ค์ค˜",
339
- "์–ด๋–ค ๊ธฐ์—…์ด LLM ๊ธฐ์ˆ ์„ ๊ฐœ๋ฐœํ•˜๋‚˜์š”?",
340
- "์ตœ๊ทผ AI ๊ด€๋ จ ๋‰ด์Šค ๊ธฐ์‚ฌ๋ฅผ ์š”์•ฝํ•ด์ค˜",
341
  ],
342
  "cache_examples": False,
343
  }
@@ -349,7 +349,7 @@ launch_kwargs = {
349
  }
350
 
351
  # ๋ฒ„์ „์— ๋งž์ถ˜ ํ…Œ๋งˆ ๋ฐ CSS ์ฃผ์ž… ํŒŒ์ดํ”„๋ผ์ธ (Gradio 6.x ํ˜ธํ™˜์„ฑ ๋ณด์žฅ)
352
- blocks_kwargs = {}
353
  if gradio_major < 5:
354
  interface_kwargs["theme"] = theme_obj
355
  blocks_kwargs["theme"] = theme_obj
@@ -366,7 +366,7 @@ else:
366
  with gr.Blocks(**blocks_kwargs) as demo:
367
  # 1. ์ƒ๋‹จ ๊ธ€๋กœ๋ฒŒ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” (GNB)
368
  gr.HTML("""
369
- <div style="display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; border-bottom: 1px solid rgba(196, 195, 236, 0.45); background-color: rgba(255, 255, 255, 0.65); backdrop-filter: blur(12px); margin: -20px -20px 20px -20px;">
370
  <div style="font-size: 20px; font-weight: 900; color: #0f172a; display: flex; align-items: center; gap: 12px;">
371
  ๐Ÿ“ˆ FinGraph <span style="font-size: 14px; font-weight: 700; color: #475569;">GraphRAG Enhanced AI Terminal</span>
372
  </div>
@@ -381,14 +381,14 @@ with gr.Blocks(**blocks_kwargs) as demo:
381
  gr.HTML(stats_html)
382
 
383
  # 3. ์˜ค๋ฅธ์ชฝ ์ปฌ๋Ÿผ: ๋ฉ”์ธ ์ฑ—๋ด‡ ์—์–ด๋ฆฌ์–ด - 3:7 split์„ ์œ„ํ•ด scale=7 ์„ค์ •
384
- with gr.Column(scale=7, min_width=500):
385
  # ChatInterface without redundant titles/descriptions
386
- chatbot_interface_kwargs = interface_kwargs.copy()
387
  chatbot_interface_kwargs.pop("title", None)
388
  chatbot_interface_kwargs.pop("description", None)
389
  chatbot_interface_kwargs.pop("theme", None)
390
 
391
- gr.ChatInterface(**chatbot_interface_kwargs)
392
 
393
  if __name__ == "__main__":
394
  demo.launch(**launch_kwargs)
 
334
  submit_btn="์ „์†ก",
335
  ),
336
  "examples": [
337
+ "์‚ผ์„ฑ์ „์ž์˜ ์ž์ฒด AI ๋ชจ๋ธ์ธ '์‚ผ์„ฑ ๊ฐ€์šฐ์Šค 2'์˜ ํŠน์ง•๊ณผ ์ฃผ์š” ์ ์šฉ ๊ณ„ํš์„ ์•Œ๋ ค์ค˜",
338
+ "์นด์นด์˜ค๊ฐ€ ๊ณต๊ฐœํ•œ AI ๋ธŒ๋žœ๋“œ '์นด๋‚˜๋‚˜(Kanana)'์™€ ์นด๋‚˜๋‚˜ ์›Œํฌ ๋“ฑ ์„œ๋น„์Šค ๋ผ์ธ์—…์„ ์„ค๋ช…ํ•ด์ค˜",
339
+ "AWS๊ฐ€ ๊ฐ•์กฐํ•˜๋Š” 'ํ”ผ์ง€์ปฌ AI'์™€ '์—์ด์ „ํ‹ฑ AI' ๊ธฐ์ˆ ์˜ ํ•œ๊ตญ ์‹œ์žฅ ์ง€์› ๋ฐ ํ˜‘๋ ฅ ๋ฐฉ์•ˆ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?",
340
+ "๊ตฌ๊ธ€์ด I/O ํ–‰์‚ฌ์—์„œ ๋ฐœํ‘œํ•œ AI ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ๋ณ€ํ™”์™€ '์ œ๋ฏธ๋‚˜์ด(Gemini)' ๊ธฐ์ˆ ์˜ ์ ์šฉ ์‚ฌ๋ก€๋ฅผ ์•Œ๋ ค์ค˜",
341
  ],
342
  "cache_examples": False,
343
  }
 
349
  }
350
 
351
  # ๋ฒ„์ „์— ๋งž์ถ˜ ํ…Œ๋งˆ ๋ฐ CSS ์ฃผ์ž… ํŒŒ์ดํ”„๋ผ์ธ (Gradio 6.x ํ˜ธํ™˜์„ฑ ๋ณด์žฅ)
352
+ blocks_kwargs: Dict[str, Any] = {}
353
  if gradio_major < 5:
354
  interface_kwargs["theme"] = theme_obj
355
  blocks_kwargs["theme"] = theme_obj
 
366
  with gr.Blocks(**blocks_kwargs) as demo:
367
  # 1. ์ƒ๋‹จ ๊ธ€๋กœ๋ฒŒ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” (GNB)
368
  gr.HTML("""
369
+ <div style="display: flex; justify-content: space-between; align-items: center; padding: 10px 20px; border-bottom: 1px solid rgba(196, 195, 236, 0.45); background-color: rgba(255, 255, 255, 0.65); backdrop-filter: blur(12px); margin: -20px -20px 6px -20px;">
370
  <div style="font-size: 20px; font-weight: 900; color: #0f172a; display: flex; align-items: center; gap: 12px;">
371
  ๐Ÿ“ˆ FinGraph <span style="font-size: 14px; font-weight: 700; color: #475569;">GraphRAG Enhanced AI Terminal</span>
372
  </div>
 
381
  gr.HTML(stats_html)
382
 
383
  # 3. ์˜ค๋ฅธ์ชฝ ์ปฌ๋Ÿผ: ๋ฉ”์ธ ์ฑ—๋ด‡ ์—์–ด๋ฆฌ์–ด - 3:7 split์„ ์œ„ํ•ด scale=7 ์„ค์ •
384
+ with gr.Column(scale=7, min_width=500, elem_id="chat-column"):
385
  # ChatInterface without redundant titles/descriptions
386
+ chatbot_interface_kwargs: Dict[str, Any] = interface_kwargs.copy()
387
  chatbot_interface_kwargs.pop("title", None)
388
  chatbot_interface_kwargs.pop("description", None)
389
  chatbot_interface_kwargs.pop("theme", None)
390
 
391
+ gr.ChatInterface(**chatbot_interface_kwargs) # type: ignore
392
 
393
  if __name__ == "__main__":
394
  demo.launch(**launch_kwargs)
src/utils/ui_templates.py CHANGED
@@ -231,13 +231,30 @@ div[data-testid="chatbot"], .chatbot-container, .chatbot {
231
  border: none !important;
232
  }
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  /* โ”€โ”€ ์ฑ—๋ด‡ ๋‚ด๋ถ€ Placeholder(์†Œ๊ฐœ๊ธ€ ์˜์—ญ) โ”€โ”€ */
235
  .placeholder, [class*="placeholder"] {
236
  padding: 0 !important;
237
  overflow: auto !important;
238
  margin: 0 auto !important;
239
  width: 100% !important;
240
- max-width: 920px !important;
241
  }
242
 
243
  /* โ”€โ”€ ์†Œ๊ฐœ๊ธ€(Prose) ์›ฐ์ปด ๋ณด๋“œ (๋…๋ฆฝ์ ์ธ ํ”„๋ฆฌ๋ฏธ์—„ ๋ผ์šด๋“œ ์นด๋“œ ๊ตฌ์กฐ) โ”€โ”€ */
@@ -245,8 +262,8 @@ div[data-testid="chatbot"], .chatbot-container, .chatbot {
245
  background: #f8fafc !important;
246
  border: 1px solid #e2e8f0 !important;
247
  border-radius: 12px !important;
248
- padding: 24px !important;
249
- max-width: 920px !important;
250
  width: 100% !important;
251
  margin: 0 auto !important;
252
  display: block !important;
@@ -257,32 +274,33 @@ div[data-testid="chatbot"], .chatbot-container, .chatbot {
257
  .placeholder h3, [class*="placeholder"] h3 {
258
  color: #334155 !important;
259
  font-weight: 800 !important;
260
- font-size: 17.5px !important;
261
  margin-top: 0 !important;
262
- margin-bottom: 12px !important;
263
  }
264
  .placeholder .prose ul {
265
  list-style-type: none !important;
266
  padding-left: 0 !important;
267
- margin-bottom: 12px !important;
268
  }
269
  .placeholder .prose li {
270
- margin-bottom: 6px !important;
271
  color: #475569 !important;
272
- font-size: 14.5px !important;
273
- line-height: 1.55 !important;
274
  }
275
  .placeholder .prose p {
276
- font-size: 14.5px !important;
277
- line-height: 1.55 !important;
 
278
  }
279
  .placeholder .prose p:last-child {
280
- font-size: 14.5px !important;
281
  font-weight: 700 !important;
282
  color: #4c1d95 !important;
283
  background: #f3e8ff !important;
284
- padding: 8px 16px !important;
285
- border-radius: 8px !important;
286
  display: inline-block !important;
287
  margin-bottom: 0 !important;
288
  }
@@ -291,14 +309,14 @@ div[data-testid="chatbot"], .chatbot-container, .chatbot {
291
  [class*="examples"], .gr-samples-wrapper, .examples-container {
292
  display: grid !important;
293
  grid-template-columns: repeat(2, 1fr) !important;
294
- gap: 12px !important;
295
  width: 100% !important;
296
- max-width: 920px !important;
297
- margin: 16px auto 24px auto !important;
298
  background: #f8fafc !important;
299
  border: 1px solid #e2e8f0 !important;
300
  border-radius: 12px !important;
301
- padding: 24px !important;
302
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05) !important;
303
  position: relative !important;
304
  z-index: 1 !important;
@@ -307,9 +325,9 @@ div[data-testid="chatbot"], .chatbot-container, .chatbot {
307
  /* ๊ฐœ๋ณ„ ๋ฒ„ํŠผ ๋””์ž์ธ (์—ฐ๋ณด๋ผ์ƒ‰ ํ…Œ๋งˆ & ๊ฐ•๋ ฅํ•œ ์ค‘์•™ ์ •๋ ฌ) */
308
  .examples-container button, div[data-testid="chatbot"] button.example, button.example, .example-btn {
309
  border-radius: 8px !important;
310
- padding: 16px !important;
311
  text-align: center !important;
312
- font-size: 14px !important;
313
  font-weight: 600 !important;
314
  color: #4c1d95 !important;
315
  background: #f5f3ff !important;
@@ -320,7 +338,7 @@ div[data-testid="chatbot"], .chatbot-container, .chatbot {
320
  display: flex !important;
321
  align-items: center !important;
322
  justify-content: center !important;
323
- min-height: 80px !important;
324
  width: 100% !important;
325
  white-space: normal !important;
326
  }
@@ -390,8 +408,13 @@ textarea:focus {
390
  div:has(> button[class*="submit-btn"]),
391
  div:has(> [data-testid="submit-button"]),
392
  .input-container, [class*="input-container"] {
393
- gap: 9px !important;
394
  align-items: center !important;
 
 
 
 
 
395
  }
396
 
397
  /* โ”€โ”€ ์ฑ—๋ด‡ ํƒญ/๋ผ๋ฒจ ์ˆจ๊น€ โ”€โ”€ */
@@ -404,7 +427,13 @@ label.svelte-1ipelgc, span.svelte-1ipelgc {
404
  display: none !important;
405
  }
406
 
407
- /* โ”€โ”€ ๋ฉ”์‹œ์ง€ ๋ฒ„๋ธ” ๊ธฐ๋ณธ ํฌ๊ธฐ ์ถ•์†Œ (์‚ฌ์šฉ์ž/๋ด‡ ๊ณตํ†ต ์„ธ๋กœ ๋†’์ด ์ตœ์ ํ™”) โ”€โ”€ */
 
 
 
 
 
 
408
  .message,
409
  .message-wrap .message,
410
  [data-testid="user-message"],
@@ -540,6 +569,19 @@ div[data-testid="chatbot"] > div.scrollbar {
540
  overflow-y: auto !important;
541
  max-height: 600px !important;
542
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  """
544
 
545
 
 
231
  border: none !important;
232
  }
233
 
234
+ /* โ”€โ”€ ์ฑ—๋ด‡ ์˜์—ญ ๋„ˆ๋น„ 70% ์ œ์–ด ๋ฐ ์ค‘์•™ ์ •๋ ฌ โ”€โ”€ */
235
+ #chat-column {
236
+ display: flex !important;
237
+ flex-direction: column !important;
238
+ align-items: center !important;
239
+ width: 100% !important;
240
+ }
241
+ #chat-column > div,
242
+ #chat-column > .form {
243
+ width: 70% !important;
244
+ max-width: 960px !important;
245
+ margin: 0 auto !important;
246
+ display: flex !important;
247
+ flex-direction: column !important;
248
+ gap: 6px !important; /* ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ์œ„์•„๋ž˜ ๊ฐ„๊ฒฉ ์ถ•์†Œ */
249
+ }
250
+
251
  /* โ”€โ”€ ์ฑ—๋ด‡ ๋‚ด๋ถ€ Placeholder(์†Œ๊ฐœ๊ธ€ ์˜์—ญ) โ”€โ”€ */
252
  .placeholder, [class*="placeholder"] {
253
  padding: 0 !important;
254
  overflow: auto !important;
255
  margin: 0 auto !important;
256
  width: 100% !important;
257
+ max-width: 100% !important;
258
  }
259
 
260
  /* โ”€โ”€ ์†Œ๊ฐœ๊ธ€(Prose) ์›ฐ์ปด ๋ณด๋“œ (๋…๋ฆฝ์ ์ธ ํ”„๋ฆฌ๋ฏธ์—„ ๋ผ์šด๋“œ ์นด๋“œ ๊ตฌ์กฐ) โ”€โ”€ */
 
262
  background: #f8fafc !important;
263
  border: 1px solid #e2e8f0 !important;
264
  border-radius: 12px !important;
265
+ padding: 10px 14px !important; /* ํŒจ๋”ฉ ์ถ•์†Œ */
266
+ max-width: 100% !important;
267
  width: 100% !important;
268
  margin: 0 auto !important;
269
  display: block !important;
 
274
  .placeholder h3, [class*="placeholder"] h3 {
275
  color: #334155 !important;
276
  font-weight: 800 !important;
277
+ font-size: 15px !important; /* ํฐํŠธ ์‚ด์ง ์ถ•์†Œ */
278
  margin-top: 0 !important;
279
+ margin-bottom: 6px !important;
280
  }
281
  .placeholder .prose ul {
282
  list-style-type: none !important;
283
  padding-left: 0 !important;
284
+ margin-bottom: 6px !important;
285
  }
286
  .placeholder .prose li {
287
+ margin-bottom: 2px !important; /* ๊ฐ„๊ฒฉ ์ถ•์†Œ */
288
  color: #475569 !important;
289
+ font-size: 13px !important;
290
+ line-height: 1.4 !important;
291
  }
292
  .placeholder .prose p {
293
+ font-size: 13px !important;
294
+ line-height: 1.4 !important;
295
+ margin-bottom: 4px !important;
296
  }
297
  .placeholder .prose p:last-child {
298
+ font-size: 12.5px !important;
299
  font-weight: 700 !important;
300
  color: #4c1d95 !important;
301
  background: #f3e8ff !important;
302
+ padding: 4px 10px !important; /* ํŒจ๋”ฉ ์ถ•์†Œ */
303
+ border-radius: 6px !important;
304
  display: inline-block !important;
305
  margin-bottom: 0 !important;
306
  }
 
309
  [class*="examples"], .gr-samples-wrapper, .examples-container {
310
  display: grid !important;
311
  grid-template-columns: repeat(2, 1fr) !important;
312
+ gap: 6px !important; /* ๊ฐญ ์ถ•์†Œ */
313
  width: 100% !important;
314
+ max-width: 100% !important;
315
+ margin: 4px auto 6px auto !important; /* ๋งˆ์ง„ ์ถ•์†Œ */
316
  background: #f8fafc !important;
317
  border: 1px solid #e2e8f0 !important;
318
  border-radius: 12px !important;
319
+ padding: 10px 14px !important; /* ํŒจ๋”ฉ ์ถ•์†Œ */
320
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05) !important;
321
  position: relative !important;
322
  z-index: 1 !important;
 
325
  /* ๊ฐœ๋ณ„ ๋ฒ„ํŠผ ๋””์ž์ธ (์—ฐ๋ณด๋ผ์ƒ‰ ํ…Œ๋งˆ & ๊ฐ•๋ ฅํ•œ ์ค‘์•™ ์ •๋ ฌ) */
326
  .examples-container button, div[data-testid="chatbot"] button.example, button.example, .example-btn {
327
  border-radius: 8px !important;
328
+ padding: 10px 12px !important;
329
  text-align: center !important;
330
+ font-size: 13px !important;
331
  font-weight: 600 !important;
332
  color: #4c1d95 !important;
333
  background: #f5f3ff !important;
 
338
  display: flex !important;
339
  align-items: center !important;
340
  justify-content: center !important;
341
+ min-height: 52px !important;
342
  width: 100% !important;
343
  white-space: normal !important;
344
  }
 
408
  div:has(> button[class*="submit-btn"]),
409
  div:has(> [data-testid="submit-button"]),
410
  .input-container, [class*="input-container"] {
411
+ gap: 6px !important; /* ๊ฐญ ์ถ•์†Œ */
412
  align-items: center !important;
413
+ max-width: 100% !important;
414
+ width: 100% !important;
415
+ margin-left: 0 !important;
416
+ margin-right: 0 !important;
417
+ margin-top: 4px !important; /* ์œ„์•„๋ž˜ ๊ฐ„๊ฒฉ ์ตœ์ ํ™” */
418
  }
419
 
420
  /* โ”€โ”€ ์ฑ—๋ด‡ ํƒญ/๋ผ๋ฒจ ์ˆจ๊น€ โ”€โ”€ */
 
427
  display: none !important;
428
  }
429
 
430
+ /* โ”€โ”€ ๋ฉ”์‹œ์ง€ ๋ฒ„๋ธ” ๊ธฐ๋ณธ ํฌ๊ธฐ ์ถ•์†Œ (์‚ฌ์šฉ์ž/๋ด‡ ๊ณตํ†ต ์„ธ๋กœ ๋†’์ด ์ตœ์ ํ™” & 100% ๋ถ€๋ชจ ๋„ˆ๋น„ ์ฑ„์›€) โ”€โ”€ */
431
+ .message-wrap, .message-container, div[data-testid="chatbot"] .wrapper {
432
+ max-width: 100% !important;
433
+ width: 100% !important;
434
+ margin-left: 0 !important;
435
+ margin-right: 0 !important;
436
+ }
437
  .message,
438
  .message-wrap .message,
439
  [data-testid="user-message"],
 
569
  overflow-y: auto !important;
570
  max-height: 600px !important;
571
  }
572
+
573
+ /* โ”€โ”€ ๋ชจ๋ฐ”์ผ ํ™”๋ฉด ๋Œ€์‘: 800px ์ดํ•˜์—์„œ๋Š” 100% ๋„ˆ๋น„ โ”€โ”€ */
574
+ @media (max-width: 800px) {
575
+ #chat-column > div,
576
+ #chat-column > .form {
577
+ width: 100% !important;
578
+ max-width: 100% !important;
579
+ }
580
+ [class*="examples"], .gr-samples-wrapper, .examples-container {
581
+ grid-template-columns: 1fr !important;
582
+ padding: 10px !important;
583
+ }
584
+ }
585
  """
586
 
587
 
tests/smoke_test_rag.py CHANGED
@@ -188,39 +188,39 @@ if __name__ == "__main__":
188
 
189
  results = []
190
 
191
- # ์‹œ๋‚˜๋ฆฌ์˜ค 1: ์‚ผ์„ฑ์ „์ž AI ๊ธฐ์ˆ  ํŠธ๋ Œ๋“œ
192
  results.append(run_scenario(
193
- label="โ‘  ํŠน์ • ๊ธฐ์—… โ€” ์‚ผ์„ฑ์ „์ž์˜ ์ตœ๊ทผ AI ๊ธฐ์ˆ  ํŠธ๋ Œ๋“œ๋Š”?",
194
- query="์‚ผ์„ฑ์ „์ž์˜ ์ตœ๊ทผ AI ๊ธฐ์ˆ  ํŠธ๋ Œ๋“œ๋Š”?",
195
- expected_keywords=["์‚ผ์„ฑ์ „์ž", "AI", "๊ธฐ์ˆ "],
196
  ))
197
 
198
- # ์‹œ๋‚˜๋ฆฌ์˜ค 2: ์นด์นด์˜ค AI ์„œ๋น„์Šค
199
  results.append(run_scenario(
200
- label="โ‘ก ํŠน์ • ๊ธฐ์—… โ€” ์นด์นด์˜ค๊ฐ€ ๊ฐœ๋ฐœ ์ค‘์ธ AI ์„œ๋น„์Šค ๋ชฉ๋ก์„ ์•Œ๋ ค์ค˜",
201
- query="์นด์นด์˜ค๊ฐ€ ๊ฐœ๋ฐœ ์ค‘์ธ AI ์„œ๋น„์Šค ๋ชฉ๋ก์„ ์•Œ๋ ค์ค˜",
202
- expected_keywords=["์นด์นด์˜ค", "AI", "์„œ๋น„์Šค"],
203
  ))
204
 
205
- # ์‹œ๋‚˜๋ฆฌ์˜ค 3: LLM ๊ธฐ์ˆ  ๊ฐœ๋ฐœ ๊ธฐ์—…
206
  results.append(run_scenario(
207
- label="โ‘ข ํŠน์ • ๊ธฐ์ˆ  โ€” ์–ด๋–ค ๊ธฐ์—…์ด LLM ๊ธฐ์ˆ ์„ ๊ฐœ๋ฐœํ•˜๋‚˜์š”?",
208
- query="์–ด๋–ค ๊ธฐ์—…์ด LLM ๊ธฐ์ˆ ์„ ๊ฐœ๋ฐœํ•˜๋‚˜์š”?",
209
- expected_keywords=["LLM"],
210
  ))
211
 
212
- # ์‹œ๋‚˜๋ฆฌ์˜ค 4: ์ตœ๊ทผ AI ๋‰ด์Šค ๊ธฐ์‚ฌ ์š”์•ฝ
213
  results.append(run_scenario(
214
- label="โ‘ฃ ์ „์ฒด ํŠธ๋ Œ๋“œ โ€” ์ตœ๊ทผ AI ๊ด€๋ จ ๋‰ด์Šค ๊ธฐ์‚ฌ๋ฅผ ์š”์•ฝํ•ด์ค˜",
215
- query="์ตœ๊ทผ AI ๊ด€๋ จ ๋‰ด์Šค ๊ธฐ์‚ฌ๋ฅผ ์š”์•ฝํ•ด์ค˜",
216
- expected_keywords=["AI"],
217
  ))
218
 
219
  # ์ตœ์ข… ์š”์•ฝ
220
  print("=" * 60)
221
  print("๐Ÿ“‹ ์ตœ์ข… ์š”์•ฝ")
222
  print("=" * 60)
223
- labels = ["โ‘  ์‚ผ์„ฑ์ „์ž AI ํŠธ๋ Œ๋“œ", "โ‘ก ์นด์นด์˜ค AI ์„œ๋น„์Šค", "โ‘ข LLM ๊ฐœ๋ฐœ ๊ธฐ์—…", "โ‘ฃ ์ตœ๊ทผ AI ๋‰ด์Šค ์š”์•ฝ"]
224
  for label, passed in zip(labels, results):
225
  print(f" {'โœ… PASS' if passed else 'โš ๏ธ PARTIAL'} | {label}")
226
  print()
 
188
 
189
  results = []
190
 
191
+ # ์‹œ๋‚˜๋ฆฌ์˜ค 1: ์‚ผ์„ฑ์ „์ž ๊ฐ€์šฐ์Šค 2 AI ํŠธ๋ Œ๋“œ
192
  results.append(run_scenario(
193
+ label="โ‘  ์‚ผ์„ฑ์ „์ž โ€” ์‚ผ์„ฑ์ „์ž์˜ ์ž์ฒด AI ๋ชจ๋ธ์ธ '์‚ผ์„ฑ ๊ฐ€์šฐ์Šค 2'์˜ ํŠน์ง•๊ณผ ์ฃผ์š” ์ ์šฉ ๊ณ„ํš์„ ์•Œ๋ ค์ค˜",
194
+ query="์‚ผ์„ฑ์ „์ž์˜ ์ž์ฒด AI ๋ชจ๋ธ์ธ '์‚ผ์„ฑ ๊ฐ€์šฐ์Šค 2'์˜ ํŠน์ง•๊ณผ ์ฃผ์š” ์ ์šฉ ๊ณ„ํš์„ ์•Œ๋ ค์ค˜",
195
+ expected_keywords=["์‚ผ์„ฑ", "๊ฐ€์šฐ์Šค"],
196
  ))
197
 
198
+ # ์‹œ๋‚˜๋ฆฌ์˜ค 2: ์นด์นด์˜ค ์นด๋‚˜๋‚˜ AI ๋ธŒ๋žœ๋“œ
199
  results.append(run_scenario(
200
+ label="โ‘ก ์นด์นด์˜ค โ€” ์นด์นด์˜ค๊ฐ€ ๊ณต๊ฐœํ•œ AI ๋ธŒ๋žœ๋“œ '์นด๋‚˜๋‚˜(Kanana)'์™€ ์นด๋‚˜๋‚˜ ์›Œํฌ ๋“ฑ ์„œ๋น„์Šค ๋ผ์ธ์—…์„ ์„ค๋ช…ํ•ด์ค˜",
201
+ query="์นด์นด์˜ค๊ฐ€ ๊ณต๊ฐœํ•œ AI ๋ธŒ๋žœ๋“œ '์นด๋‚˜๋‚˜(Kanana)'์™€ ์นด๋‚˜๋‚˜ ์›Œํฌ ๋“ฑ ์„œ๋น„์Šค ๋ผ์ธ์—…์„ ์„ค๋ช…ํ•ด์ค˜",
202
+ expected_keywords=["์นด์นด์˜ค", "์นด๋‚˜๋‚˜"],
203
  ))
204
 
205
+ # ์‹œ๋‚˜๋ฆฌ์˜ค 3: AWS ํ”ผ์ง€์ปฌ AI ๋ฐ ์—์ด์ „ํ‹ฑ AI
206
  results.append(run_scenario(
207
+ label="โ‘ข AWS โ€” AWS๊ฐ€ ๊ฐ•์กฐํ•˜๋Š” 'ํ”ผ์ง€์ปฌ AI'์™€ '์—์ด์ „ํ‹ฑ AI' ๊ธฐ์ˆ ์˜ ํ•œ๊ตญ ์‹œ์žฅ ์ง€์› ๋ฐ ํ˜‘๋ ฅ ๋ฐฉ์•ˆ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?",
208
+ query="AWS๊ฐ€ ๊ฐ•์กฐํ•˜๋Š” 'ํ”ผ์ง€์ปฌ AI'์™€ '์—์ด์ „ํ‹ฑ AI' ๊ธฐ์ˆ ์˜ ํ•œ๊ตญ ์‹œ์žฅ ์ง€์› ๋ฐ ํ˜‘๋ ฅ ๋ฐฉ์•ˆ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?",
209
+ expected_keywords=["AWS", "ํ”ผ์ง€์ปฌ", "์—์ด์ „ํ‹ฑ"],
210
  ))
211
 
212
+ # ์‹œ๋‚˜๋ฆฌ์˜ค 4: ๊ตฌ๊ธ€ I/O ์ œ๋ฏธ๋‚˜์ด ๊ธฐ์ˆ  ๋ณ€ํ™”
213
  results.append(run_scenario(
214
+ label="โ‘ฃ ๊ตฌ๊ธ€ โ€” ๊ตฌ๊ธ€์ด I/O ํ–‰์‚ฌ์—์„œ ๋ฐœํ‘œํ•œ AI ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ๋ณ€ํ™”์™€ '์ œ๋ฏธ๋‚˜์ด(Gemini)' ๊ธฐ์ˆ ์˜ ์ ์šฉ ์‚ฌ๋ก€๋ฅผ ์•Œ๋ ค์ค˜",
215
+ query="๊ตฌ๊ธ€์ด I/O ํ–‰์‚ฌ์—์„œ ๋ฐœํ‘œํ•œ AI ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ๋ณ€ํ™”์™€ '์ œ๋ฏธ๋‚˜์ด(Gemini)' ๊ธฐ์ˆ ์˜ ์ ์šฉ ์‚ฌ๋ก€๋ฅผ ์•Œ๋ ค์ค˜",
216
+ expected_keywords=["๊ตฌ๊ธ€", "์ œ๋ฏธ๋‚˜์ด"],
217
  ))
218
 
219
  # ์ตœ์ข… ์š”์•ฝ
220
  print("=" * 60)
221
  print("๐Ÿ“‹ ์ตœ์ข… ์š”์•ฝ")
222
  print("=" * 60)
223
+ labels = ["โ‘  ์‚ผ์„ฑ ๊ฐ€์šฐ์Šค 2", "โ‘ก ์นด์นด์˜ค ์นด๋‚˜๋‚˜", "โ‘ข AWS ํ”ผ์ง€์ปฌ AI", "โ‘ฃ ๊ตฌ๊ธ€ ์ œ๋ฏธ๋‚˜์ด"]
224
  for label, passed in zip(labels, results):
225
  print(f" {'โœ… PASS' if passed else 'โš ๏ธ PARTIAL'} | {label}")
226
  print()