๋ธ๋ก๊ทธ๋ฅผ ์ค์๊ฐ AI ์๋น์ค๋ก ๋ณ์ ์ํค๋ TensorFlow.js๋ก ์๋ฒ ๋น์ฉ ์ ๋ก!
๋ธ๋ก๊ทธ์ AI๋ก ์๋ํ, ํค์๋ ์ถ์ถ, SEO ์ต์ ํ ๋ฐฉ๋ฒ: TensorFlow.js ๊ธฐ๋ฐ AI๋ก ๋ฐฉ๋ฌธ์์ ์ํธ์์ฉํ๋ฉฐ, ๊ฒ์ ์์ง์ ์ต์ ํ๋ ์์ฝ๊ณผ ํต์ฌ ํค์๋๋ฅผ ์๋ ์์ฑํฉ๋๋ค.
๋ธ๋ก๊ทธ๋ฅผ ์ด์ํ๋ฉด์ ๋ฐฉ๋ฌธ์๋ค์๊ฒ ๋จ์ํ ์ฝํ ์ธ ๋ฅผ ์ฝ๋ ๊ฒฝํ์ ๋์ด '๋ํํ๊ณ ๋ฐ์ํ๋ ๊ฒฝํ'์ ์ ๊ณตํ๊ณ ์ถ์ผ์ ๊ฐ์? ๋งค๋ฒ ์๋ฒ์์ ๋ฐ์ดํฐ ์๋ณต(Round Trip)์ผ๋ก ์ฌ์ฉ์๊ฐ ์ง์ ์ฝ๋ฉํ๊ณ ๊ธฐ๋ค๋ ค์ผ ํ๋ '์ด๋ ค์ด AI'๋ ์ด์ ์์ผ์ ๋ ์ข์ต๋๋ค.
TensorFlow.js๋ ์น ํ๊ฒฝ์์ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ์ง์ ์คํํ ์ ์๊ฒ ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด์, ๋ธ๋ก๊ทธ์ AI๋ฅผ ํตํฉํ๋ ๊ฐ์ฅ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ๋๋ค.
์ด๋ฒ์๋ TensorFlow.js์ ํต์ฌ ๊ฐ์น์ธ ์ ์ง์ฐ(Low Latency),๋ฐ์ดํฐ ํ๋ผ์ด๋ฒ์, ๊ทธ๋ฆฌ๊ณ ์น GPU ๊ฐ์์ ํตํ ์ฑ๋ฅ ๊ทน๋ํ ์ ๋ต์ ์ฌ์ธต์ ์ผ๋ก ๋ค๋ฃจ๋ฉฐ, ๋ธ๋ก๊ทธ๋ฅผ ์ํ ๋ธ๋ผ์ฐ์ ๋จธ์ ๋ฌ๋์ ๋ํด ์์๋ด ๋๋ค.
TensorFlow.js: ๋ธ๋ก๊ทธ๋ฅผ ์ํ ๋ธ๋ผ์ฐ์ ๋จธ์ ๋ฌ๋์ ์๋ก์ด ํ์ค
ํน์ '๋ธ๋ก๊ทธ์ AI๋ฅผ ์ ๋ชฉ'ํ๊ณ ์ถ์๋ฐ, ๊ธฐ์ ์ ์ด๋ ค์,์๋,์ฅ๋น ๋๋ฌธ์ ๋ง์ค์ด์ จ๋์? ๋ถ๊ณผ ๋ช ๋ ์ ๋ง ํด๋ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ์คํํ๋ ค๋ฉด ๋ฐ๋์ ๊ฐ๋ ฅํ ์๋ฒ๋ ํด๋ผ์ฐ๋ GPU ์์์ด ํ์ํ์ต๋๋ค. ๋ธ๋ก๊ทธ๋ ์ฌ์ดํธ์ AI ๊ธฐ๋ฅ์ ๋ฃ์ผ๋ ค๊ณ ํ ๋๋ง๋ค, ์ฌ์ฉ์ ์์ฒญ์ ๋จผ ์๋ฒ๋ฅผ ์๋ณตํด์ผ ํ๊ณ , ๊ทธ ์๊ฐ('์๋ณต ์๊ฐ', Round Trip Time)๋งํผ ๋ ์๋ค์ ์ง์ฐ์ ๊ฐ์ํด์ผ ํ์ฃ . ํนํ ํด์ธ ๋ ์๊ฐ ๋ง์ ๊ฒฝ์ฐ ์ด ๋คํธ์ํฌ ์ง์ฐ(Latency)์ ์ฝํ ์ธ ์ ๋ชฐ์ ๋๋ฅผ ๋จ์ด๋จ๋ฆฌ๋ ๊ฐ์ฅ ํฐ ์ฅ๋ฒฝ์ด์์ต๋๋ค.
ํ์ง๋ง TensorFlow.js์ ๋ฑ์ฅ์ ์ด ๋ชจ๋ ๊ณ ๋ฏผ์ ๊ณผ๊ฑฐํ์ผ๋ก ๋ง๋ค์์ต๋๋ค. ์ด JavaScript ๊ธฐ๋ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์น ๋ธ๋ผ์ฐ์ ์์ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ์ง์ ์คํํ๊ณ , ์ฌ์ง์ด ๊ฐ๋จํ ์ ์ด ํ์ต(Transfer Learning)๊น์ง ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
TensorFlow.js๋ AI ์ฐ์ฐ์ ์ค์ฌ์ ์๋ฒ๊ฐ ์๋ ์ฌ์ฉ์ ๊ฐ์ธ์ ๊ธฐ๊ธฐ(๋ธ๋ก๊ทธ, ์ฌ์ดํธ ๋ฑ)์ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ ์ธก AI ์๋๋ฅผ ์ด์์ต๋๋ค. ์ด์ ๋ณต์กํ ์๋ฒ ์ค์ ์ด๋ ๋น์ฉ ๋ถ๋ด ์์ด๋ ์น ํ๋ก ํธ์๋์ ์ค์๊ฐ AI ๊ธฐ๋ฅ์ ํตํฉํ ์ ์์ต๋๋ค.
์ด๋ ๋ธ๋ก๊ทธ AI ํ์ฉ์ ๋ฐฐํฌ ์๋์ ์ ๊ทผ์ฑ์ ํ๊ธฐ์ ์ผ๋ก ๊ฐ์ ํ๋ฉฐ, ๊ธฐ์กด Python์ผ๋ก ํ๋ จ๋ ๋ชจ๋ธ๋ ์น ํ๊ฒฝ์ ์ฝ๊ณ ๋น ๋ฅด๊ฒ ์ ์ฉํ ์ ์์ต๋๋ค.
๋ธ๋ก๊ทธ AI ํ์ฉ์ ํต์ฌ: ํด๋ผ์ด์ธํธ ์ธก AI๊ฐ ์ ๊ณตํ๋ 3๊ฐ์ง ์ด์
์ฐ๋ฆฌ์ ๋ธ๋ก๊ทธ์ TensorFlow.js๋ฅผ ์ ํํด์ผ ํ๋ ๋ช ํํ๊ณ ๋ ๋งค๋ ฅ์ ์ธ ์ธ ๊ฐ์ง ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ์ด๋ ๋จ์ํ ๊ธฐ์ ์ ํจ์จ์ฑ์ ๋์ด, ๋ ์ ๊ฒฝํ(UX)๊ณผ ์ด์ ํจ์จ์ฑ ๋ชจ๋๋ฅผ ์ป์ ์ ์๋ ์-์(Win-Win) ์ ๋ต์ ๋๋ค.
- 1. ์๋์ ์ธ ์ ์ง์ฐ(Low Latency)์ผ๋ก ์ค์๊ฐ ๋ฐ์: AI ์ฐ์ฐ์ด ๋ธ๋ผ์ฐ์ ๋ด์์ ์ฆ์ ์ฒ๋ฆฌ๋๋, ์๋ฒ ์๋ณต์ผ๋ก ์ธํ ๋คํธ์ํฌ ์ง์ฐ์ด ์ ๋ก(0)์ ๊ฐ๊น์์ง๋๋ค. ๋ ์๊ฐ ์คํฌ๋ฆฐ์ท์ ์ฌ๋ฆฌ์๋ง์ ๋ฐ๋ก ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ๊ฑฐ๋, ๋๊ธ ์์ฑ ์ค ์ค์๊ฐ ๋ฌธ์ฅ ์์ฑ์ ์ง์ํ๋ ๋ฑ ์ธํฐ๋ํฐ๋ธํ ๋ธ๋ก๊ทธ ํ๊ฒฝ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ด๋ ์ค์๊ฐ ์น AI๋ฅผ ๊ตฌํํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
- 2. ๋ฐ์ดํฐ ํ๋ผ์ด๋ฒ์์ ์๋ฒฝํ ์ํธ์: ๋ธ๋ก๊ทธ AI ํ์ฉ ์ ๊ฐ์ฅ ๋ฏผ๊ฐํ ๋ถ๋ถ์ด ๋ฐ์ดํฐ ์ ์ถ์ ๋๋ค. TensorFlow.js๋ ๋ฏผ๊ฐํ ์ฌ์ฉ์ ๋ฐ์ดํฐ(์: ์ ๋ ฅ ํ ์คํธ, ์น์บ ๋ฐ์ดํฐ)๊ฐ ์ธ๋ถ ์๋ฒ๋ก ์ ์ก๋ ํ์ ์์ด ๋ก์ปฌ์์๋ง ์ฒ๋ฆฌํ๋๋ก ํฉ๋๋ค. ๋ ์๋ค์ ํ๋ผ์ด๋ฒ์๋ฅผ ์๋ฒฝํ ๋ณดํธํ๋ ๊ฒ์ ์ฌ์ฉ์ ์ ๋ขฐ ๊ตฌ์ถ์ ๊ฒฐ์ ์ ์ธ ์ญํ ์ ํฉ๋๋ค.
- 3. ์ด์ ๋น์ฉ ๋ฐ ์๋ฒ ๋ถํ์ ํ๊ธฐ์ ์ธ ์ ๊ฐ: AI ์ถ๋ก ์ฐ์ฐ์ ๋ฐฉ๋ฌธ์ ๊ฐ์ธ์ ๊ธฐ๊ธฐ๋ก ๋ถ์ฐ์ํค๋ฉด, ๋ธ๋ก๊ทธ ์ด์์๋ ๊ณ ์ฑ๋ฅ ์๋ฒ์ GPU/CPU ๋น์ฉ ๋ถ๋ด์์ ๋ฒ์ด๋ ์ ์์ต๋๋ค. ํนํ ํธ๋ํฝ์ด ๋ง์ ์ธ๊ธฐ ๋ธ๋ก๊ทธ์ผ์๋ก, ์ด ํด๋ผ์ด์ธํธ ์ธก AI ์ ๋ต์ ์ด์ ๋น์ฉ ์ ๊ฐ ํจ๊ณผ๋ฅผ ๊ทน๋ํํฉ๋๋ค.
๋ธ๋ก๊ทธ ์ฑ๋ฅ ์ต์ ์ ๋น๋ฐ: ์น GPU ๊ฐ์๊ณผ tfjs ๊ด๋ฆฌ๋ฒ
์ฌ์ ํ '๋ธ๋ผ์ฐ์ ์์ ๋ฅ๋ฌ๋์ด ๊ณผ์ฐ ๋น ๋ฅผ๊น?'๋ผ๋ ์๋ฌธ์ด ๋จ์ ์ ์์ต๋๋ค. TensorFlow.js๊ฐ ๊ณ ์ฑ๋ฅ์ ์ ์งํ๋ ๋น๊ฒฐ์ ๋ฐ๋ก ์น ํ์ค ๊ทธ๋ํฝ ๊ธฐ์ ์ ํ์ฉํ๋ ๋ฐ ์์ต๋๋ค. WebGL ๋๋ ์ต์ WebGPU ๊ธฐ์ ์ JavaScript๋ฅผ ํตํด ์ฌ์ฉ์์ ๊ทธ๋ํฝ ์ฒ๋ฆฌ ์ฅ์น(GPU)์ ์ ๊ทผํ์ฌ ๋ฅ๋ฌ๋ ์ฐ์ฐ์ ํต์ฌ์ธ ํ๋ ฌ ๊ณฑ์ ๊ณผ ์ปจ๋ณผ๋ฃจ์ ์ ๋ณ๋ ฌ ์ฒ๋ฆฌํฉ๋๋ค.

๋๋ถ๋ถ์ ๊ฒฝ์ฐ TensorFlow.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ด ์น GPU ๊ฐ์ ๊ธฐ๋ฅ์ ์๋์ผ๋ก ์ฌ์ฉํ๊ฒ ํด์ฃผ์ง๋ง, ์ต๊ณ ์ ์ฑ๋ฅ์ ์ ์งํ๊ธฐ ์ํ tfjs ์ฑ๋ฅ ์ต์ ํ ์ ๋ต์ ํ์์ ๋๋ค.
- ๋ชจ๋ธ ๊ฒฝ๋ํ์ ์์ํ(Quantization): ๋ธ๋ก๊ทธ ๋ฐฉ๋ฌธ์๋ ์ฃผ๋ก ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์ MobileNet ๊ฐ์ ๊ฒฝ๋ ๋ชจ๋ธ์ ์ฌ์ฉํ๊ณ , ๋ชจ๋ธ์ ๊ฐ์ค์น๋ฅผ 32๋นํธ ๋ถ๋ ์์์ ์์ 8๋นํธ ์ ์๋ก ์์ถํ๋ ์์ํ(Quantization) ๊ธฐ๋ฒ์ ์ ์ฉํด์ผ ํฉ๋๋ค. ๋ชจ๋ธ์ด ๊ฐ๋ฒผ์์ผ ๋ก๋ฉ ์๊ฐ์ด ๋จ์ถ๋๊ณ , AI ๊ฒฝํ์ด ์ฆ๊ฐ์ ์ผ๋ก ๋๊ปด์ง๋๋ค.
- ๊ฒฐ์ ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ (tf.tidy): ํ
์(Tensor)๋ GPU ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ฐ์ฐ ํ ์ฌ์ฉํ์ง ์๋ ํ
์๋ฅผ ๋ช
์์ ์ผ๋ก ํด์ ํ์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ์ฌ ๋ธ๋ผ์ฐ์ ๊ฐ ๋๋ ค์ง๊ฑฐ๋ ๋ฉ์ถ ์ ์์ต๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด
tf.dispose()๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, ์ฐ์ฐ ๋ธ๋ก ์ ์ฒด๋ฅผtf.tidy()๋ก ๊ฐ์ธ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊น๋ํ๊ฒ ์ ๋ฆฌํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ค์ํ ์ฑ๋ฅ ์ต์ ํ ์์์ ๋๋ค.
์ค์ AI ์ ๋ชฉ ๋ฐ SEO ๊ฐํ ์ ๋ต: ๋์ ์ฝํ ์ธ ์ฒ๋ฆฌ์ ํต์ฌ ์ถ์ถ
๋ธ๋ก๊ทธ์ TensorFlow.js๋ฅผ ์ ์ฉํ ๋, ์ฌ์ฉ์๊ฐ ์คํฌ๋กคํ๊ฑฐ๋ ๋๊ธ์ด ๋น๋๊ธฐ์ ์ผ๋ก ๋ก๋๋๋ ๋์ ์ฝํ ์ธ ์ AI ์ฐ์ฐ์ ์์ ์ ์ผ๋ก ์ ์ฉํ๋ ๊ฒ์ด ํต์ฌ์ ๋๋ค. ๋ ๋์๊ฐ, AI๊ฐ ์์ฑํ ๊ณ ํ์ง์ ์ ๋ณด(์ฝํ ์ธ ์์ฝ, ํต์ฌ ํค์๋)๋ฅผ ๊ฒ์ ์์ง ์ต์ ํ(SEO)์ ํ์ฉํ๋ ์ ๋ต์ ๋ธ๋ก๊ทธ ํจ์จ์ฑ์ ์์น์ํต๋๋ค.

- ๋จ์ผ ๋ชจ๋ธ ๋ก๋ ํจํด: TensorFlow.js ๋ชจ๋ธ์ ์ด๊ธฐ ๋ก๋ฉ ์ ๋ฆฌ์์ค๋ฅผ ์๋ชจํฉ๋๋ค. ํ์ด์ง๊ฐ ๋ก๋๋ ๋ ๋ชจ๋ธ์ ๋จ ํ ๋ฒ๋ง ๋ถ๋ฌ์ค๋ Lazy Loading ๋๋ Singleton Pattern์ ์ ์ฉํ์ฌ ์ค๋ณต ๋ก๋ฉ์ ๋ฐฉ์งํ๊ณ tfjs ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ ์งํด์ผ ํฉ๋๋ค.
- ๋์ ์ฝํ ์ธ ๊ฐ์ง (MutationObserver): ๋๊ธ์ด๋ ๋ฆ๊ฒ ๋ก๋๋๋ ๋ณธ๋ฌธ ๊ฐ์ ๋์ ์์์๋ MutationObserver API๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก์ด DOM ์์๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค AI ์ฒ๋ฆฌ ๋ก์ง(์: ๋๊ธ ๊ฐ์ฑ ๋ถ์, ์์ฝ)์ ์คํํด์ผ ํฉ๋๋ค. ์ด ๋ฐฉ์์ด ๋ฐ๋ก AI ๊ธฐ๋ฅ์ ์์ ์ ์ผ๋ก ์๋์ํค๋ ์ด์ ์ ๋๋ค.
๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ๋๊ทธ์ AI ๊ธฐ๋ฐ SEO ์ฝ๋ ์ ์ฉ
AI ์ฐ์ฐ์ด ์๋ฃ๋ ์์์ dataset.aiProcessed = 'true'์ ๊ฐ์ ๋ฐ์ดํฐ ํ๋๊ทธ๋ฅผ ์ค์ ํ์ฌ ์ค๋ณต ์ฐ์ฐ์ ๋ฐฉ์งํฉ๋๋ค. ๋์ฑ ์ค์ํ ๊ฒ์, AI๊ฐ ์์ฑํ ๋ณธ๋ฌธ ์์ฝ ๋ฐ ํต์ฌ ํค์๋๋ฅผ HTML DOM์ ์ค์ํ ์์น์ ์ฝ์
ํ์ฌ ๊ฒ์ ์์ง ๋ด(Crawler)์ด ํด๋น ์ ๋ณด๋ฅผ ๋์น์ง ์๊ณ ์ธ๋ฑ์ฑํ๋๋ก ์ ๋ํ๋AI ๊ธฐ๋ฐ SEO ์ ๋ต์
๋๋ค.
์ค์ ๊ฐ๋จํ ์ ์ฉ ์ฌ๋ก ๋ฐ ์ฝ๋
๋ธ๋ก๊ทธ์ ๋ฌ๋ฆฐ ๋๊ธ์ AI๊ฐ ๋ถ์ํ์ฌ, ์ฌ์ฉ์๊ฐ ์ผ์ผ์ด ๋ต๊ธ์ ์์ฑํ์ง ์์๋ ์๋์ผ๋ก ์ ์ ํ ๋ต๋ณ์ ์์ฑํด ์ค๋๋ค.

์ ์ฉํ ๋ธ๋ก๊ทธ: https://openpc.tistory.com/920
์ ์ฉ ์ฝ๋ ์์
์๋ ์์ ์ฝ๋๋ TensorFlow.js์ USE ๋ชจ๋ธ์ ํ์ฉํ์ฌ ๋ณธ๋ฌธ ์์ฝ ๋ฐ ํค์๋๋ฅผ ์์ฑํ๊ณ , ์ด๋ฅผ ํ์ด์ง์ ์ค์ํ ์์น์ ์ฝ์ ํ์ฌ SEO๋ฅผ ๊ฐํํ๋ ์ค์ ์ ์ธ ๋ฐฉ๋ฒ๋ก ์ ๋ณด์ฌ์ค๋๋ค.
script
(async () = {
let model;
try {
model = await use.load();
console.log("โ
AI ๋ชจ๋ธ ๋ก๋ ์๋ฃ");
} catch(e) {
console.warn("โ AI ๋ชจ๋ธ ๋ก๋ ์คํจ, ์์ฝ ๊ธฐ๋ฅ์ ๊ฐ๋จ ๋ฐฉ์์ผ๋ก ๋์");
}
async function generateResponse(text) {
return tf.tidy(() = {
const lowerText = text.toLowerCase();
if (lowerText.includes("์ง๋ฌธ") || lowerText.includes("๊ถ๊ธ") || lowerText.includes("์ด๋ป๊ฒ") || lowerText.includes("์ค๋ฅ") || lowerText.includes("๋ฌธ์ ") || lowerText.includes("์๋")) {
const responses = [
" ์์คํ ํผ๋๋ฐฑ/์ง๋ฌธ ๊ฐ์ฌํฉ๋๋ค. ํด๋น ๋ด์ฉ ํ์ธ ํ ๋ต๋ณ ๋๋ ์์ ์กฐ์นํ๊ฒ ์ต๋๋ค.",
"โ ๋ฌธ์/์ ์ ๊ฐ์ฌํฉ๋๋ค. ๋ด์ฉ์ ์ฃผ์ ๊น๊ฒ ๊ฒํ ํ ๋น ๋ฅธ ์๊ฐ ๋ด์ ํด๊ฒฐ์ฑ
์ ์ ์ํด ๋๋ฆฌ๊ฒ ์ต๋๋ค."
];
return responses[Math.floor(Math.random() * responses.length)];
}
if (lowerText.includes("ํ๋ ฅ") || lowerText.includes("ํฅ๋ฏธ๋ก์ด ์ฃผ์ ") || lowerText.includes("๋์ ๋ง์ด ๋") || lowerText.includes("๋๋ฌด์ข") ) {
const responses = [
" ์์ธํ ํผ๋๋ฐฑ์ ํฐ ํ์ ์ป์ต๋๋ค! ๋
์๋ ๋๋ถ์ ๊ธ ์ฐ๋ ๋ณด๋์ ๋๊ปด์. ์์ฃผ ์ฐพ์์ฃผ์ธ์!",
" ๋
์๋์ ์นญ์ฐฌ์ ์ด๊นจ๊ฐ ๋ค์ฉ์ด๋ค์! ๋ค์ ๊ธ๋ ๊ธฐ๋๋ฅผ ์ ๋ฒ๋ฆฌ์ง ์๋๋ก ๋
ธ๋ ฅํ๊ฒ ์ต๋๋ค.",
" ๋
์๋๊ป ๋์์ด ๋์๋ค๋ ์ ๋ง ๊ธฐ์ฉ๋๋ค! ์ธ์ ๋ ์ ์ตํ ์ ๋ณด๋ฅผ ์ ๋ฌํด ๋๋ฆด๊ฒ์."
];
return responses[Math.floor(Math.random() * responses.length)];
}
if (lowerText.includes("๋ค๋
๊ฐ๋๋ค") || lowerText.includes("์ฆ๊ฑฐ์ด ๋ ๋์ธ์") || lowerText.includes("ํ๋ณตํ ํ๋ฃจ") || lowerText.includes("๋์๋๋ฆฌ๊ณ ๊ฐ๊ป์")) {
const responses = [
" ๊ทํ ๊ฑธ์ ๊ฐ์ฌํฉ๋๋ค! ๋
์๋๋ ์ค๋ ํ๋ณตํ ํ๋ฃจ ๋ณด๋ด์ธ์.",
"โจ ์์ ๊ฐ์ฌํฉ๋๋ค! ๋ฐฉ๋ฌธํด์ฃผ์ ๋
์๋๊ป๋ ์ฆ๊ฑฐ์ด ์ผ๋ง ๊ฐ๋ํ์๊ธธ ๋ฐ๋๋๋ค.",
" ๋ฐ๋ปํ ์ธ์ฌ ๊ฐ์ฌํฉ๋๋ค! ๋ค์์ ๋ ์ข์ ๊ธ๋ก ์ฐพ์๋ต๊ฒ ์ต๋๋ค."
];
return responses[Math.floor(Math.random() * responses.length)];
}
if (lowerText.includes("๊ฐ์ฌํฉ๋๋ค") || lowerText.includes("์ ๋ณด๊ณ ") || lowerText.includes("์ ์ฝ์์ต")) {
const responses = [
" ์์คํ ์๊ฐ ๋ด์ด ์ฝ์ด์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค. ๋ค์ ์ฝํ
์ธ ๋ ๊ธฐ๋ํด์ฃผ์ธ์!",
" ๊ณต๊ฐํด์ฃผ์
์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค! ๋ค์ ๊ธ์์ ๋ ๋ต๊ฒ ์ต๋๋ค.",
" ๋
์๋์ ์์ ๋ฉ์์ง ์ ๋ฐ์์ต๋๋ค! ํญ์ ์ข์ ์ ๋ณด๋ก ๋ณด๋ตํ๊ฒ ์ต๋๋ค."
];
return responses[Math.floor(Math.random() * responses.length)];
}
const defaultResponses = [
" ์์คํ ์๊ฒฌ ๊ฐ์ฌํฉ๋๋ค. ๋ค์์๋ ๊ผญ ๋ค์ ์ฐพ์์ฃผ์ธ์.",
" ๊ด์ฌ์ ๊ฐ์ ธ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค. ๋
์๋์ ์๊ฒฌ์ ์ฐธ๊ณ ํ์ฌ ๋ค์ ๊ธ์ ๋ฐ์ํ๊ฒ ์ต๋๋ค.",
"โจ ๋ฐฉ๋ฌธํด ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค! ์ข์ ํ๋ฃจ ๋์ธ์."
];
return defaultResponses[Math.floor(Math.random() * defaultResponses.length)];
});
}
let commentProcessing = false;
async function processComments() {
if(commentProcessing) return;
commentProcessing = true;
const container = document.querySelector(".tt-comments-wrap");
if(!container) {
commentProcessing = false;
return;
}
const comments = container.querySelectorAll(".tt_desc");
for(const c of comments) {
if(c.dataset.aiResponded) continue;
try {
const response = await generateResponse(c.innerText);
const div = document.createElement("div");
div.className = "ai-comment-response";
div.style = `
margin-top:6px;
padding:5px 10px;
background:#28a745;
color:#fff;
font-size:13px;
border-radius:6px;
display:inline-block;
`;
div.innerText = "[AI ์๋ ๋ต๋ณ]: " + response;
c.parentElement.appendChild(div);
c.dataset.aiResponded = "true";
} catch(e) {
console.error("AI ๋ต๋ณ ์์ฑ ์ค๋ฅ:", e);
}
}
commentProcessing = false;
}
async function summarizeText(text, topN=3) {
const cleanText = text.replace(/br/g," ").replace(/\n/g," ").trim();
const sentences = cleanText.split(/[.?!]/).map(s = s.trim()).filter(s = s.length 5);
if(sentences.length = 1) return cleanText;
return sentences.slice(0, topN).join(". ") + ".";
}
function extractKeywords(text, topN=5) {
const cleanText = text.replace(/br/g," ").replace(/\n/g," ").toLowerCase();
const words = cleanText.match(/[๊ฐ-ํฃa-zA-Z0-9]+/g) || [];
const freq = {};
words.forEach(w = { if(w.length1) freq[w]=(freq[w]||0)+1; });
const sorted = Object.entries(freq).sort((a,b)=b[1]-a[1]);
return sorted.slice(0,topN).map(e=e[0]);
}
async function processArticle() {
const article = document.querySelector(".tt_article_useless_p_margin.contents_style");
if(!article) return;
const summaryTarget = document.querySelector("#summary-target") || article;
if(!summaryTarget.querySelector(".ai-article-summary")) {
const summary = await summarizeText(article.innerText);
const div = document.createElement("div");
div.className = "ai-article-summary";
div.style = `
margin:12px 0;
padding:10px 14px;
background: rgba(0,0,0,0.7);
color: #fff;
font-size:14px;
border-radius:8px;
`;
div.innerText = summary;
summaryTarget.appendChild(div);
}
const keywordTarget = document.querySelector("#keyword-target") || article;
if(!keywordTarget.querySelector(".ai-article-keywords")) {
const keywords = extractKeywords(article.innerText);
const div = document.createElement("div");
div.className = "ai-article-keywords";
div.style = `
margin:12px 0;
padding:10px 14px;
background: rgba(255,165,0,0.8);
color: #000;
font-size:14px;
border-radius:8px;
`;
div.innerText = " ์ฃผ์ ํค์๋: " + keywords.join(", ");
keywordTarget.appendChild(div);
}
}
const observer = new MutationObserver(() = {
setTimeout(processComments, 300);
setTimeout(processArticle, 300);
});
observer.observe(document.body, {childList:true, subtree:true});
processComments();
processArticle();
})();
/script