Published:

Last Updated:

๋ธ”๋กœ๊ทธ๋ฅผ ์‹ค์‹œ๊ฐ„ 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)์— ์ ‘๊ทผํ•˜์—ฌ ๋”ฅ๋Ÿฌ๋‹ ์—ฐ์‚ฐ์˜ ํ•ต์‹ฌ์ธ ํ–‰๋ ฌ ๊ณฑ์…ˆ๊ณผ ์ปจ๋ณผ๋ฃจ์…˜์„ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ์— AI ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•-TensorFlow.js ์†Œ๊ฐœ
TensorFlow.js

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ TensorFlow.js ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด ์›น GPU ๊ฐ€์† ๊ธฐ๋Šฅ์„ ์ž๋™์œผ๋กœ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•ด์ฃผ์ง€๋งŒ, ์ตœ๊ณ ์˜ ์„ฑ๋Šฅ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•œ tfjs ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ „๋žต์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.

  1. ๋ชจ๋ธ ๊ฒฝ๋Ÿ‰ํ™”์™€ ์–‘์žํ™”(Quantization): ๋ธ”๋กœ๊ทธ ๋ฐฉ๋ฌธ์ž๋Š” ์ฃผ๋กœ ๋ชจ๋ฐ”์ผ ๊ธฐ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ MobileNet ๊ฐ™์€ ๊ฒฝ๋Ÿ‰ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๊ณ , ๋ชจ๋ธ์˜ ๊ฐ€์ค‘์น˜๋ฅผ 32๋น„ํŠธ ๋ถ€๋™ ์†Œ์ˆ˜์ ์—์„œ 8๋น„ํŠธ ์ •์ˆ˜๋กœ ์••์ถ•ํ•˜๋Š” ์–‘์žํ™”(Quantization) ๊ธฐ๋ฒ•์„ ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ์ด ๊ฐ€๋ฒผ์›Œ์•ผ ๋กœ๋”ฉ ์‹œ๊ฐ„์ด ๋‹จ์ถ•๋˜๊ณ , AI ๊ฒฝํ—˜์ด ์ฆ‰๊ฐ์ ์œผ๋กœ ๋А๊ปด์ง‘๋‹ˆ๋‹ค.
  2. ๊ฒฐ์ •์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ (tf.tidy): ํ…์„œ(Tensor)๋Š” GPU ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์—ฐ์‚ฐ ํ›„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ…์„œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ•ด์ œํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋А๋ ค์ง€๊ฑฐ๋‚˜ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด tf.dispose()๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์—ฐ์‚ฐ ๋ธ”๋ก ์ „์ฒด๋ฅผ tf.tidy()๋กœ ๊ฐ์‹ธ์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™” ์š”์†Œ์ž…๋‹ˆ๋‹ค.

์‹ค์ „ AI ์ ‘๋ชฉ ๋ฐ SEO ๊ฐ•ํ™” ์ „๋žต: ๋™์  ์ฝ˜ํ…์ธ  ์ฒ˜๋ฆฌ์™€ ํ•ต์‹ฌ ์ถ”์ถœ

๋ธ”๋กœ๊ทธ์— TensorFlow.js๋ฅผ ์ ์šฉํ•  ๋•Œ, ์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กคํ•˜๊ฑฐ๋‚˜ ๋Œ“๊ธ€์ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋กœ๋“œ๋˜๋Š” ๋™์  ์ฝ˜ํ…์ธ ์— AI ์—ฐ์‚ฐ์„ ์•ˆ์ •์ ์œผ๋กœ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ๋” ๋‚˜์•„๊ฐ€, AI๊ฐ€ ์ƒ์„ฑํ•œ ๊ณ ํ’ˆ์งˆ์˜ ์ •๋ณด(์ฝ˜ํ…์ธ  ์š”์•ฝ, ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ)๋ฅผ ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™”(SEO)์— ํ™œ์šฉํ•˜๋Š” ์ „๋žต์€ ๋ธ”๋กœ๊ทธ ํšจ์œจ์„ฑ์„ ์ƒ์Šน์‹œํ‚ต๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ ์ฝ˜ํ…์ธ  ์š”์•ฝ ํ‚ค์›Œ๋“œ๋ฅผ AI๋ฅผ ํ™œ์šฉํ•ด์„œ ์ ์šฉํ•˜๊ธฐ
TensorFlow.js ๋ฅผ ํ™œ์šฉํ•ด์„œ AI๊ฐ€ ๋ธ”๋กœ๊ทธ ๊ธ€ ์š”์•ฝ๋ฐ ํ‚ค์›Œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑ
  • ๋‹จ์ผ ๋ชจ๋ธ ๋กœ๋“œ ํŒจํ„ด: 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๊ฐ€ ๋ถ„์„ํ•˜์—ฌ, ์‚ฌ์šฉ์ž๊ฐ€ ์ผ์ผ์ด ๋‹ต๊ธ€์„ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ์ ์ ˆํ•œ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ์— AI๋ฅผ ํ™œ์šฉํ•ด์„œ ๋Œ“๊ธ€์— ์ž๋™ ๋‹ต๊ธ€ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•
AI๋ฅผ ํ™œ์šฉํ•ด์„œ ๋Œ“๊ธ€์— ์ž๋™ ๋‹ต๊ธ€ ์ƒ์„ฑ

์ ์šฉํ•œ ๋ธ”๋กœ๊ทธ: https://openpc.tistory.com/920

TensorFlow.js์™€ ์„œ๋ฒ„ ๊ธฐ๋ฐ˜ ML ๋น„๊ต: ํด๋ผ์ด์–ธํŠธ ์ธก AI์˜ ์šฐ์œ„

ํด๋ผ์ด์–ธํŠธ ์ธก AI์™€ ์„œ๋ฒ„ ๊ธฐ๋ฐ˜ ML ๋น„๊ต: ์™œ TensorFlow.js์ธ๊ฐ€?
๊ตฌ๋ถ„ TensorFlow.js (ํด๋ผ์ด์–ธํŠธ/๋ธŒ๋ผ์šฐ์ €) ์„œ๋ฒ„ ๊ธฐ๋ฐ˜ ML (ํด๋ผ์šฐ๋“œ/๋ฐฑ์—”๋“œ)
์‹คํ–‰ ์œ„์น˜ ์‚ฌ์šฉ์ž์˜ ๊ธฐ๊ธฐ (GPU, WebGL ํฌํ•จ) ์›๊ฒฉ ์„œ๋ฒ„ ๋˜๋Š” ํด๋ผ์šฐ๋“œ GPU
์ง€์—ฐ ์‹œ๊ฐ„ ๋งค์šฐ ๋‚ฎ์Œ (๋„คํŠธ์›Œํฌ ์ง€์—ฐ ์—†์Œ) ๋„คํŠธ์›Œํฌ ์†๋„์— ์˜์กด
๋ฐ์ดํ„ฐ ํ”„๋ผ์ด๋ฒ„์‹œ ๋งค์šฐ ๋†’์Œ (๋กœ์ปฌ ์ฒ˜๋ฆฌ๋กœ ๋ฐ์ดํ„ฐ ์œ ์ถœ ์œ„ํ—˜ ์ฐจ๋‹จ) ๋ฐ์ดํ„ฐ ์ „์†ก ๋ฐ ๋ณด๊ด€ ํ•„์š”
์ตœ์  ํ™œ์šฉ์ฒ˜ ์‹ค์‹œ๊ฐ„ ์ธํ„ฐ๋ž™์…˜, ๋ธŒ๋ผ์šฐ์ € ๋จธ์‹ ๋Ÿฌ๋‹, ๊ฐœ์ธํ™”, ๋น„์šฉ ํšจ์œจ์  ์ถ”๋ก  ๋Œ€๊ทœ๋ชจ ํ›ˆ๋ จ, ๋ฐฉ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ, ๋ณต์žกํ•˜๊ณ  ๊ฑฐ๋Œ€ํ•œ ๋ชจ๋ธ

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” TensorFlow.js๋ฅผ ํ™œ์šฉํ•ด ๋ธ”๋กœ๊ทธ๋ฅผ ์‹ค์‹œ๊ฐ„ AI ์„œ๋น„์Šค๋กœ ๋ณ€์‹ ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•๊ณผ, ์„œ๋ฒ„ ๋น„์šฉ ์—†์ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ๊ตฌํ˜„ํ•˜๋Š” ์ „๋žต์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์ธก AI๋ฅผ ํ™œ์šฉํ•˜๋ฉด, ๋…์ž๋“ค์—๊ฒŒ ์ง€์—ฐ ์—†๋Š” ์‹ค์‹œ๊ฐ„ ๋ฐ˜์‘ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋Š” ์™ธ๋ถ€ ์„œ๋ฒ„๋กœ ์ „์†ก๋˜์ง€ ์•Š์•„ ํ”„๋ผ์ด๋ฒ„์‹œ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์›น GPU ๊ฐ€์†๊ณผ ๋ชจ๋ธ ์ตœ์ ํ™”๋ฅผ ํ†ตํ•ด ๋ธ”๋กœ๊ทธ ์„ฑ๋Šฅ์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ๋„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ ๋Œ“๊ธ€ ๋ถ„์„, ๋ณธ๋ฌธ ์š”์•ฝ, ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ ์ถ”์ถœ ๋“ฑ AI ๊ธฐ๋ฐ˜ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋ฉด, ๋ธ”๋กœ๊ทธ์˜ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜๊ณผ SEO ํšจ์œจ์„ฑ์„ ๋™์‹œ์— ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ์ด์ƒ ์„œ๋ฒ„ ์„ธํŒ…์ด๋‚˜ ๋น„์šฉ ๋ถ€๋‹ด์— ์–ฝ๋งค์ด์ง€ ์•Š๊ณ , ๋‹จ์ˆœํ•œ ์ฝ๊ธฐ ์ค‘์‹ฌ ๋ธ”๋กœ๊ทธ์—์„œ ๋ฒ—์–ด๋‚˜ ๋…์ž์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ์ง€๋Šฅํ˜• ๋ธ”๋กœ๊ทธ๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

FAQ: tfjs๋ฅผ ํ™œ์šฉํ•œ ์›น AI์˜ ์งˆ๋ฌธ

TensorFlow.js๋ฅผ ์‚ฌ์šฉํ•œ ๋ธŒ๋ผ์šฐ์ € ๋จธ์‹ ๋Ÿฌ๋‹์€ ๋ณด์•ˆ ๋ฌธ์ œ๊ฐ€ ์—†๋‚˜์š”?

TensorFlow.js๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ, ์˜คํžˆ๋ ค ์„œ๋ฒ„ ๊ธฐ๋ฐ˜ ๋ชจ๋ธ๋ณด๋‹ค ํ”„๋ผ์ด๋ฒ„์‹œ ์ธก๋ฉด์—์„œ ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. ์—ฐ์‚ฐ์ด ์‚ฌ์šฉ์ž์˜ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ๋งŒ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ฏผ๊ฐํ•œ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ(์˜ˆ: ์–ผ๊ตด ์ด๋ฏธ์ง€, ์Œ์„ฑ)๊ฐ€ ์ธํ„ฐ๋„ท์„ ํ†ตํ•ด ์™ธ๋ถ€ ์„œ๋ฒ„๋กœ ์œ ์ถœ๋  ์œ„ํ—˜์ด ๊ทผ๋ณธ์ ์œผ๋กœ ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก AI์˜ ๊ฐ€์žฅ ํฐ ์žฅ์  ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

tfjs ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ๋ชจ๋ธ ํฌ๊ธฐ ์™ธ์— ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?

๋ชจ๋ธ ํฌ๊ธฐ ์™ธ์—๋„, ์›น GPU ๊ฐ€์†์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ™œ์„ฑํ™”๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ์—ฐ์‚ฐ์ด ๋๋‚œ ํ›„ ํ…์„œ๋ฅผ ์ •๋ฆฌํ•˜๋Š” tf.tidy() ๋˜๋Š” tf.dispose()๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฐ์ •์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ๋ฏผ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ…์„œ ๊ฐ์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ๋ˆ„์ ๋˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋А๋ ค์ง€๊ฑฐ๋‚˜ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” TensorFlow.js ๊ฐœ๋ฐœ ์‹œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ tfjs ์„ฑ๋Šฅ ์ตœ์ ํ™” ์š”์†Œ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

Python์—์„œ ํ›ˆ๋ จ๋œ ๋ชจ๋“  ๋ชจ๋ธ์ด TensorFlow.js๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•˜๋‚˜์š”?

๋Œ€๋ถ€๋ถ„์˜ Keras ๋ฐ ํ‘œ์ค€ TensorFlow ๋ชจ๋ธ์€ TensorFlow.js ๋ณ€ํ™˜๊ธฐ๋ฅผ ํ†ตํ•ด ์›น ํฌ๋งท์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋ธ์— ์‚ฌ์šฉ๋œ ์ผ๋ถ€ ๋ณต์žกํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ๋ ˆ์ด์–ด๋‚˜ ์—ฐ์‚ฐ์€ WebGL ๋ฐฑ์—”๋“œ์—์„œ ์•„์ง ์ง€์›๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณ€ํ™˜ ์ „์— TensorFlow.js ๋ฌธ์„œ๋ฅผ ํ†ตํ•ด ์ง€์›๋˜๋Š” ์—ฐ์‚ฐ์ž ๋ชฉ๋ก์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์‹ค์ „ TensorFlow.js ์‚ฌ์šฉ๋ฒ•์˜ ์ค‘์š”ํ•œ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.

์ ์šฉ ์ฝ”๋“œ ์˜ˆ์ œ

์•„๋ž˜ ์˜ˆ์‹œ ์ฝ”๋“œ๋Š” 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