์ด์คํธ์ํํธ์์ ์ฃผ๊ดํ๋ ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋ถํธ์บ ํ '์ค๋ฅด๋ฏธ'์์ ๋ฐฐ์ฐ๋ฉฐ ๋ง๋ ํ๋ก์ ํธ์
๋๋ค. ํ์์๋ ๊ฐ๋ฐ์ ํ ๋ ๋ณ์๋ช
, ํจ์๋ช
์ ์ง์ ๋ ๊ณ ๋ฏผ์ ๋ง์ด ํ๋ ํธ์ด๊ธฐ ๋๋ฌธ์ ์์ฐ์ค๋ฝ๊ฒ ์ฃผ์ ๋ฅผ '๋ณ์๋ช
์ถ์ฒ๊ธฐ'๋ก ์ ํ๊ฒ ๋์์ต๋๋ค.
ChatGPT์ API ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ์นํ์ด์ง๋ฅผ ๊ตฌํํ๋ ํ๋ก์ ํธ์
๋๋ค. HTML, CSS, JavaScript ๋ฅผ ํ์ฉํ๋ ์ ์์ ์ฌ๋๊ป ๊ตฌํํ๊ฒ ๋์์ต๋๋ค. Bootstrap, Tailwind ๋ฑ์ ์ฌ์ฉ๋ ๊ณ ๋ ค๋์์ง๋ง ์์ง ํ๋ก ํธ์๋์ ๊ฐ์ข
๊ธฐ๋ฅ๊ณผ ์ธ์ด๊ฐ ๋ฏ์ค๊ณ ์ต์ํด์ ธ์ผํ๊ธฐ ๋๋ฌธ์ ๋ฐฑ์ง์ํ์์ ์ ์์ ์๋ํ์์ต๋๋ค.
ํ๋ก์ ํธ ๊ธฐ๊ฐ์ 23.08.29 ~ 23.09.06 ์ด 9์ผ์ด์์ผ๋ฉฐ, 1์ธ๊ฐ๋ฐ๋ก ์ด๋ฃจ์ด์ก์ต๋๋ค.
GitHub: https://github.com/jmkim648/variable-recommander
๋ฐฐํฌ: https://jmkim648.github.io/variable-recommander/
- ํจ์๋ช /๋ณ์๋ช ์ถ์ฒ ๊ธฐ๋ฅ
- ์ฝ๋ ์ ๋ ฅ์ ์ปจ๋ฒค์ ์ ๋ง๊ฒ ์์ ํ๋ ๊ธฐ๋ฅ
- localStorage ๊ธฐ๋ฅ์ ์ด์ฉํ ๊ฒ์ ์ด๋ ฅ ๊ด๋ฆฌ
- Dark Mode ์ค์
- History(๊ฒ์ ์ด๋ ฅ) ๋ฉ๋ด ์ฌ๋ผ์ด๋
- ์์ด์ฝ ์ ๋๋ฉ์ด์ (Dark mode toggle button, history menu slide button)
- ๊ตฌํ ํ๋ฉด ๋ฐ ์ค๋ช
5. ๋ฏธํกํ๋ ์ /์ถํ ๋ชฉํ
root
โ index.html
โ README.md
โ
โโcss
โ common.css
โ darkmode.css
โ history.css
โ index.css
โ
โโdata
โ data.js
โ
โโimg
โ favicon.ico
โ
โโmodule
gpt-api.js
history.js
index.js
page-changer.js
spin.js
์ ํํ ์ธ์ด์ ์ฉ๋์ ๋ง๊ฒ ChatGPT๊ฐ ํจ์๋ช , ๋ณ์๋ช ์ ์ถ์ฒํด์ค๋๋ค. ํด๋น ์ธ์ด์ ์์ง ์ต์ํ์ง ์์ ์ด๋ค ํํ๋ก ํจ์์ ๋ณ์๋ช ์ ์ง๋์ง ํท๊ฐ๋ฆด ๋, ๋ฌด์ธ๊ฐ๋ฅผ ์ํ ํจ์๋ฅผ ๋ง๋ค๊ณ ์ถ์๋ฐ ์ด๋ฆ์ ์ง๊ธฐ ๋ง๋งํ ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ค์ค๋ก ์์ฑํ ์ฝ๋๋ฅผ ๋ณต์ฌํด ์ ๋ ฅํ๋ฉด ChatGPT๊ฐ ์ธ์ด์ ๋ง๋ ์ปจ๋ฒค์ ์ผ๋ก ์์ , ์ถ์ฒํด์ค๋๋ค. ํจ์/๋ณ์๋ช ์ถ์ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ณธ์ธ์ด ์ธ์ด์ ์ต์์น ์๊ฑฐ๋ ์์ ์ด ์์ ๋ ํ์ธํ๋ ์ฉ๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ธ๋ผ์ฐ์ ์ localStorage๊ธฐ๋ฅ์ ์ด์ฉํด History ๋ฉ๋ด๋ฅผ ๊ตฌํ, ๊ฒ์ ์ด๋ ฅ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด ์ด๋ ฅ์ ๋ธ๋ผ์ฐ์ ๋ฅผ ๊ป๋ค๊ฐ ์ผ๋ ๋จ์์์ผ๋ฉฐ, ์ต๋ 15๊ฐ๊น์ง ์ ์ฅ๋ฉ๋๋ค.
๊ฒ์ ์ด๋ ฅ์ ์ ํํ ์ธ์ด๊ฐ ์๋จ์ <python>๊ณผ ๊ฐ์ด ํ๊ธฐ๋๋ฉฐ, ์๋์ ์ด๋ค ๋ด์ฉ์ ์ถ์ฒ๋ฐ์๋์ง ์๋ ค์ค๋๋ค. ์ด๋ ฅ ํญ๋ชฉ์ ๋๋ฅผ ๊ฒฝ์ฐ ๋น์ ํ์๋์๋ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋๋ฉฐ, ์ฐ์ธก์ 'X'ํ์๋ฅผ ๋๋ฅด๋ฉด ํด๋น ์ด๋ ฅ์ ์ญ์ ํ ์ ์์ต๋๋ค.
Dark Mode ๊ธฐ๋ฅ์ ๊ตฌํํ์ต๋๋ค. ํค๋ ์ฐ์ธก์ ์์ด์ฝ์ ๋๋ฅผ ๊ฒฝ์ฐ dark mode, light mode๋ก ํ ๊ธ ์ ํ๋ฉ๋๋ค. light mode์ผ ๋๋ ์์ด์ฝ์ด ๊ฒ์์ ํด ๋ชจ์์ด๊ณ , dark mode์ผ ๋๋ ํ์์ ๋ฌ ๋ชจ์์ผ๋ก ์ ํ๋ฉ๋๋ค. ์ ํ๋ ๋๋ง๋ค ๋ฒํผ์ ๊ฐ๋จํ ์ ๋๋ฉ์ด์ ์ด ์ ์ฉ๋ฉ๋๋ค.
History(๊ฒ์์ด๋ ฅ) ๋ฉ๋ด ์ผ์ชฝ์ ํ์ดํ ๋ฒํผ์ ๋๋ฅด๋ฉด History๋ฉ๋ด๊ฐ ์ฐ์ธก์ผ๋ก ์ฌ๋ผ์ง๋๋ค. mainํ๋ฉด์ด ๋ฐ์ํ์ผ๋ก ์ค๊ณ๋์ด ์๊ธฐ ๋๋ฌธ์ History ๋ฉ๋ด๊ฐ ์ ํ ๋ main ๋ฉ๋ด๊ฐ ์์ผ๋ก ๋์ด๋ฉ๋๋ค. History ๋ฉ๋ด๊ฐ ์ ํ ๋ ์ ๋๋ฉ์ด์
์ด ์ ์ฉ๋๋ฉฐ ํ์ดํ๋ 180๋ ๋์๊ฐ๋๋ค. History ๋ฉ๋ด๊ฐ ์ ํ์์ ๋ ํ์ดํ๋ฅผ ๋ค์ ๋๋ฅด๋ฉด ๋ฉ๋ด๊ฐ ํผ์ณ์ง๋๋ค.
- ์๋จ ์ธ์ด์ ํ ๋ฉ๋ด์์ ์ธ์ด๋ฅผ ์ ํํฉ๋๋ค.
- ํ๋จ์ ์ฉ๋ ์ ํ ๋ฉ๋ด์์ ์ํ๋ ์ฉ๋๋ฅผ ์ ํํฉ๋๋ค. ์ํ๋ ํญ๋ชฉ์ด ์์ ๊ฒฝ์ฐ ๊ธฐํ๋ฅผ ํด๋ฆญ, ์ํ๋ ์ฉ๋๋ฅผ ์ ๋ ฅํฉ๋๋ค.
- ๋ก๋ฉ ํ ๊ฒฐ๊ณผ์ฐฝ์ ํจ์๋ช , ๋ณ์๋ช ์ด ์ถ์ฒ๋ฉ๋๋ค.
- fetch ์ค ๋ค๋ฅธ ์ค๋ธ์ ํธ๋ฅผ ํด๋ฆญํ๊ฑฐ๋, ์ถ์ฒํ๊ธฐ!๋ฅผ ์ฌ๋ฌ๋ฒ ๋๋ฅผ ๊ฒฝ์ฐ ์ํ์ง ์์๋ ์ํฉ์ด ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ spinner ๊ธฐ๋ฅ์ ์ ์ฉํด ์ํธ์์ฉ์ ๋ง๋๋ก ํ์ต๋๋ค.
- ์๋จ ์ธ์ด์ ํ ๋ฉ๋ด์์ ์ธ์ด๋ฅผ ์ ํํฉ๋๋ค.
- ํ๋จ์ ์ฝ๋ ์ ๋ ฅ๋์ ํ์ธํ๊ณ ์ถ์ ์ฝ๋๋ฅผ ์ ๋ ฅํฉ๋๋ค.
- ๋ก๋ฉ ํ ๊ฒฐ๊ณผ์ฐฝ์ ์์ ๋ ์ฝ๋, ์ฃผ์ ์์ ์ฌํญ์ด ์ฃผ์์ผ๋ก ํ์๋ฉ๋๋ค.
- ์ถ์ฒํ๊ธฐ! ๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค ํด๋น ์ธ์ด, ์ฉ๋๊ฐ ์ฐ์ธก ๊ฒ์์ด๋ ฅ ๋ฉ๋ด์ ๊ธฐ๋ก๋ฉ๋๋ค.
- ๊ฒ์ ์ด๋ ฅ ๋ฉ๋ด์ ๋ฆฌ์คํธ๋ฅผ ํด๋ฆญํ๋ฉด ํด๋น ํญ๋ชฉ์ ๊ฒฐ๊ณผ๊ฐ ๊ฒฐ๊ณผ์ฐฝ ํ๋ฉด์ ์ถ๋ ฅ๋ฉ๋๋ค.
- ๋ฆฌ์คํธ ์ค๋ฅธ์ชฝ์ X ์์ด์ฝ์ ํด๋ฆญํ๋ฉด ํญ๋ชฉ์ด ์ญ์ ๋์ด ๊ฒ์ ์ด๋ ฅ์์ ์ฌ๋ผ์ง๋๋ค.
- ๊ฒ์ ์ด๋ ฅ์ ์ต๋ 15๊ฐ๊น์ง๋ง ์ ์ฅ๋๋ฉฐ, ๊ทธ ์ด์ ๊ฒ์ํ ๊ฒฝ์ฐ ์ค๋๋ ํญ๋ชฉ๋ถํฐ ์ฌ๋ผ์ง๋๋ค.
- ์ฐ์ธก ์๋จ์ ์์ด์ฝ์ ํด๋ฆญ์ ๋คํฌ๋ชจ๋, ๋ผ์ดํธ๋ชจ๋๊ฐ ํ ๊ธ๋ฉ๋๋ค.
- ์์ด์ฝ ํด๋ฆญ ์ ์ ๋๋ฉ์ด์ ์ด ์ ์ฉ๋ฉ๋๋ค.
- ๊ฒ์ ์ด๋ ฅ ๋ฉ๋ด ์ข์๋จ์ โถ๋ฅผ ํด๋ฆญ ์ ๋ฉ๋ด์ width๊ฐ ์ค์ด๋ค๋ฉฐ ์ฌ๋ผ์ง๋๋ค.
- โ๋ก ๋ฐ๋ ์์ด์ฝ์ ๋ค์ ํด๋ฆญํ๋ฉด ๋ฉ๋ด๊ฐ ๋ํ๋ฉ๋๋ค.
- ์ ๋๋ฉ์ด์ ์ ์ฉ ์ค ๋ด๋ถ ๊ธ์จ๊ฐ ์ด์์์ผ๋ฉด ์ค๋ฐ๋์ด ์ ์ฉ๋๋ฉด์ ๊ธ์ด ๊ธธ์ญํด์ง๊ธฐ ๋๋ฌธ์, โถ ๋ฒํผ์ ๋๋ฅด๋ ์ฆ์ ๋ด๋ถ ๋ด์ฉ์ ์ญ์ ์ํต๋๋ค. โ๋ฒํผ์ ๋๋ฅด๋ฉด ์ ๋๋ฉ์ด์ ์ด ๋๋ ํ ๋ด๋ถ ์์๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
๋ฉ๋ด๋ฅผ ๋ซ์ ์ ํด๋น ์์๋งํผ width๊ฐ์ด ๋ณํ๋ฉด์ ๊ธฐํํ๋ ์๋์ ๋ค๋ฅธ ํํ์ ๋์์ธ์ด ๋์ด๋ฒ๋ฆฌ๋ ์ด์๊ฐ ์์์ต๋๋ค. ๋ฉ์ธ ํ๋ฉด์ width๊ฐ์ ๊ณ ์ ๊ฐ์ด ์๋๋ผ %๋ฅผ ์ฌ์ฉํ ๋น์จ๊ฐ์ผ๋ก ๋ฐ๊พธ๊ณ , max-width๋ฅผ ์ค์ ํ์ฌ ๋ฐ์ํ ๋์์ธ์ ์ผ๋ถ๋ฅผ ๊ตฌํํ ์ ์์์ต๋๋ค.
.main-container {
height: calc(100vh - 80px);
}
/.../
.chat-wrap {
width: 50%;
max-width: 650px;
}๋ฉ๋ด ์ฌ๋ผ์ด๋ ์ ์ค์ ํ ์ต๋ width๊ฐ์ ๋์ง ์๋ ์ ์์ ๋ฉ์ธ ํ๋ฉด์ด ๊ฐ๋ก๋ก ๋์ด๋ฉ๋๋ค.
์ฒ์์๋ ๋จ์ํ ์ ๋๋ฉ์ด์
์ ์ค ์์ด์ฝ์ transition: all ease 0.5๋ฅผ ์ฃผ๊ณ toggle ์ ์ด๋ฒคํธ๋ฅผ ํตํด transform์ ์ ์ฉํ์์ต๋๋ค. ํ์ง๋ง ์ด ๊ฒฝ์ฐ ํ์ด์ง๋ฅผ ์ฒ์ ๊ทธ๋ฆด ๋ ์์ด์ฝ์ผ๋ก ์ผ๋ ์ด๋ชจ์ง โ๏ธ์ ์ ์ฉ๋ scale, color ๋ฑ์ ํจ๊ณผ๊น์ง ์์ํ ์ ์ฉ๋๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
์ด๋ฒคํธ๋ก transform์ ์ ์ฉํ์์ ์, โ๏ธ์์ ๐๋ก ๋ณํ๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ๋ก ์ค์ ํ๊ณ ๐์์ โ๏ธ๋ก ๋ณํ ๋๋ ๋ณ๊ฐ์ ์ด๋ฒคํธ๋ฅผ ์ค์ ํด์ผํ๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
.dark-mode-button {
scale: 1.5;
border: 0;
color: transparent;
margin-right: 15px;
transition: text-shadow ease 0.3s, transform ease 0.3s;
}
.scale-down {
transform: scale(0) rotate(180deg);
}$darkModeButton.addEventListener("click", (e) => {
e.preventDefault();
let currentClass = $body.className;
$body.className = currentClass === "dark-mode" ? "light-mode" : "dark-mode";
//button animation
$darkModeButton.classList.add('scale-down');
setTimeout(()=>{
$darkModeButton.classList.remove('scale-down');
$darkModeButton.innerHTML = $darkModeButton.innerHTML === "๐" ? "โ๏ธ" : "๐";
}, 200);
});์์ ๋ฌธ์ ๋ class์์ฑ์ ์ค์ ํ ํด๋น class๋ฅผ add, remove ํ๋ ํํ๋ก ํด๊ฒฐํ์์ต๋๋ค. ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ ธ ํจ์จ์ฑ๊ณผ ๊ฐ๋ ์ฑ์ด ์ฌ๋์ผ๋ฉฐ, ๊ฒธ์ฌ๊ฒธ์ฌ setTimeout์ ์ด์ฉํ ๋๋ ์ด๊น์ง ๋ฐฐ์์ ์ฌ์ฉํ ์ ์์์ต๋๋ค.
์ฒ์ ๊ธฐ๋ฅ ๊ตฌํ ์ Layout์ ์ง ๋์ ๋ค, ๊ธฐ๋ฅ ๊ตฌํ๊ณผ ํจ๊ป ์ถ๊ฐ๋๋ ์ค๋ธ์ ํธ๋ค๋ง๋ค ์๋ก CSS๋ฅผ ๊ถ๋ฆฌํ๊ณ ์ ์ฉํ๋ ๊ฒ์ ์๊ฐ๊ณผ ์ฌ๋ ฅ์๋ชจ๊ฐ ๊ทน์ฌํ ์ผ์ด์์ต๋๋ค. ๋คํฌ๋ชจ๋๋ฅด ๊ตฌํํ ๋ ์์์ ํ๋ฒ ๋ ๊ณ ๋ฏผํ๊ณ ์ง์ ํด์ผํ๋ค๋ ๊ฒ์ ๊นจ๋ซ๊ณ ๋ณ์๋ฅผ ํตํด ์์ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์์ต๋๋ค.
/* variable */
:root {
--black: #151515;
--white: rgb(230, 230, 230);
/* dark */
--dark-color-header: rgb(32, 33, 35);
--dark-color-main: rgb(70, 70, 85);
--dark-color-history: rgb(53, 53, 65);
/.../
/* input */
--dark-input-textbox: rgb(230, 230, 230);
--dark-input-textarea: rgb(230, 230, 230);
--light-input-textbox: rgb(220, 220, 220);
--light-input-textarea: rgb(220, 220, 220);
}
/* subject-title holder, title */
body.dark-mode .subject-title {
color: var(--white);
}
body.light-mode .subject-title {
color: var(--black);
}๋ํ ๋ชจ๋ ์์์ ์ ์ฉํ์ง๋ ๋ชปํ์ง๋ง, ๊ณตํต๋ ์ฉ๋๋ฅผ ๊ฐ๋ ์์์ ๋์ผํ ํด๋์ค๋ช ์ addํ์ฌ ํ๋ฒ์ ์คํ์ผ ์ง์ ์ ํ ์ ์์ด ํจ์จ์ฑ์ ์ฑ๊ธธ ์ ์์์ต๋๋ค.
์ถํ ์ฌ์ฌ์ฉ์ฑ, ํ์ฅ์ฑ์ ์ํด ํ๋กฌํํธ ์์ง๋์ด๋ง์ data๋ก ์ธ ๋ฌธ์์ด์ ๋ฐ๋ก ํ์ผ๋ก ๊ด๋ฆฌํ ํ์์ฑ์ ๋๊ผ์ต๋๋ค. ๋ฐ๋ผ์
//./data.js
export const python = [
{
"role": "system",
"content": "assistant๋ ์ฌ๋ฌด์ ์ธ Python ์ ๋ฌธ๊ฐ์ด๋ค."
},
{
"role": "system",
"content": "assistant๋ ํจ์๋ช
, ๋ณ์๋ช
์ถ์ฒ ํ๋ก๊ทธ๋จ์ด๋ค."
},
{
"role": "system",
"content": "assistant๋ Python ์ด์ธ์ ์ง๋ฌธ์๋ ๋ต๋ณํ์ง ์๋๋ค."
},
]์ ํํ๋ก ๋ฐ๋ก jsํ์ผ์ Objectํํ๋ก ์ ์ฅํ์ฌ ๊ด๋ฆฌํ์์ต๋๋ค. ๋ณธ ํ๋ก๊ทธ๋จ์์๋ ๋ฐ์ดํฐ๋ฅผ ์ธ์ด๋ณ, ๊ธฐ๋ฅ๋ณ๋ก ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ด 8๊ฐ์ ๋ฐ์ดํฐ์ ์ด ํ์ํฉ๋๋ค. ์ฒ์์๋ ์๋์ ๊ฐ์ด ์ผ์ผ์ด ์ ์ธ, Init์ ํ์์ต๋๋ค.
let currentData = [];
let dataPython = [];
let dataJava = [];
let dataCpp = [];
let dataJs = [];
let conventionPython = [];
let conventionJava = [];
let conventionCpp = [];
let conventionJs = [];
dataPython = jsonObject.python;
...
conventionCpp = jsonObject.conCpp;
conventionJs = jsonObject.conJs;๊ฐ๋ฐ ์ค ๊ฐ๋ ์ฑ๊ณผ ํธ์์ฑ์ ๋ฌธ์ ๊ฐ ์์์ ๋๊ปด ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๊พธ์์ต๋๋ค.
const dataMap = {
1: {
python: [],
java: [],
cpp: [],
javascript: [],
},
2: {
python: [],
java: [],
cpp: [],
javascript: [],
},
};
function initData() {
dataMap[1].python = jsonObject.python;
dataMap[1].java = jsonObject.java;
dataMap[1].cpp = jsonObject.cpp;
dataMap[1].javascript = jsonObject.javascript;
dataMap[2].python = jsonObject.conpython;
dataMap[2].java = jsonObject.conjava;
dataMap[2].cpp = jsonObject.concpp;
dataMap[2].javascript = jsonObject.conjavascript;
}์๋ฐ์คํฌ๋ฆฝํธ์ DOM์ ํ์ฉํ ํจ์๋ฅผ ๋ง๋ ๋ค ๋ง์ดํ๋ ์๋ฌ์ ๋๋ค.
Uncaught TypeError: Cannot set properties of null (setting 'innerHTML')
๋ ๋๋ง ์์ง์ด jsํ์ผ์ ๋ก๋ํ๋ script ํ๊ทธ๋ฅผ ๋ง๋๋ฉด DOM ํ์ฑ์ ์ค๋จํ๊ณ , jsํ์ผ์ ๋ก๋ํ ํ ํด๋น ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ์ ์คํํ๋ค๊ณ ํฉ๋๋ค. ์ด ๋ ํด๋น js ํ์ผ์์ ์์ฑ๋๋ค ๋ง DOM์ ์ ๊ทผํ๊ฒ ๋๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
ํด๊ฒฐ์ฑ
์ 1. scriptํ๊ทธ๋ฅผ ๋ณธ๋ฌธ ์๋์ ์์น์ํจ๋ค. 2. async, defer ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ์ง์ ํ๋ค. ์์ต๋๋ค.
<script defer src="./module/index.js" type="module"></script>
<script defer src="./module/page-changer.js" type="module"></script>
<script defer src="./module/history.js" type="module"></script>
<script defer src="./module/gpt-api.js" type="module"></script>์ฐ์ ์๋ฌ๊ฐ ๋ ๋ ํ์ธ ํ defer๋ฅผ ๋ถ์ฌ ํด๊ฒฐํ์์ต๋๋ค. ํ์ง๋ง ์ดํ defer๋ฅผ ์์ ๋ ๋ค์ ์๋ฌ๊ฐ ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ ๋ฑ ์ ํํ ์ฉ๋์ ์ฌ์ฉ๋ฒ ํ์ ์ ๋ฏธ์ํจ์ ๋๊ปด ๋ ์ฐพ์๋ณผ ํ์๋ฅผ ๋๊ผ์ต๋๋ค.
์ฒ์์๋ ํ๋กฌํํธ ์์ง๋์ด๋ง์ '์ํ๋ ๋ํ๋ฅผ ํ ์ ์๋๋ก ํ์ตํ๋ ๊ฒ'์ผ๋ก ์ดํดํ์ง๋ง ๋ฉฐ์น ๊ณต๋ถํ๋ฉด์ ํ์ต์ด ์๋๋ผ '๋ํ๋ฅผ ํ๋ฉด์ ํ๋ฆ์ ์ก์์ฃผ๋ ๊ฒ'์ด๋ผ๋ ๊ฒ์ ์์์ต๋๋ค.
{
//GPT์ ์ญํ ์ง์
"role": "system",
"content": "assistant๋ Python ์ ๋ฌธ๊ฐ์ด๋ค."
/.../
{
//GPT์ ๋ํ๋ฅผ ํ๋ฉด์ ์์ฒญ, ๊ท์จ ๋ช
์
"role": "system",
"content": "assistant๋ ์ฝ๋๋ฅผ Python ์คํ์ผ๋ก ๋ณด์ฌ์ค๋ค."
},
{
//๋ต๋ณ ํํ ์์ฒญ
"role": "user",
"content": "์์ผ๋ก ๋ณ์๋ช
, ํจ์๋ช
์ง๋ฌธ์ list๋ก ๋ตํด์ค."
},
/.../
{
//GPT์ ๋ต๋ณ์ ์ ์ฅํด ์์ผ๋ก์ ๋ต๋ณ ํ์๊ณผ ๋ฐฉํฅ์ฑ์ ์ ๋
"role": "assistant",
"content": "ํจ์๋ช
: \n 1. multiply: ๊ณฑ์
์ ์ํํ๋ ํจ์ \n 2. product: ๋ ๊ฐ์ ์ซ์๋ฅผ ๊ณฑํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ํจ์ \n 3. calculate_product:/.../ํ๋ด๋ ๋ณ์ \n 2. result: ๊ณฑ์
๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๋ ๋ณ์ \n 3. multiplier, multiplicand: ๊ณฑ์
์ ํผ์ฐ์ฐ์๋ฅผ ๋ํ๋ด๋ ๋ณ์ \n 5. operand1, operand2: ๊ณฑ์
์ ์ฌ์ฉ๋๋ ํผ์ฐ์ฐ์๋ฅผ ๋ํ๋ด๋ ๋ณ์"
},์ฒ์์๋ ๊ฐ์ ์ก์ง ๋ชปํ์ง๋ง ์คํ์ ์งํํ๋ฉด์ ๋งฅ๋ฝ์ ์๊ฒ ๋์์ต๋๋ค.
GPT์ ๋ต๋ณ์ ๊ท์น๊ณผ ์ ์ฝ์ ์ ํ๋ ๊ฒ์ role: system์ผ๋ก ์ง์ ํฉ๋๋ค. role: user๋ก ์์ฒญ์ ํด๋ ๋ฐ์๋ค์ฌ์ง์ง๋ง ์๋์ ์ผ๋ก system์ ๋นํด ๊ฐ๊ฑดํ์ง๋ ๋ชปํ ๋๋์ ๋ฐ์์ต๋๋ค.
๋ต๋ณ์ ๊ตฌ์ฒด์ ์ธ ํํ๋ role: user๋ก "~~ํ๊ฒ ๋ตํด์ค." ๋ผ๋ ํํ๋ก ์์ฒญํด๋ ๋ฐ์๋ค์ฌ์ง๊ธฐ๋ ํ์ง๋ง ๋ฌด์๋๋ ๊ฒฝํฅ์ด ๊ฐํ์ต๋๋ค. role: assistant๋ก GPT์ ๋ต๋ณ ์ค ์ด๋ฐ ํํ๊ฐ ์ ํจํ๋ค๊ณ ์ ๋ ฅํ๋ฉด ๋์ ํ๋ฅ ๋ก ๊ทธ ํํ์ ๋ง์ถฐ์ฃผ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
๋ํ role: user๋ก ๊ฐ์ ์ ํ์ ์ง๋ฌธ์ ๋ฐ๋ณตํ๋ฉด GPT์ ๋ํ์ ๋ต๋ณ์ scope๊ฐ ๊ทธ๊ฒ์ ์ง์ค๋๋ ๊ฒฝํฅ์ ๋ณด์ด๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
"ํจ์๋ช
: 1. multiply: ๊ณฑ์
์ ์ํํ๋ ํจ์ 2. product: ๋ ๊ฐ์ ์ซ์๋ฅผ ๊ณฑํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ํจ์ 3/..../๊ณฑ์
์ ํผ์ฐ์ฐ์๋ฅผ ๋ํ๋ด๋ ๋ณ์ 5. operand1, operand2: ๊ณฑ์
์ ์ฌ์ฉ๋๋ ํผ์ฐ์ฐ์๋ฅผ ๋ํ๋ด๋ ๋ณ์"GPT์ ๋ต๋ณ์ ์ถ๋ ฅํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ฉด์ ํ
์คํธ๊ฐ ์์ ๊ฐ์ด ๋์ค๋ ๊ฒฝ์ฐ๊ฐ ์์์ต๋๋ค. consol.log(answer)๋ก ์ฐ์ด๋ณด๋ ๋ฌธ์์ด์ ์ด์ค์ผ์ดํ ๊ฐํ๋ฌธ์ '\n'์ด ํฌํจ๋์ด ์๊ณ , HTML์์๋ ์ด๊ฒ์ด ์ธ์๋๊ณ ์์ง ์๋ ๊ฒ์ ํ์ธํ์ต๋๋ค. ์ฒ์์๋ ๋ค์๊ณผ ๊ฐ์ ํจ์๋ฅผ ๋ง๋ค์์ต๋๋ค.
function replaceNltoBr(answer) {
if (typeof answer !== 'string') {
return answer;
}
return answer.replace(/\n/g, "<br>");
}'\n'์
๋ก ๋ฐ๊ฟ HTML์์๋ ๊ฐํ์ด ์ธ์๋์์ต๋๋ค.
ํ์ง๋ง ๋๋ฒ์งธ ์ฃผ์ ๊ธฐ๋ฅ '์ฝ๋ ์
๋ ฅ ํ ๋ณํ ์ถ๋ ฅ'์์๋ ํด๋น ํจ์๋ฅผ ์ ์ฉํ ์ ์์์ต๋๋ค.
const printAnswer = (answer) => {
saveHistoryData(answer);
saveLocalStorage(localData);
displayLocalStorage();
$chatList.innerText = "";
let li = document.createElement("li");
li.class_name = "answer";
add-pre-tag(li, answer);
$chatList.appendChild(li);
};๋ต๋ณ์ด ์ด๋ฐ์์ผ๋ก ์ค๋ฉด ๊ฐํ๋ฟ ์๋๋ผ tab๊น์ง ๊ณ ๋ คํด์ผ ํ๊ธฐ ๋๋ฌธ์ <br>ํ๊ทธ๋ก๋ ํด๊ฒฐํ ์ ์์์ต๋๋ค. ๋ค๋ฆ๊ฒ HTML์ li์ text์์๋ก ๋ต๋ณ์ ๋ฃ์ ๊ฒ์ด ์๋๋ผ preํ๊ทธ์ codeํ๊ทธ๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ๋ฐ๊ฒฌํ์ต๋๋ค.
function addPreTag(li, answer) {
if (currentPage === 1) {
li.innerText = answer;
}
else {
let pre = document.createElement("pre");
let code = document.createElement("code");
code.className = `language-${selectedLang}`;
code.innerText = answer;
pre.appendChild(code);
li.appendChild(pre);
}
}์ฝ๋ ๋ธ๋ก์ ๋ต๋ณ์ผ๋ก ๋ฐ์ ๋๋ ํด๋น ํจ์๋ฅผ ์ ์ฉํ์ฌ li์์์ pre, code์์๋ฅผ ์ถ๊ฐํ์ฌ ์ฝ๋ ๋ธ๋ก ์งธ๋ก ์ถ๋ ฅํ ์ ์๊ฒ ํ์์ต๋๋ค.
Velog - ์ฒซ ํ๋ก์ ํธ๋ฅผ ๋๋ด๊ณ ..๋๋์ /๋ฏธํกํ๋ ์
- ํนํ, ์ด๋ฐ ๊ธฐํ์ ๋ฐ๋๋ ๊ฒฝ์ฐ์ ๋๋นํด ํ์ฅ์ฑ์ ๊ณ ๋ คํ ๊ฒ
- ์ต์์น ์์๋ ๋ฒ๋ฆ์ ๋ค์ผ ๊ฒ
- ์ฌ์ฌ์ฉ์ฑ๊ณผ ์์ ์ฑ์ ์ต์ฐ์ ์ ์ผ๋ก ๊ณ ๋ ค
- ๊ฐ์ผ๋ก ๋๋ ์ ๋ชจ๋ํ๋ผ๊ณ ์ธ์ํ์ง ๋ง๊ณ ํ์คํ ์๊ณ ์ธ ๊ฒ
- ๋ด ์ค์ค๋ก๋ฅผ ๊ณผ๋ํ๊ฐํ์ง ๋ง ๊ฒ
- ์ด ์ฝ๋๋ ํญ์ ๋ ์ต์ ํํ ์ ์๊ณ ๋ ๋ณด๊ธฐ ์ข๊ฒ ๋ง๋ค ์ ์๋ค๊ณ ์๊ฐํ ๊ฒ







