๋ณธ ํ๋ก์ ํธ๋ ๋ค์ด๋ฒ ๋ด์ค ๋๊ธ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก, ๋๊ธ์ด ์ธ๊ฐ(ํด๋จผ)์ด ์์ฑํ ๊ฒ์ธ์ง ์๋ ์์ฑ(๋ด)๋ ๊ฒ์ธ์ง ํ๋ณํ๋ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ๊ฐ๋ฐํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
์ค์ ์ฌ์ฉ์ ๋๊ธ(์ธ๊ฐ ๋ฐ์ดํฐ)๊ณผ Ollama ๊ธฐ๋ฐ LLM์ผ๋ก ์์ฑํ ๋ด ๋๊ธ์ ์์งยท์์ฑํ์ฌ ๋น๊ต ํ์ต์ฉ ๋ฐ์ดํฐ์
์ ๊ตฌ์ถํฉ๋๋ค.
- ๋ชฉํ: ์ธ๊ฐ/๋ด ๋๊ธ ๋ถ๋ฅ ๋ชจ๋ธ ๊ฐ๋ฐ
- ๋ฐ์ดํฐ ์์ค:
- ์ธ๊ฐ ๋๊ธ
1942๊ฐ: ๋ค์ด๋ฒ ๊ณต์ ๋๊ธ API (cbox) ์์ง - ๋ด ๋๊ธ
1982๊ฐ: Ollamagpt-oss:20b๋ชจ๋ธ๋ก ๊ธฐ์ฌ ๊ธฐ๋ฐ ์์ฑ + ํจ๋ฌํ๋ ์ด์ง
- ์ธ๊ฐ ๋๊ธ
- ์ต์ข
์ฐ์ถ๋ฌผ:
judge๋ ์ด๋ธ ํฌํจ ๋ฐ์ดํฐ์ โ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ ํ์ต
| Category | Technology |
|---|---|
์ธ์ด |
Python 3.10 |
LLM |
Ollama (gpt-oss:20b) |
DB |
MySQL + SQLAlchemy (ORM) |
ํฌ๋กค๋ง |
Requests, BeautifulSou |
| Column | Type | Description |
|---|---|---|
newID |
INT PK | ๋ด์ค ์๋ณ ID |
Title |
LONGTEXT | ๊ธฐ์ฌ ์ ๋ชฉ |
Content |
LONGTEXT | ๊ธฐ์ฌ ๋ณธ๋ฌธ ๋ด์ฉ |
| Column | Type | Description |
|---|---|---|
commentID |
INT PK | ๋๊ธ ์๋ณ ID |
newID |
INT FK | ์ฐ๊ฒฐ๋ ๋ด์ค ID (NEWS.newID) |
comment |
LONGTEXT | ๋๊ธ ๋ด์ฉ |
judge |
INT | 0 = ํด๋จผ ๋๊ธ, 1 = ๋ด ๋๊ธ (๋ ์ด๋ธ) |
graph TD
A[๋ด์ค ๊ธฐ์ฌ ํฌ๋กค๋ง<br>Title + Content] --> B[(MySQL: NEWS)]
C[๋ค์ด๋ฒ cbox API<br>์ค์ ๋๊ธ ์์ง] --> D[(MySQL: COMMENT, judge=0)]
B --> E[Ollama gpt-oss:20b<br>๊ธฐ์ฌ ๊ธฐ๋ฐ 4๊ฐ ๋๊ธ ์์ฑ]
E --> F[๊ฐ ๋๊ธ๋ณ ํจ๋ฌํ๋ ์ด์ง<br>์๋ฏธ ์ ์ง + ์์ฐ์ด ๋ณํ]
F --> G[(MySQL: COMMENT, judge=1)]
D & G --> H[๋ฐ์ดํฐ์
์์ฑ<br>ํด๋จผ + ๋ด ๋๊ธ]
H --> I[ML ๋ชจ๋ธ ํ์ต<br>์ง์ ํ๋ณ]
- ๋ค์ด๋ฒ ๋ด์ค ์น์ URL ์์ง
- BeautifulSoup + Requests๋ก ์ ๋ชฉ + ๋ณธ๋ฌธ ํฌ๋กค๋ง
- SQLAlchemy๋ก NEWS ํ ์ด๋ธ ์ ์ฅ
- ๋ค์ด๋ฒ ๊ณต์ cbox API ์ฌ์ฉ
- moreParam.next ํ์ด์ง ์ฒ๋ฆฌ๋ก ๋ค์ค ํ์ด์ง ๋ก๋ฉ
- judge=0์ผ๋ก COMMENT ํ ์ด๋ธ ์ ์ฅ
import ollama
def generate_comment(article):
prompt = f"""
๋ค์ ๊ธฐ์ฌ ์ ๋ชฉ๊ณผ ๋ณธ๋ฌธ์ ์ฐธ๊ณ ํ์ฌ ์์ฐ์ค๋ฝ๊ณ ๊ณต๊ฐ ๊ฐ๋ฅํ ๋๊ธ์ 4๊ฐ ์์ฑ,
๋๊ธ์ ๊ธธ์ด๋ ์ต๋ 100 ์ต์ 40 ๊ธธ์ด๋ก ๋ค์ํ๊ฒ ์์ฑ, ํน์๊ธฐํธ ์ฌ์ฉ ๊ธ์ง.
์ ๋ชฉ: {article['title']}
๋ณธ๋ฌธ: {article['content']}
"""
response = ollama.chat(
model="gpt-oss:20b",
messages=[{"role": "user", "content": prompt}]
)
return response["message"]["content"].strip()def paraphrase_comment(comment_text):
prompt = f"""
๋ค์ ๋๊ธ์ ์์ฐ์ค๋ฝ๊ฒ ๋ฐ๊พธ๋, ์๋ฏธ๋ ์ ์งํ์ธ์.
๊ธธ์ด๋ ์ต๋ 100์, ์ต์ 40์๋ก ๋ค์ํ๊ฒ ์์ฑํ๊ณ , ํน์๊ธฐํธ ์ฌ์ฉ ๊ธ์ง:
๋๊ธ: {comment_text}
"""
response = ollama.chat(
model="gpt-oss:20b",
messages=[{"role": "user", "content": prompt}]
)
return response["message"]["content"].strip()- ๊ฐ ์์ฑ ๋๊ธ โ 1ํ ์ด์ ํจ๋ฌํ๋ ์ด์ง
- ์๋ฏธ ์ ์ง ์ฌ๋ถ ๋ฐ ์์ฐ์ค๋ฌ์ ๊ฒ์ฆ ํ ์ ์ฅ
| ์๋ณธ ๋๊ธ | ํจ๋ฌํ๋ ์ด์ง๋ ๋๊ธ |
|---|---|
| ์ ๋นํ ์กฐ์ฌ๋ฅผ ๊ธฐ๋ํฉ๋๋ค. ๊ตฐ ์ธ๋ ฅ ์ ๊ฐ์ด ์๋ ์ ๋นํ ์์ฌ๋ผ๋ ์ ์ด ์ค์ํด์. | ์ ๋นํ ์กฐ์ฌ๋ฅผ ๊ธฐ๋ํ๋ฉฐ, ๊ตฐ ์ธ๋ ฅ ์ ๊ฐ์ด ์๋๋ผ ์ค์ ์์ฌ์ ์ค์ ์ ๋๋ ์ ์ด ์ค์ํฉ๋๋ค. |
| ์ ๋ ํ ์ ์์ฅ์ด ๋งํ ํ์ถ์ด ์ ๋ง ํ์ํ๋ ์๊ฐ์ด๋ผ๊ณ ์๊ฐํด์ | ์ ๋ ํ ์ ์์ฅ์ด ๋งํ ํ์ถ์ด ๊ทธ๋ ์ ๋ง ํ์ํ๋ ์๊ฐ์ด๋ผ๊ณ ์๊ฐํด์ |
- ์์ฑ/ํจ๋ฌํ๋ ์ด์ง ๋๊ธ โ judge=1๋ก ์ ์ฅ
- judge ํ๋๋ฅผ ๋ถ๋ฅ ๋ชจ๋ธ์ ์ ๋ต ๋ ์ด๋ธ๋ก ์ฌ์ฉ
- ๋ด์ค ๊ธฐ์ฌ ์์ง โ NEWS ์ ์ฅ
- ์ค์ ๋๊ธ ์์ง โ COMMENT (judge=0)
- ๋ด ๋๊ธ ์์ฑ (4๊ฐ/๊ธฐ์ฌ)
- ํจ๋ฌํ๋ ์ด์ง ์ํ
- ๋ด ๋๊ธ ์ ์ฅ (judge=1)
- ๋ฐ์ดํฐ์ ์์ฑ โ ML ํ์ต ์ค๋น
| newID | Title | Content |
|---|---|---|
| 3 | ์ ๋ถ, ์ํ์ ์นผ ๋นผ๋ ๋คโฆ"๊ณผ์ง๊ธ ์ต๋ 30๋ฐฐ, ์ ๊ณ ์์๊ฒ ํฌ์๊ธ" | 7์ผ ์ ์ค์ผ๊ตฌ์ฅ์์ ์ด๋ฆฌ๋ 2025KBO๋ฆฌ๊ทธ LGํธ์์ค์ SSG์๋ต |
| 13 | ๋๊ฒฝ์, ๋ผ๋์ค ์๋ฐฉ์ ์งํ์์ "์ ์ฑํธ ๋๋ณ์ธ์ด๋" ๋ฐ๋ | "ๆชข ๋์ฅ๋ ํญ์ ํฌ๊ธฐ๋ ์ธ์โฆ์ ์ฅ๊ด ์
์ฅ์ ์๋ต |
| commentID | newID | comment | judge |
|---|---|---|---|
| 3082 | 3 | ์ ๋ ์ํ๊ฐ ํํ ์ฌํ ๋ฌธ์ ๋ผ์ ์ด๋ฒ ์ ๋ถ ์ ์ฑ ์ ํฌ๋ง์ ๋๊ผ์ด์ ๊ทธ๋ฆฌ๊ณ ์์ผ๋ก๋ ์ ์ฅ๊ถ ๊ฐ๊ฒฉ์ด ์์นํด๋ ์ฐจ๋ผ๋ฆฌ ์ ๊ฐ๋ฅผ ์ง์ผ์ผ ํ ๊ฒ ๊ฐ์์ | 1 |
| 3832 | 3 | ์ ๋ถ๊ฐ ์ํ๋ฅผ ์ก๋ ๋ฐฉ์์ด ๊ณผ์ง๊ธ์ ์ง์คํ๋ ์ ์ด ์ธ์์ ์ด๋ค์ ํ์ง๋ง ์ ๊ณ ์ ํฌ์๋ ๊ผญ ํ์ํ๋ค๊ณ ์๊ฐํด์ | 1 |
| 100 | 13 | ๋๊ฒฝ์์ ํญ์ ๋ ผ๋ฆฌ๊ฐ ๋ธ๋ฆฌ๋๊น ๋ง์ง๋ง์ ๊ผญ ์ธ์ ๊ณต๊ฒฉ์ด์ง. ๋๊ฒฝ์์ด ๊ตญํ์ ๋ํํ๊ณ ๋์๋ ์๊ธฐ ๋์ ๊ตญํ์ด ์ ๋ ์ ์ด ์๋ค | 0 |
| 113 | 13 | ์ 2์ ํ์คํ๋ฉ์์๋ค.. ์งํ์๊ฐ ๋จผ์ง๋ฌธ์ด๋ ํ ์ ์๊ณ , ๋๋ต์์ ์์ผ๋ฉด ๋ชจ๋ฅธ๋ค๊ณ ํ๋ฉด ๋ ์ผ์ด์ง, ์งํ์๋ฅผ ๊ณต๊ฒฉํ๋ ์น์ฌํ์ง์ ํ๋? ๋ฌ์ ๋ด์ผ์ง ์๊ฐ๋ฝ์ ์ง์ ์งํด๋๋ฉด ๋๊ฒ๋? 5์ ์ฉ์ด๋ ๋๋ด์.. ์ด์ ๊ฐ์์ง์ ํ๋ค๋... | 0 |
์๋ณธ CSV ํ์ผ์๋ ๋ค์ ์ปฌ๋ผ์ด ํฌํจ๋์ด ์์ต๋๋ค:
- ๋ด์ค์ ๋ชฉ (title)
- ๋ด์ค๋ด์ฉ (content)
- ๋๊ธ (comment)
- ๋ดํ๋จ (judge, 0: ํด๋ฉด๋๊ธ, 1: ๋ด๋๊ธ)
- ๋ด์ค์ ๋ชฉ, ๋๊ธ ํ ์คํธ๋ฅผ ๊ฒฐํฉํ์ฌ ํ๋์ ๋ฌธ์ฅ ๋จ์ ํ ์คํธ ์์ฑ
- ํ๊ตญ์ด์ ์ต์ ํ๋ Sentence-BERT ๋ชจ๋ธ(
snunlp/KR-SBERT-V40K-klueNLI-augSTS)์ ์ฌ์ฉํด ๋ฌธ์ฅ ์๋ฒ ๋ฉ ์์ฑ - ๊ฐ ํ ์คํธ๋ณ 768์ฐจ์ ๋ฒกํฐ๋ฅผ ์ถ์ถ
- ์๋ฒ ๋ฉ ๋ฒกํฐ์ ๋ดํ๋จ ๋ ์ด๋ธ์ ๋ณ๋๋ก ์ ์ฅํ์ฌ ํ์ต ๋ฐ์ดํฐ๋ก ํ์ฉ
- ๋ฌธ๋งฅ๊ณผ ๋ฌธ์ฅ ์๋ฏธ๋ฅผ ๋ฐ์ํ ์๋ฒ ๋ฉ์ผ๋ก ๋จ์ด ํ๊ท ๋ฐฉ์ ๋๋น ํํ๋ ฅ ํฅ์
- ๋ด์ค์ ๋๊ธ์ ํตํฉํ ๋ฌธ์ฅ ์๋ฒ ๋ฉ์ผ๋ก ๋๊ธ ๋งฅ๋ฝ ํ์ ๊ฐ๋ฅ
- ๋ดํ๋จ ๋ถ๋ฅ ๋ชจ๋ธ ์ฑ๋ฅ ํฅ์์ ๊ธฐ์ฌ
- ์ ์ฅ๋ Sentence-BERT ์๋ฒ ๋ฉ ๋ฒกํฐ์ ๋ ์ด๋ธ์ ๊ธฐ๋ฐ์ผ๋ก ๋จธ์ ๋ฌ๋/๋ฅ๋ฌ๋ ๋ชจ๋ธ ํ์ต
- ๋ด ํ์ง ๋ชจ๋ธ์ ์ ๋ ฅ ํน์ง(feature)์ผ๋ก ํ์ฉ๋์ด ์ ํ๋ ๋ฐ ์ฌํ์จ ๊ฐ์ ๊ธฐ๋
graph TD
A[Input] --> B[Linear input_dim to 32]
B --> C[BatchNorm1d 32]
C --> D[SiLU]
D --> E[Dropout 0.1]
E --> F[Linear 32 to 1]
F --> G[Output]
- Layer: 5๊ฐ
- ์์คํจ์: BCEWithLogitsLoss
- ํ์ฑํํจ์: SiLU
- Early Stopping (patience=20)
- ๋ฐ์ดํฐ ๋ถํ : Train 85% / Valid 7.5% / Test 7.5%
Train / Valid / Test = 3335 294 295
Accuracy : 0.9898 Precision: 1.0000 Recall : 0.9795 F1-score : 0.9896 ROC AUC : 0.9994