Ver3.0 ๐ค ChatGPT API๋ก ์๋์์ ์์คํ ์ค๊ณํ๊ธฐ

๐ค ChatGPT API๋ก ์๋์์ ์์คํ ์ค๊ณํ๊ธฐ
๐ฏ ์ ์ง๊ธ ChatGPT API ์๋ํ์ธ๊ฐ?
์๋
! ์ค๋์ ์ ๋ง ์ค์ฉ์ ์ด๊ณ ์ฌ๋ฏธ์๋ ์ฃผ์ ๋ฅผ ๊ฐ์ง๊ณ ์์ด. ๋ฐ๋ก ChatGPT API๋ฅผ ํ์ฉํ ์๋์์
์์คํ
์ค๊ณ์ ๋ํ ์ด์ผ๊ธฐ์ผ. ๐
์์ฆ ์
๋ฌดํ๋ค ๋ณด๋ฉด ๋ฐ๋ณต์ ์ธ ์์
๋ค์ด ์ ๋ง ๋ง์ง ์์? ์ด๋ฉ์ผ ๋ต์ฅ ์ฐ๊ธฐ, ๋ฐ์ดํฐ ์ ๋ฆฌํ๊ธฐ, ๋ณด๊ณ ์ ์ด์ ์์ฑํ๊ธฐ... ์ด๋ฐ ์ผ๋ค์ ๋งค์ผ ํ๋ค ๋ณด๋ฉด ์ ์ ์ค์ํ ์ฐฝ์์ ์ธ ์
๋ฌด์ ์ธ ์๊ฐ์ด ๋ถ์กฑํด์ง๊ณค ํด. ๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ ChatGPT API๊ฐ ๋ฑ์ฅํ๋ฉด ์ด์ผ๊ธฐ๊ฐ ์์ ํ ๋ฌ๋ผ์ ธ! ๐
ChatGPT API๋ OpenAI์์ ์ ๊ณตํ๋ ์ธ๊ณต์ง๋ฅ ์ธ์ด๋ชจ๋ธ์ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๋๊ตฌ์ผ. ์ฝ๊ฒ ๋งํ๋ฉด, ์ฐ๋ฆฌ๊ฐ ChatGPT ์น์ฌ์ดํธ์์ ๋ํํ๋ฏ์ด ์ง๋ฌธํ๊ณ ๋ต๋ณ๋ฐ๋ ๊ทธ ๊ธฐ๋ฅ์ ์ฐ๋ฆฌ ํ๋ก๊ทธ๋จ ์์ ์ง์ ๋ฃ์ ์ ์๋ค๋ ๊ฑฐ์ง.
์ค์ ๋ก ๋ง์ ๊ธฐ์ ๋ค์ด ์ด๋ฏธ ChatGPT API๋ฅผ ํ์ฉํด์ ์ ๋ฌด ํจ์จ์ ํฌ๊ฒ ๋์ด๊ณ ์์ด. ๊ณ ๊ฐ ์๋น์ค ์๋ํ, ์ฝํ ์ธ ์์ฑ, ๋ฐ์ดํฐ ๋ถ์, ์ฝ๋ ๋ฆฌ๋ทฐ ์๋ํ ๋ฑ ํ์ฉ ๋ฒ์๊ฐ ์ ๋ง ๋์ด. ๊ทธ๋ฆฌ๊ณ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ AI ์๋ํ ๊ด๋ จ ์ฌ๋ฅ์ ๊ฑฐ๋ํ๋ ์ฌ๋ก๊ฐ ์ ์ ๋์ด๋๊ณ ์๋ค๋ ์ ๋ ์ฃผ๋ชฉํ ๋งํด! ๐
๐ ChatGPT API์ ๊ธฐ๋ณธ ๊ฐ๋ ์ดํดํ๊ธฐ
๋ณธ๊ฒฉ์ ์ผ๋ก ์๋ํ ์์คํ ์ ์ค๊ณํ๊ธฐ ์ ์, ChatGPT API๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ํ์คํ ์ก๊ณ ๊ฐ์. ์ด ๋ถ๋ถ์ ์ ๋๋ก ์ดํดํ๋ฉด ๋์ค์ ์์คํ ์ค๊ณํ ๋ ํจ์ฌ ์์ํด์ง ๊ฑฐ์ผ! ๐ช
๐ก API๋ ๋ฌด์์ธ๊ฐ?
API๋ Application Programming Interface์ ์ฝ์์ผ. ์ฝ๊ฒ ๋น์ ํ์๋ฉด, ๋ ์คํ ๋์ ๋ฉ๋ดํ๊ณผ ์จ์ดํฐ ๊ฐ์ ์ญํ ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ. ์ฐ๋ฆฌ๊ฐ ์ฃผ๋ฐฉ์ ์ง์ ๋ค์ด๊ฐ์ ์๋ฆฌ๋ฅผ ๋ง๋ค ํ์ ์์ด, ๋ฉ๋ดํ์ ๋ณด๊ณ ์จ์ดํฐ์๊ฒ ์ฃผ๋ฌธํ๋ฉด ์๋ฆฌ๊ฐ ๋์ค์์? API๋ ๋ง์ฐฌ๊ฐ์ง์ผ.
ChatGPT API๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฑด, OpenAI์ ๊ฐ๋ ฅํ AI ๋ชจ๋ธ์๊ฒ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์์
์ ์์ฒญํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์์ค๋ ๊ฑฐ์ผ. ์ฐ๋ฆฌ๊ฐ ์ง์ AI ๋ชจ๋ธ์ ๋ง๋ค๊ฑฐ๋ ํ์ต์ํฌ ํ์ ์์ด, ์ด๋ฏธ ์ ๋ง๋ค์ด์ง AI์ ๋ฅ๋ ฅ์ ๋น๋ ค ์ฐ๋ ๊ฑฐ์ง! ๐ฏ
๐งฉ ์ฃผ์ ๊ตฌ์ฑ ์์
API ํค๋ ์ผ์ข ์ ์ถ์ ์ฆ์ด์ผ. OpenAI ๊ณ์ ์ ๋ง๋ค๊ณ API ํค๋ฅผ ๋ฐ๊ธ๋ฐ์์ผ ChatGPT API๋ฅผ ์ฌ์ฉํ ์ ์์ด. ์ด ํค๋ ์ ๋ ๊ณต๊ฐํ๋ฉด ์ ๋๊ณ , ์์ ํ๊ฒ ๋ณด๊ดํด์ผ ํด. ์๋ํ๋ฉด ์ด ํค๋ก API๋ฅผ ์ฌ์ฉํ๋ฉด ๋น์ฉ์ด ์ฒญ๊ตฌ๋๊ฑฐ๋ ! ๐ณ
์๋ํฌ์ธํธ๋ API ์์ฒญ์ ๋ณด๋ด๋ ์ฃผ์์ผ. ChatGPT API์ ๊ฒฝ์ฐ ์ฃผ๋ก
https://api.openai.com/v1/chat/completions ๊ฐ์ URL์ ์ฌ์ฉํด. ์ด ์ฃผ์๋ก ์ฐ๋ฆฌ์ ์์ฒญ์ ๋ณด๋ด๋ฉด AI๊ฐ ์ฒ๋ฆฌํด์ ๋ต๋ณ์ ๋๋ ค์ค.
์์ฒญ์ ์ฐ๋ฆฌ๊ฐ AI์๊ฒ ๋ณด๋ด๋ ๋ฉ์์ง์ผ. ์ฌ๊ธฐ์๋ ์ฌ๋ฌ ๊ฐ์ง ์ ๋ณด๊ฐ ํฌํจ๋ผ:
- ๋ชจ๋ธ ์ ํ: GPT-4, GPT-3.5-turbo ๋ฑ ์ด๋ค ๋ชจ๋ธ์ ์ฌ์ฉํ ์ง
- ๋ฉ์์ง: AI์๊ฒ ์ ๋ฌํ ์ค์ ๋ด์ฉ
- ํ๋ผ๋ฏธํฐ: ์๋ต์ ๊ธธ์ด, ์ฐฝ์์ฑ ์ ๋ ๋ฑ์ ์กฐ์ ํ๋ ์ค์ ๊ฐ๋ค
์๋ต์ AI๊ฐ ์ฐ๋ฆฌ ์์ฒญ์ ์ฒ๋ฆฌํ ๊ฒฐ๊ณผ์ผ. JSON ํ์์ผ๋ก ๋์์ค๋ฉฐ, ์ฌ๊ธฐ์๋ AI๊ฐ ์์ฑํ ํ ์คํธ๋ฟ๋ง ์๋๋ผ ์ฌ์ฉํ ํ ํฐ ์, ๋ชจ๋ธ ์ ๋ณด ๋ฑ ๋ค์ํ ๋ฉํ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ผ ์์ด.
๐ฐ ํ ํฐ๊ณผ ๋น์ฉ ์ดํดํ๊ธฐ
ChatGPT API๋ฅผ ์ฌ์ฉํ ๋ ๊ฐ์ฅ ์ค์ํ ๊ฐ๋
์ค ํ๋๊ฐ ๋ฐ๋ก 'ํ ํฐ'์ด์ผ. ํ ํฐ์ ํ
์คํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ธฐ๋ณธ ๋จ์์ธ๋ฐ, ๋๋ต ์์ด ๋จ์ด ํ๋๊ฐ 1~2๊ฐ ํ ํฐ ์ ๋๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ. ํ๊ธ์ ๊ฒฝ์ฐ๋ ์กฐ๊ธ ๋ ๋ณต์กํด์, ํ ๊ธ์๊ฐ 2~3๊ฐ ํ ํฐ์ด ๋ ์๋ ์์ด.
๋น์ฉ์ ์ด ํ ํฐ ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฒญ๊ตฌ๋ผ. ์๋ฅผ ๋ค์ด GPT-4์ ๊ฒฝ์ฐ ์
๋ ฅ ํ ํฐ 1,000๊ฐ๋น ์ฝ $0.03, ์ถ๋ ฅ ํ ํฐ 1,000๊ฐ๋น ์ฝ $0.06 ์ ๋์ ๋น์ฉ์ด ๋ฐ์ํด. (๊ฐ๊ฒฉ์ ๋ณ๋๋ ์ ์์ผ๋ ๊ณต์ ๋ฌธ์๋ฅผ ํ์ธํด์ผ ํด!) ๐
๐ ๏ธ ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ํ๊ธฐ
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ๊ฐ๋ฐ ํ๊ฒฝ์ ์ค์ ํด๋ณผ ์๊ฐ์ด์ผ! ๊ฑฑ์ ํ์ง ๋ง, ์๊ฐ๋ณด๋ค ์ด๋ ต์ง ์์. ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐ๋ผ์ค๋ฉด ๊ธ๋ฐฉ ์ค๋นํ ์ ์์ ๊ฑฐ์ผ. ๐
๐ ํ์ํ ์ค๋น๋ฌผ
| ํญ๋ชฉ | ์ค๋ช | ํ์ ์ฌ๋ถ |
|---|---|---|
| OpenAI ๊ณ์ | API ํค๋ฅผ ๋ฐ๊ธ๋ฐ๊ธฐ ์ํ ๊ณ์ | โ ํ์ |
| ํ๋ก๊ทธ๋๋ฐ ์ธ์ด | Python, JavaScript, Java ๋ฑ | โ ํ์ |
| ๊ฐ๋ฐ ๋๊ตฌ | VS Code, PyCharm ๋ฑ ์ฝ๋ ์๋ํฐ | โ ํ์ |
| ๊ฒฐ์ ์๋จ | API ์ฌ์ฉ๋ฃ ๊ฒฐ์ ์ฉ ์ ์ฉ์นด๋ | โ ํ์ |
| ๋ฐ์ดํฐ๋ฒ ์ด์ค | ์์ ๊ฒฐ๊ณผ ์ ์ฅ์ฉ (์ ํ์ฌํญ) | โญ ์ ํ |
๐ OpenAI API ํค ๋ฐ๊ธ๋ฐ๊ธฐ
์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ OpenAI์์ API ํค๋ฅผ ๋ฐ๊ธ๋ฐ๋ ๊ฑฐ์ผ. ์ด ๊ณผ์ ์ ์ ๋ง ๊ฐ๋จํด:
Step 1: OpenAI ์น์ฌ์ดํธ(platform.openai.com)์ ์ ์ํด์ ๊ณ์ ์ ๋ง๋ค์ด. ์ด๋ฏธ ChatGPT๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ๊ฐ์ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํ๋ฉด ๋ผ! ๐
Step 2: ๋ก๊ทธ์ธ ํ 'API Keys' ๋ฉ๋ด๋ก ์ด๋ํด. ์ฌ๊ธฐ์ 'Create new secret key' ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์๋ก์ด API ํค๊ฐ ์์ฑ๋ผ.
Step 3: ์์ฑ๋ ํค๋ ๋ฑ ํ ๋ฒ๋ง ๋ณด์ฌ์ฃผ๋๊น, ๋ฐ๋์ ์์ ํ ๊ณณ์ ๋ณต์ฌํด์ ์ ์ฅํด๋ฌ์ผ ํด. ๋์ค์ ๋ค์ ๋ณผ ์ ์๊ฑฐ๋ ! ๐
Step 4: ๊ฒฐ์ ์ ๋ณด๋ฅผ ๋ฑ๋กํด. OpenAI๋ ์ฌ์ฉํ ๋งํผ ๋น์ฉ์ ์ฒญ๊ตฌํ๋ ์ข
๋์ ๋ฐฉ์์ด์ผ. ์ฒ์ ๊ฐ์
ํ๋ฉด ์์ก์ ๋ฌด๋ฃ ํฌ๋ ๋ง์ ์ ๊ณตํ๊ธฐ๋ ํ๋ ํ์ธํด๋ด!
๐ Python ํ๊ฒฝ ์ค์ (์ถ์ฒ)
ChatGPT API๋ฅผ ์ฌ์ฉํ๋ ๋ฐ๋ ์ฌ๋ฌ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ์ธ ์ ์์ง๋ง, ๋๋ Python์ ์ถ์ฒํด. ์๋ํ๋ฉด OpenAI์์ ๊ณต์์ ์ผ๋ก Python ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ์ง์ํ๊ณ , ์ฝ๋๋ ๊ฐ๊ฒฐํ๊ณ ์ฝ๊ธฐ ์ฝ๊ฑฐ๋ ! ๐
๋จผ์ Python์ด ์ค์น๋์ด ์๋์ง ํ์ธํด๋ด. ํฐ๋ฏธ๋์ด๋ ๋ช
๋ น ํ๋กฌํํธ์์ ๋ค์ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํด๋ณด๋ฉด ๋ผ:
python --version
Python 3.7 ์ด์์ด ์ค์น๋์ด ์์ผ๋ฉด ์ค๋น ์๋ฃ! ์๋ค๋ฉด python.org์์ ๋ค์ด๋ก๋ํด์ ์ค์นํ๋ฉด ๋ผ.
๋ค์์ผ๋ก OpenAI Python ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํด์ผ ํด. ์ด๊ฒ๋ ์ ๋ง ๊ฐ๋จํด:
pip install openai
์ถ๊ฐ๋ก ์๋ํ ์์คํ ์ ๋ง๋ค ๋ ์ ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๋ ํจ๊ป ์ค์นํ๋ฉด ์ข์:
pip install python-dotenv requests pandas schedule
๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ญํ ์ ๊ฐ๋จํ ์ค๋ช
ํ๋ฉด:
- python-dotenv: ํ๊ฒฝ ๋ณ์๋ฅผ ์์ ํ๊ฒ ๊ด๋ฆฌ
- requests: HTTP ์์ฒญ์ ์ฝ๊ฒ ์ฒ๋ฆฌ
- pandas: ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐ ๋ถ์
- schedule: ์์
์ค์ผ์ค๋ง (์ ํด์ง ์๊ฐ์ ์๋ ์คํ)
๐ ์ฒซ ๋ฒ์งธ API ํธ์ถ ํ ์คํธ
์, ์ด์ ๋ชจ๋ ์ค๋น๊ฐ ๋๋ฌ์ผ๋ ์ค์ ๋ก API๋ฅผ ํธ์ถํด๋ณด์! ๊ฐ๋จํ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํด๋ณผ๊ฒ. ์๋ก์ด Python ํ์ผ์ ๋ง๋ค๊ณ ๋ค์ ์ฝ๋๋ฅผ ์ ๋ ฅํด๋ด:
import openai
import os
from dotenv import load_dotenv
# ํ๊ฒฝ ๋ณ์ ๋ก๋
load_dotenv()
# API ํค ์ค์
openai.api_key = os.getenv("OPENAI_API_KEY")
# ๊ฐ๋จํ ๋ํ ํ
์คํธ
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "๋น์ ์ ์น์ ํ AI ์ด์์คํดํธ์
๋๋ค."},
{"role": "user", "content": "์๋
ํ์ธ์! ChatGPT API ํ
์คํธ ์ค์
๋๋ค."}
],
temperature=0.7,
max_tokens=150
)
# ์๋ต ์ถ๋ ฅ
print(response.choices[0].message.content)
print(f"\n์ฌ์ฉ๋ ํ ํฐ: {response.usage.total_tokens}")
์ด ์ฝ๋๋ฅผ ์คํํ๊ธฐ ์ ์, ํ๋ก์ ํธ ํด๋์ .env ํ์ผ์ ๋ง๋ค๊ณ ๋ค์๊ณผ ๊ฐ์ด API ํค๋ฅผ ์ ์ฅํด์ผ ํด:
OPENAI_API_KEY=your-api-key-here
์ฝ๋๋ฅผ ์คํํ๋ฉด ChatGPT๊ฐ ์น์ ํ๊ฒ ์ธ์ฌ๋ฅผ ํด์ค ๊ฑฐ์ผ! ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ๋ ํ ํฐ ์๋ ํจ๊ป ์ถ๋ ฅ๋๋๊น, ๋น์ฉ์ด ์ผ๋ง๋ ๋ค์๋์ง ๋๋ต ๊ณ์ฐํด๋ณผ ์ ์์ด. ๐
๋ง์ฝ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๋ฉด, API ํค๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์๋์ง, ์ธํฐ๋ท ์ฐ๊ฒฐ์ ์ ์์ธ์ง, ๊ฒฐ์ ์ ๋ณด๊ฐ ์ ๋๋ก ๋ฑ๋ก๋์๋์ง ํ์ธํด๋ด!
๐๏ธ ์๋ํ ์์คํ ์ํคํ ์ฒ ์ค๊ณ
์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์๋ํ ์์คํ ์ ์ ์ฒด ๊ตฌ์กฐ๋ฅผ ์ค๊ณํด๋ณผ ์๊ฐ์ด์ผ! ์ข์ ์ํคํ ์ฒ๋ ์์คํ ์ ์ฑ๋ฅ, ์ ์ง๋ณด์์ฑ, ํ์ฅ์ฑ์ ๊ฒฐ์ ํ๋ ํต์ฌ ์์์ผ. ๋ง์น ๊ฑด๋ฌผ์ ์ง์ ๋ ํผํผํ ์ค๊ณ๋๊ฐ ํ์ํ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ! ๐๏ธ
๐จ ์์คํ ๊ตฌ์กฐ์ ๊ธฐ๋ณธ ์์น
์๋ํ ์์คํ
์ ์ค๊ณํ ๋๋ ๋ช ๊ฐ์ง ์ค์ํ ์์น์ ๋ฐ๋ผ์ผ ํด:
1. ๋ชจ๋ํ (Modularity)
๊ฐ ๊ธฐ๋ฅ์ ๋
๋ฆฝ์ ์ธ ๋ชจ๋๋ก ๋ถ๋ฆฌํด์ผ ํด. ์๋ฅผ ๋ค์ด '๋ฐ์ดํฐ ์์ง', 'API ํธ์ถ', '๊ฒฐ๊ณผ ์ ์ฅ', '์๋ฌ ์ฒ๋ฆฌ' ๊ฐ์ ๊ธฐ๋ฅ๋ค์ ๊ฐ๊ฐ ๋ณ๋์ ๋ชจ๋๋ก ๋ง๋๋ ๊ฑฐ์ผ. ์ด๋ ๊ฒ ํ๋ฉด ๋์ค์ ํน์ ๋ถ๋ถ๋ง ์์ ํ๊ฑฐ๋ ์
๊ทธ๋ ์ด๋ํ๊ธฐ๊ฐ ํจ์ฌ ์ฌ์์ ธ! ๐งฉ
2. ํ์ฅ์ฑ (Scalability)
์ฒ์์๋ ์์ ๊ท๋ชจ๋ก ์์ํ๋๋ผ๋, ๋์ค์ ์ฌ์ฉ๋์ด ๋์ด๋ ๊ฒ์ ๋๋นํด์ผ ํด. ์๋ฅผ ๋ค์ด ํ๋ฃจ์ 10๊ฐ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์์คํ
์ด ๊ฐ์๊ธฐ 1000๊ฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ ์๋ ์์์? ์ด๋ฐ ์ํฉ์ ๋๋นํ ์ค๊ณ๊ฐ ํ์ํด. ๐
3. ์์ ์ฑ (Reliability)
API ํธ์ถ์ด ์คํจํ๊ฑฐ๋, ๋คํธ์ํฌ ๋ฌธ์ ๊ฐ ์๊ธฐ๊ฑฐ๋, ์์์น ๋ชปํ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ด. ์ด๋ฐ ์ํฉ์์๋ ์์คํ
์ด ๋ฉ์ถ์ง ์๊ณ ์ ์ ํ ๋์ํ ์ ์์ด์ผ ํด. ์ฌ์๋ ๋ก์ง, ์๋ฌ ๋ก๊น
, ํด๋ฐฑ ๋ฉ์ปค๋์ฆ ๋ฑ์ด ํ์ํ์ง! ๐ก๏ธ
4. ๋น์ฉ ํจ์จ์ฑ (Cost Efficiency)
API ํธ์ถ์ ๋์ด ๋ค์ด. ๋ฐ๋ผ์ ๋ถํ์ํ ํธ์ถ์ ์ค์ด๊ณ , ์บ์ฑ์ ํ์ฉํ๊ณ , ํ ํฐ ์ฌ์ฉ์ ์ต์ ํํ๋ ์ ๋ต์ด ํ์ํด. ๐ฐ
๐ ์ํฌํ๋ก์ฐ ์ค๊ณ
์๋ํ ์์คํ
์ ์ํฌํ๋ก์ฐ๋ ํฌ๊ฒ ๋ค์ฏ ๋จ๊ณ๋ก ๋๋ ์ ์์ด:
Step 1: ํธ๋ฆฌ๊ฑฐ (Trigger)
์๋ํ๊ฐ ์์๋๋ ์์ ์ด์ผ. ์ด๊ฑด ์ฌ๋ฌ ๋ฐฉ์์ด ์์ด:
- ์๊ฐ ๊ธฐ๋ฐ: ๋งค์ผ ์ค์ 9์, ๋งค์ฃผ ์์์ผ ๋ฑ
- ์ด๋ฒคํธ ๊ธฐ๋ฐ: ์๋ก์ด ์ด๋ฉ์ผ ๋์ฐฉ, ํ์ผ ์
๋ก๋, ์นํ
์์ ๋ฑ
- ์๋ ์คํ: ์ฌ์ฉ์๊ฐ ๋ฒํผ์ ํด๋ฆญํ๊ฑฐ๋ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅ
Step 2: ๋ฐ์ดํฐ ์์ง ๋ฐ ์ ์ฒ๋ฆฌ
ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ณ ์ ๋ฆฌํ๋ ๋จ๊ณ์ผ. ์๋ฅผ ๋ค์ด ๊ณ ๊ฐ ๋ฌธ์ ๋ฉ์ผ์ ์ฒ๋ฆฌํ๋ค๋ฉด, ๋ฉ์ผ ๋ด์ฉ์ ๊ฐ์ ธ์์ ๋ถํ์ํ ์๋ช
์ด๋ ์ด์ ๋ํ ๋ด์ฉ์ ์ ๊ฑฐํ๋ ๊ฑฐ์ง. ์ด ๋จ๊ณ์์ ๋ฐ์ดํฐ ํ์ง์ด ๊ฒฐ์ ๋๋๊น ์ ๋ง ์ค์ํด! ๐
Step 3: API ํธ์ถ ๋ฐ ์ฒ๋ฆฌ
์ ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ChatGPT API์ ์์ฒญ์ ๋ณด๋ด๋ ๋จ๊ณ์ผ. ์ฌ๊ธฐ์ ํ๋กฌํํธ ์์ง๋์ด๋ง์ด ํต์ฌ์ด์ผ. ์ด๋ป๊ฒ ์ง๋ฌธํ๋๋์ ๋ฐ๋ผ ๊ฒฐ๊ณผ์ ํ์ง์ด ์ฒ์ฐจ๋ง๋ณ์ด๊ฑฐ๋ ! ๐ฏ
Step 4: ๊ฒฐ๊ณผ ๊ฒ์ฆ ๋ฐ ํ์ฒ๋ฆฌ
API๋ก๋ถํฐ ๋ฐ์ ์๋ต์ ๊ฒ์ฆํ๊ณ ํ์ํ ํ์์ผ๋ก ๋ณํํ๋ ๋จ๊ณ์ผ. ๋๋ก๋ AI๊ฐ ์์์น ๋ชปํ ํ์์ผ๋ก ๋ต๋ณํ๊ฑฐ๋, ๋ถ์์ ํ ์๋ต์ ์ค ์ ์์ด. ์ด๋ฐ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ ๊ฒ์ฆ ๋ก์ง์ด ํ์ํด. โ
Step 5: ๊ฒฐ๊ณผ ์ ์ฅ ๋ฐ ์ก์
์ต์ข
๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ฑฐ๋, ์ด๋ฉ์ผ์ ๋ณด๋ด๊ฑฐ๋, ๋ค๋ฅธ ์์คํ
์ ์ ๋ฌํ๋ ๋ฑ์ ์ก์
์ ์ํํ๋ ๋จ๊ณ์ผ. ์ฌ๊ธฐ์ ๋ก๊น
๋ ํจ๊ป ํด๋๋ฉด ๋์ค์ ๋ฌธ์ ์ถ์ ์ด ์ฌ์์ ธ! ๐
2. ๋ฐ์ดํฐ ์์ง: ๋ฉ์ผ ๋ด์ฉ, ๋ฐ์ ์ ์ ๋ณด, ์ด์ ๋ํ ์ด๋ ฅ ์์ง
3. API ํธ์ถ: "๋ค์ ๊ณ ๊ฐ ๋ฌธ์์ ๋ํด ์น์ ํ๊ณ ์ ๋ฌธ์ ์ธ ๋ต๋ณ์ ์์ฑํด์ฃผ์ธ์: [๋ฌธ์ ๋ด์ฉ]"
4. ๊ฒฐ๊ณผ ๊ฒ์ฆ: ๋ต๋ณ์ด ์ ์ ํ ๊ธธ์ด์ธ์ง, ๋ฏผ๊ฐํ ์ ๋ณด๊ฐ ํฌํจ๋์ง ์์๋์ง ํ์ธ
5. ์ก์ : ๋ต๋ณ ์ด์์ ๋ด๋น์์๊ฒ ์ ๋ฌํ๊ฑฐ๋, ์๋์ผ๋ก ๊ณ ๊ฐ์๊ฒ ๋ฐ์ก
๐ ์ฃผ์ ์ปดํฌ๋ํธ ์ค๊ณ
์ด์ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ์ข ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์ค๊ณํด๋ณด์. ์ค์ ์ฝ๋ ๊ตฌ์กฐ๋ฅผ ์๊ฐํ๋ฉด์ ์ฝ์ด๋ด! ๐ป
ChatGPT API์์ ๋ชจ๋ ํต์ ์ ๋ด๋นํ๋ ํต์ฌ ๋ชจ๋์ด์ผ. ์ด ๋ชจ๋์ ๋ค์ ๊ธฐ๋ฅ๋ค์ ํฌํจํด์ผ ํด:
- API ํค ๊ด๋ฆฌ ๋ฐ ์ธ์ฆ
- ์์ฒญ ์์ฑ ๋ฐ ์ ์ก
- ์๋ต ํ์ฑ
- ์๋ฌ ํธ๋ค๋ง
- ์ฌ์๋ ๋ก์ง
- ํ ํฐ ์ฌ์ฉ๋ ์ถ์
์ด ๋ชจ๋์ ์ ๋ง๋ค์ด๋๋ฉด ๋์ค์ ๋ค๋ฅธ ํ๋ก์ ํธ์์๋ ์ฌ์ฌ์ฉํ ์ ์์ด์ ์ ๋ง ์ ์ฉํด! ๐ง
ํ๋กฌํํธ๋ฅผ ๊ด๋ฆฌํ๊ณ ์์ฑํ๋ ๋ชจ๋์ด์ผ. ํ๋์ฝ๋ฉ๋ ํ๋กฌํํธ ๋์ , ํ ํ๋ฆฟ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ผ๋ก ํ๋กฌํํธ๋ฅผ ์์ฑํ๋ ๊ฒ ์ข์. ์๋ฅผ ๋ค์ด:
template = "๋ค์ {category} ๊ด๋ จ ์ง๋ฌธ์ {tone} ํค์ผ๋ก ๋ต๋ณํด์ฃผ์ธ์: {question}"์ด๋ ๊ฒ ํ๋ฉด ๊ฐ์ ํ ํ๋ฆฟ์ผ๋ก ๋ค์ํ ์ํฉ์ ๋์ํ ์ ์์ด. ๋ํ ํ๋กฌํํธ ๋ฒ์ ๊ด๋ฆฌ๋ ์ค์ํด. A/B ํ ์คํธ๋ฅผ ํตํด ์ด๋ค ํ๋กฌํํธ๊ฐ ๋ ์ข์ ๊ฒฐ๊ณผ๋ฅผ ๋ด๋์ง ๋น๊ตํ ์ ์๊ฑฐ๋ ! ๐
์ฌ๋ฌ ์์ ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ํ ์์คํ ์ด์ผ. API์๋ ๋ถ๋น ์์ฒญ ์ ํ(Rate Limit)์ด ์๊ธฐ ๋๋ฌธ์, ๋ชจ๋ ์์ฒญ์ ๋์์ ๋ณด๋ผ ์ ์์ด. ํ๋ฅผ ์ฌ์ฉํ๋ฉด ์์ฒญ์ ์์๋๋ก ์ฒ๋ฆฌํ๊ณ , ์ ํ์ ์ด๊ณผํ์ง ์๋๋ก ์กฐ์ ํ ์ ์์ด.
Python์์๋
queue ๋ชจ๋์ด๋ Redis ๊ฐ์ ์ธ๋ถ ํ ์์คํ
์ ์ฌ์ฉํ ์ ์์ด. ๋ ๋ณต์กํ ์์คํ
์ด๋ผ๋ฉด Celery ๊ฐ์ ๋ถ์ฐ ์์
ํ๋ฅผ ๊ณ ๋ คํด๋ณผ ์๋ ์์ง! ๐ฆ
๊ฐ์ ์ง๋ฌธ์ ๋ํด ๋งค๋ฒ API๋ฅผ ํธ์ถํ๋ ๊ฑด ๋นํจ์จ์ ์ด์ผ. ์บ์ฑ์ ํ์ฉํ๋ฉด ๋น์ฉ์ ํฌ๊ฒ ์ ๊ฐํ ์ ์์ด! ์๋ฅผ ๋ค์ด "ํ์ฌ ์์ ์๊ฐ์ด ์ด๋ป๊ฒ ๋๋์?" ๊ฐ์ ์์ฃผ ๋ฌป๋ ์ง๋ฌธ์ ์บ์์ ์ ์ฅํด๋๊ณ ์ฌ์ฌ์ฉํ๋ ๊ฑฐ์ง.
๊ฐ๋จํ ๊ฒฝ์ฐ์๋ Python์ ๋์ ๋๋ฆฌ๋
functools.lru_cache๋ฅผ ์ฌ์ฉํ ์ ์๊ณ , ๋ ๋ณต์กํ ๊ฒฝ์ฐ์๋ Redis๋ Memcached ๊ฐ์ ์ ๋ฌธ ์บ์ฑ ์์คํ
์ ์ฌ์ฉํ ์ ์์ด. ๐พ
์์คํ ์ด ์ ๋๋ก ์๋ํ๋์ง ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๋ ๊ฑด ์ ๋ง ์ค์ํด! ๋ค์ ์ ๋ณด๋ค์ ์ถ์ ํด์ผ ํด:
- API ํธ์ถ ํ์ ๋ฐ ์ฑ๊ณต๋ฅ
- ํ๊ท ์๋ต ์๊ฐ
- ํ ํฐ ์ฌ์ฉ๋ ๋ฐ ๋น์ฉ
- ์๋ฌ ๋ฐ์ ๋น๋ ๋ฐ ์ ํ
- ์์คํ ๋ฆฌ์์ค ์ฌ์ฉ๋
Python์
logging ๋ชจ๋์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๊ณ , ๋ ๊ณ ๊ธ ๊ธฐ๋ฅ์ด ํ์ํ๋ฉด ELK Stack(Elasticsearch, Logstash, Kibana)์ด๋ Datadog ๊ฐ์ ๋๊ตฌ๋ฅผ ๊ณ ๋ คํด๋ณผ ์ ์์ด. ๐
๐ ๋ณด์ ๊ณ ๋ ค์ฌํญ
์๋ํ ์์คํ
์ ์ค๊ณํ ๋ ๋ณด์์ ์ ๋ ๊ฐ๊ณผํด์๋ ์ ๋๋ ๋ถ๋ถ์ด์ผ! ํนํ API ํค์ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ ๋์ฑ ์ ๊ฒฝ ์จ์ผ ํด. ๐ก๏ธ
API ํค ๋ณด์
- ํ๊ฒฝ ๋ณ์๋ ๋น๋ฐ ๊ด๋ฆฌ ์๋น์ค(AWS Secrets Manager, Azure Key Vault ๋ฑ) ์ฌ์ฉ
- ์ฝ๋์ ํ๋์ฝ๋ฉ ์ ๋ ๊ธ์ง
- ์ ๊ธฐ์ ์ธ ํค ๋กํ
์ด์
- ํค๋ณ ๊ถํ ์ต์ํ
๋ฐ์ดํฐ ๋ณด์
- ๋ฏผ๊ฐํ ์ ๋ณด๋ ์ํธํํด์ ์ ์ฅ
- API๋ก ์ ์กํ๋ ๋ฐ์ดํฐ์ ๊ฐ์ธ์ ๋ณด๊ฐ ํฌํจ๋์ง ์๋๋ก ์ฃผ์
- ๋ก๊ทธ์ ๋ฏผ๊ฐํ ์ ๋ณด ๊ธฐ๋ก ๊ธ์ง
- GDPR, ๊ฐ์ธ์ ๋ณด๋ณดํธ๋ฒ ๋ฑ ๊ด๋ จ ๋ฒ๊ท ์ค์
์ ๊ทผ ์ ์ด
- ์์คํ
์ ๋ํ ์ ๊ทผ ๊ถํ ๊ด๋ฆฌ
- API ์๋ํฌ์ธํธ ์ธ์ฆ ๋ฐ ์ธ๊ฐ
- IP ํ์ดํธ๋ฆฌ์คํธ ์ค์
- ๊ฐ์ฌ ๋ก๊ทธ ์ ์ง
๐ป ์ค์ ๊ตฌํ: ๋จ๊ณ๋ณ ์ฝ๋ ์์ฑ
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ๋ก ์ฝ๋๋ฅผ ์์ฑํด๋ณด์! ์ฌ๊ธฐ์๋ ์ค์ฉ์ ์ธ ์์ ๋ฅผ ํตํด ์๋ํ ์์คํ ์ ๋จ๊ณ๋ณ๋ก ๊ตฌํํด๋ณผ ๊ฑฐ์ผ. ์ฝ๋๋ฅผ ๋ฐ๋ผ ์น๋ฉด์ ์ง์ ์ค์ตํด๋ณด๋ฉด ํจ์ฌ ์ดํด๊ฐ ์ ๋ ๊ฑฐ์ผ! ๐ช
๐ฏ ํ๋ก์ ํธ ์์ : ๋ธ๋ก๊ทธ ์ฝํ ์ธ ์๋ ์์ฑ ์์คํ
์ฐ๋ฆฌ๊ฐ ๋ง๋ค ์์คํ
์ ์ฃผ์ ๋ฅผ ์
๋ ฅํ๋ฉด ์๋์ผ๋ก ๋ธ๋ก๊ทธ ๊ธ์ ์์ฑํด์ฃผ๋ ์์คํ
์ด์ผ. ๋จ์ํด ๋ณด์ด์ง๋ง, ์ค์ ๋ก๋ ์ฌ๋ฌ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค์ด ํฌํจ๋์ด ์์ด:
- ํค์๋ ๊ธฐ๋ฐ ์์๋ผ์ธ ์์ฑ
- ์น์
๋ณ ๋ด์ฉ ์์ฑ
- SEO ์ต์ ํ ์ ์
- ์ด๋ฏธ์ง ์ค๋ช
์์ฑ
- ๊ฒฐ๊ณผ ์ ์ฅ ๋ฐ ๊ด๋ฆฌ
๐ ํ๋ก์ ํธ ๊ตฌ์กฐ
blog_automation/
โ
โโโ .env # ํ๊ฒฝ ๋ณ์ (API ํค ๋ฑ)
โโโ config.py # ์ค์ ํ์ผ
โโโ main.py # ๋ฉ์ธ ์คํ ํ์ผ
โ
โโโ modules/
โ โโโ __init__.py
โ โโโ api_client.py # ChatGPT API ํด๋ผ์ด์ธํธ
โ โโโ prompt_manager.py # ํ๋กฌํํธ ๊ด๋ฆฌ
โ โโโ content_generator.py # ์ฝํ
์ธ ์์ฑ ๋ก์ง
โ โโโ storage.py # ๋ฐ์ดํฐ ์ ์ฅ
โ
โโโ templates/
โ โโโ prompts.json # ํ๋กฌํํธ ํ
ํ๋ฆฟ
โ
โโโ logs/ # ๋ก๊ทธ ํ์ผ
โโโ output/ # ์์ฑ๋ ์ฝํ
์ธ
๐ง Step 1: ๊ธฐ๋ณธ ์ค์ ๋ฐ API ํด๋ผ์ด์ธํธ
๋จผ์ config.py ํ์ผ์ ๋ง๋ค์ด์ ๊ธฐ๋ณธ ์ค์ ์ ์ ์ํด๋ณด์:
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
# API ์ค์
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
MODEL = "gpt-3.5-turbo" # ๋๋ "gpt-4"
# ํ ํฐ ์ ํ
MAX_TOKENS = 2000
TEMPERATURE = 0.7
# ์ฌ์๋ ์ค์
MAX_RETRIES = 3
RETRY_DELAY = 2 # ์ด
# ๋น์ฉ ์ ํ (๋ฌ๋ฌ)
DAILY_COST_LIMIT = 10.0
# ๋ก๊น
LOG_LEVEL = "INFO"
LOG_FILE = "logs/automation.log"
# ์ถ๋ ฅ ๋๋ ํ ๋ฆฌ
OUTPUT_DIR = "output"
๋ค์์ผ๋ก api_client.py๋ฅผ ๋ง๋ค์ด๋ณด์. ์ด๊ฑด ChatGPT API์์ ๋ชจ๋ ํต์ ์ ๋ด๋นํ๋ ํต์ฌ ๋ชจ๋์ด์ผ:
import openai
import time
import logging
from config import Config
class ChatGPTClient:
def __init__(self):
openai.api_key = Config.OPENAI_API_KEY
self.model = Config.MODEL
self.logger = logging.getLogger(__name__)
self.total_tokens_used = 0
def chat_completion(self, messages, temperature=None, max_tokens=None):
"""
ChatGPT API ํธ์ถ (์ฌ์๋ ๋ก์ง ํฌํจ)
"""
temperature = temperature or Config.TEMPERATURE
max_tokens = max_tokens or Config.MAX_TOKENS
for attempt in range(Config.MAX_RETRIES):
try:
response = openai.ChatCompletion.create(
model=self.model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens
)
# ํ ํฐ ์ฌ์ฉ๋ ์ถ์
tokens_used = response.usage.total_tokens
self.total_tokens_used += tokens_used
self.logger.info(f"API ํธ์ถ ์ฑ๊ณต. ์ฌ์ฉ ํ ํฐ: {tokens_used}")
return {
'content': response.choices[0].message.content,
'tokens': tokens_used,
'model': response.model
}
except openai.error.RateLimitError:
self.logger.warning(f"Rate limit ๋๋ฌ. {Config.RETRY_DELAY}์ด ํ ์ฌ์๋...")
time.sleep(Config.RETRY_DELAY)
except openai.error.APIError as e:
self.logger.error(f"API ์๋ฌ: {str(e)}")
if attempt < Config.MAX_RETRIES - 1:
time.sleep(Config.RETRY_DELAY)
else:
raise
except Exception as e:
self.logger.error(f"์์์น ๋ชปํ ์๋ฌ: {str(e)}")
raise
raise Exception("์ต๋ ์ฌ์๋ ํ์ ์ด๊ณผ")
def get_total_cost(self):
"""
์ด ๋น์ฉ ๊ณ์ฐ (๋๋ต์ ์ธ ์ถ์ )
"""
# GPT-3.5-turbo ๊ธฐ์ค: $0.002 per 1K tokens
cost_per_token = 0.002 / 1000
return self.total_tokens_used * cost_per_token
๐ Step 2: ํ๋กฌํํธ ๋งค๋์
ํ๋กฌํํธ๋ฅผ ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ํ ๋ชจ๋์ ๋ง๋ค์ด๋ณด์. ๋จผ์ templates/prompts.json ํ์ผ์ ๋ง๋ค์ด:
{
"outline_generation": {
"system": "๋น์ ์ ์ ๋ฌธ ์ฝํ
์ธ ๊ธฐํ์์
๋๋ค. ์ฃผ์ด์ง ์ฃผ์ ์ ๋ํด ์ฒด๊ณ์ ์ด๊ณ ๋
ผ๋ฆฌ์ ์ธ ๊ธ ๊ตฌ์กฐ๋ฅผ ๋ง๋ญ๋๋ค.",
"user_template": "๋ค์ ์ฃผ์ ์ ๋ํ ๋ธ๋ก๊ทธ ๊ธ์ ์์๋ผ์ธ์ ์์ฑํด์ฃผ์ธ์.\n\n์ฃผ์ : {topic}\n\n์๊ตฌ์ฌํญ:\n- 5-7๊ฐ์ ์ฃผ์ ์น์
์ผ๋ก ๊ตฌ์ฑ\n- ๊ฐ ์น์
์ ๋ช
ํํ ์ ๋ชฉ๊ณผ 2-3๊ฐ์ ํ์ ํฌ์ธํธ ํฌํจ\n- SEO๋ฅผ ๊ณ ๋ คํ ๊ตฌ์กฐ\n- ๋
์ ์นํ์ ์ธ ํ๋ฆ"
},
"section_writing": {
"system": "๋น์ ์ ์๋ จ๋ ๋ธ๋ก๊ทธ ์๊ฐ์
๋๋ค. ์น๊ทผํ๋ฉด์๋ ์ ๋ฌธ์ ์ธ ํค์ผ๋ก ๊ธ์ ์์ฑํฉ๋๋ค.",
"user_template": "๋ค์ ์น์
์ ๋ด์ฉ์ ์์ฑํด์ฃผ์ธ์.\n\n์ ์ฒด ์ฃผ์ : {topic}\n์น์
์ ๋ชฉ: {section_title}\n์น์
ํฌ์ธํธ: {section_points}\n\n์๊ตฌ์ฌํญ:\n- 300-500 ๋จ์ด ๋ถ๋\n- ๊ตฌ์ฒด์ ์ธ ์์ ํฌํจ\n- ๋
์๊ฐ ์ดํดํ๊ธฐ ์ฌ์ด ์ค๋ช
\n- ์์ฐ์ค๋ฌ์ด ๋ฌธ์ฅ ํ๋ฆ"
},
"seo_optimization": {
"system": "๋น์ ์ SEO ์ ๋ฌธ๊ฐ์
๋๋ค. ๊ฒ์ ์์ง ์ต์ ํ๋ฅผ ์ํ ์ค์ฉ์ ์ธ ์กฐ์ธ์ ์ ๊ณตํฉ๋๋ค.",
"user_template": "๋ค์ ๋ธ๋ก๊ทธ ๊ธ์ ๋ํ SEO ์ต์ ํ ์ ์์ ํด์ฃผ์ธ์.\n\n์ฃผ์ : {topic}\n๋ด์ฉ ์์ฝ: {content_summary}\n\n๋ค์ ํญ๋ชฉ์ ํฌํจํด์ฃผ์ธ์:\n- ์ถ์ฒ ํค์๋ (5-10๊ฐ)\n- ๋ฉํ ์ค๋ช
(150์ ์ด๋ด)\n- ์ ๋ชฉ ํ๊ทธ ์ ์\n- ๋ด๋ถ ๋งํฌ ์ ๋ต"
}
}
์ด์ prompt_manager.py๋ฅผ ๋ง๋ค์ด๋ณด์:
import json
import logging
class PromptManager:
def __init__(self, template_file="templates/prompts.json"):
self.logger = logging.getLogger(__name__)
with open(template_file, 'r', encoding='utf-8') as f:
self.templates = json.load(f)
def get_messages(self, template_name, **kwargs):
"""
ํ
ํ๋ฆฟ ์ด๋ฆ๊ณผ ๋ณ์๋ฅผ ๋ฐ์์ ๋ฉ์์ง ๋ฆฌ์คํธ ์์ฑ
"""
if template_name not in self.templates:
raise ValueError(f"ํ
ํ๋ฆฟ '{template_name}'์ ์ฐพ์ ์ ์์ต๋๋ค.")
template = self.templates[template_name]
# ์ฌ์ฉ์ ๋ฉ์์ง์ ๋ณ์ ์นํ
user_content = template['user_template'].format(**kwargs)
messages = [
{"role": "system", "content": template['system']},
{"role": "user", "content": user_content}
]
self.logger.debug(f"ํ๋กฌํํธ ์์ฑ: {template_name}")
return messages
def add_template(self, name, system_prompt, user_template):
"""
์๋ก์ด ํ
ํ๋ฆฟ ์ถ๊ฐ
"""
self.templates[name] = {
"system": system_prompt,
"user_template": user_template
}
self.logger.info(f"์ ํ
ํ๋ฆฟ ์ถ๊ฐ: {name}")
๐จ Step 3: ์ฝํ ์ธ ์์ฑ ๋ก์ง
์ด์ ์ค์ ๋ก ์ฝํ
์ธ ๋ฅผ ์์ฑํ๋ ํต์ฌ ๋ก์ง์ ๊ตฌํํด๋ณด์. content_generator.py:
import logging
import json
from api_client import ChatGPTClient
from prompt_manager import PromptManager
class ContentGenerator:
def __init__(self):
self.client = ChatGPTClient()
self.prompt_manager = PromptManager()
self.logger = logging.getLogger(__name__)
def generate_blog_post(self, topic):
"""
์ฃผ์ ๋ฅผ ๋ฐ์์ ์์ ํ ๋ธ๋ก๊ทธ ๊ธ ์์ฑ
"""
self.logger.info(f"๋ธ๋ก๊ทธ ๊ธ ์์ฑ ์์: {topic}")
# Step 1: ์์๋ผ์ธ ์์ฑ
outline = self._generate_outline(topic)
self.logger.info("์์๋ผ์ธ ์์ฑ ์๋ฃ")
# Step 2: ๊ฐ ์น์
๋ด์ฉ ์์ฑ
sections = self._write_sections(topic, outline)
self.logger.info(f"{len(sections)}๊ฐ ์น์
์์ฑ ์๋ฃ")
# Step 3: SEO ์ต์ ํ ์ ์
seo_suggestions = self._generate_seo(topic, sections)
self.logger.info("SEO ์ต์ ํ ์ ์ ์์ฑ ์๋ฃ")
# ๊ฒฐ๊ณผ ์กฐํฉ
result = {
'topic': topic,
'outline': outline,
'sections': sections,
'seo': seo_suggestions,
'metadata': {
'total_tokens': self.client.total_tokens_used,
'estimated_cost': self.client.get_total_cost()
}
}
self.logger.info(f"๋ธ๋ก๊ทธ ๊ธ ์์ฑ ์๋ฃ. ์ด ํ ํฐ: {result['metadata']['total_tokens']}")
return result
def _generate_outline(self, topic):
"""
์์๋ผ์ธ ์์ฑ
"""
messages = self.prompt_manager.get_messages(
'outline_generation',
topic=topic
)
response = self.client.chat_completion(messages)
# ์๋ต์ ํ์ฑํด์ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ๋ก ๋ณํ
outline_text = response['content']
# ๊ฐ๋จํ ํ์ฑ (์ค์ ๋ก๋ ๋ ์ ๊ตํ ํ์ฑ์ด ํ์ํ ์ ์์)
sections = []
current_section = None
for line in outline_text.split('\n'):
line = line.strip()
if not line:
continue
# ์ฃผ์ ์น์
(์ซ์๋ก ์์)
if line[0].isdigit() and '.' in line:
if current_section:
sections.append(current_section)
current_section = {
'title': line.split('.', 1)[1].strip(),
'points': []
}
# ํ์ ํฌ์ธํธ (-, *, โข ๋ฑ์ผ๋ก ์์)
elif line[0] in ['-', '*', 'โข'] and current_section:
current_section['points'].append(line[1:].strip())
if current_section:
sections.append(current_section)
return sections
def _write_sections(self, topic, outline):
"""
๊ฐ ์น์
์ ๋ด์ฉ ์์ฑ
"""
sections = []
for section_info in outline:
messages = self.prompt_manager.get_messages(
'section_writing',
topic=topic,
section_title=section_info['title'],
section_points='\n'.join(section_info['points'])
)
response = self.client.chat_completion(messages)
sections.append({
'title': section_info['title'],
'content': response['content'],
'tokens': response['tokens']
})
return sections
def _generate_seo(self, topic, sections):
"""
SEO ์ต์ ํ ์ ์ ์์ฑ
"""
# ์ ์ฒด ๋ด์ฉ ์์ฝ
content_summary = '\n\n'.join([
f"{s['title']}: {s['content'][:200]}..."
for s in sections
])
messages = self.prompt_manager.get_messages(
'seo_optimization',
topic=topic,
content_summary=content_summary
)
response = self.client.chat_completion(messages, temperature=0.5)
return response['content']
๐พ Step 4: ๋ฐ์ดํฐ ์ ์ฅ
์์ฑ๋ ์ฝํ
์ธ ๋ฅผ ์ ์ฅํ๋ ๋ชจ๋์ ๋ง๋ค์ด๋ณด์. storage.py:
import os
import json
import logging
from datetime import datetime
from config import Config
class ContentStorage:
def __init__(self):
self.logger = logging.getLogger(__name__)
self.output_dir = Config.OUTPUT_DIR
# ์ถ๋ ฅ ๋๋ ํ ๋ฆฌ ์์ฑ
os.makedirs(self.output_dir, exist_ok=True)
def save_blog_post(self, content_data):
"""
๋ธ๋ก๊ทธ ๊ธ์ ํ์ผ๋ก ์ ์ฅ
"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
topic_slug = self._slugify(content_data['topic'])
# JSON ํ์์ผ๋ก ์ ์ฅ
json_filename = f"{timestamp}_{topic_slug}.json"
json_path = os.path.join(self.output_dir, json_filename)
with open(json_path, 'w', encoding='utf-8') as f:
json.dump(content_data, f, ensure_ascii=False, indent=2)
self.logger.info(f"JSON ์ ์ฅ ์๋ฃ: {json_path}")
# Markdown ํ์์ผ๋ก๋ ์ ์ฅ
md_filename = f"{timestamp}_{topic_slug}.md"
md_path = os.path.join(self.output_dir, md_filename)
markdown_content = self._convert_to_markdown(content_data)
with open(md_path, 'w', encoding='utf-8') as f:
f.write(markdown_content)
self.logger.info(f"Markdown ์ ์ฅ ์๋ฃ: {md_path}")
return {
'json_path': json_path,
'markdown_path': md_path
}
def _convert_to_markdown(self, content_data):
"""
์ฝํ
์ธ ๋ฅผ Markdown ํ์์ผ๋ก ๋ณํ
"""
md = []
# ์ ๋ชฉ
md.append(f"# {content_data['topic']}\n")
# ๋ฉํ๋ฐ์ดํฐ
md.append(f"*์์ฑ์ผ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n")
md.append(f"*ํ ํฐ ์ฌ์ฉ: {content_data['metadata']['total_tokens']}*\n")
md.append(f"*์์ ๋น์ฉ: ${content_data['metadata']['estimated_cost']:.4f}*\n")
md.append("\n---\n")
# ๊ฐ ์น์
for section in content_data['sections']:
md.append(f"\n## {section['title']}\n")
md.append(f"{section['content']}\n")
# SEO ์ ์
md.append("\n---\n")
md.append("\n## SEO ์ต์ ํ ์ ์\n")
md.append(f"{content_data['seo']}\n")
return '\n'.join(md)
def _slugify(self, text):
"""
ํ
์คํธ๋ฅผ ํ์ผ๋ช
์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ ํํ๋ก ๋ณํ
"""
# ๊ฐ๋จํ ๊ตฌํ (์ค์ ๋ก๋ ๋ ์ ๊ตํ ์ฒ๋ฆฌ ํ์)
import re
text = text.lower()
text = re.sub(r'[^\w\s-]', '', text)
text = re.sub(r'[-\s]+', '_', text)
return text[:50] # ๊ธธ์ด ์ ํ
๐ Step 5: ๋ฉ์ธ ์คํ ํ์ผ
๋ง์ง๋ง์ผ๋ก ๋ชจ๋ ๊ฒ์ ํตํฉํ๋ main.py๋ฅผ ๋ง๋ค์ด๋ณด์:
import logging
import sys
from config import Config
from modules.content_generator import ContentGenerator
from modules.storage import ContentStorage
def setup_logging():
"""
๋ก๊น
์ค์
"""
logging.basicConfig(
level=getattr(logging, Config.LOG_LEVEL),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(Config.LOG_FILE, encoding='utf-8'),
logging.StreamHandler(sys.stdout)
]
)
def main():
# ๋ก๊น
์ค์
setup_logging()
logger = logging.getLogger(__name__)
logger.info("=" * 50)
logger.info("๋ธ๋ก๊ทธ ์ฝํ
์ธ ์๋ ์์ฑ ์์คํ
์์")
logger.info("=" * 50)
# ์ฃผ์ ์
๋ ฅ
topic = input("\n๋ธ๋ก๊ทธ ์ฃผ์ ๋ฅผ ์
๋ ฅํ์ธ์: ").strip()
if not topic:
logger.error("์ฃผ์ ๊ฐ ์
๋ ฅ๋์ง ์์์ต๋๋ค.")
return
try:
# ์ฝํ
์ธ ์์ฑ
generator = ContentGenerator()
content = generator.generate_blog_post(topic)
# ์ ์ฅ
storage = ContentStorage()
paths = storage.save_blog_post(content)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
print("\n" + "=" * 50)
print("โ
๋ธ๋ก๊ทธ ๊ธ ์์ฑ ์๋ฃ!")
print("=" * 50)
print(f"\n๐ JSON ํ์ผ: {paths['json_path']}")
print(f"๐ Markdown ํ์ผ: {paths['markdown_path']}")
print(f"\n๐ฐ ์ฌ์ฉ ํ ํฐ: {content['metadata']['total_tokens']}")
print(f"๐ต ์์ ๋น์ฉ: ${content['metadata']['estimated_cost']:.4f}")
print("\n" + "=" * 50)
except Exception as e:
logger.error(f"์๋ฌ ๋ฐ์: {str(e)}", exc_info=True)
print(f"\nโ ์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}")
if __name__ == "__main__":
main()
โ ์ฃผ์ ๋ฅผ ์ ๋ ฅ๋ฐ์ ์๋์ผ๋ก ์์๋ผ์ธ ์์ฑ
โ ๊ฐ ์น์ ์ ๋ด์ฉ์ ์๋์ผ๋ก ์์ฑ
โ SEO ์ต์ ํ ์ ์ ์ ๊ณต
โ ๊ฒฐ๊ณผ๋ฅผ JSON๊ณผ Markdown ํ์์ผ๋ก ์ ์ฅ
โ ํ ํฐ ์ฌ์ฉ๋๊ณผ ๋น์ฉ ์ถ์
โ ์๋ฌ ์ฒ๋ฆฌ ๋ฐ ๋ก๊น
์ด ์ฝ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ ๋ง์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ด! ๐
โก ๊ณ ๊ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
๊ธฐ๋ณธ์ ์ธ ์๋ํ ์์คํ ์ ๋ง๋ค์์ผ๋, ์ด์ ๋ ๊ฐ๋ ฅํ๊ณ ์ค์ฉ์ ์ธ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค์ ์ถ๊ฐํด๋ณด์! ์ด๋ฐ ๊ธฐ๋ฅ๋ค์ด ์์ผ๋ฉด ์์คํ ์ ํจ์จ์ฑ๊ณผ ์ ๋ขฐ์ฑ์ด ํฌ๊ฒ ํฅ์๋ผ. ๐
๐ ์คํธ๋ฆฌ๋ฐ ์๋ต ์ฒ๋ฆฌ
ChatGPT API๋ ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์๋ต์ ๋ฐ์ ์ ์์ด. ์ด๋ ๊ฒ ํ๋ฉด ์ ์ฒด ์๋ต์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์์ฑ๋๋ ๋๋ก ์ค์๊ฐ์ผ๋ก ๋ฐ์๋ณผ ์ ์์ง! ํนํ ๊ธด ์ฝํ ์ธ ๋ฅผ ์์ฑํ ๋ ์ ์ฉํด. ์ฌ์ฉ์ ๊ฒฝํ๋ ํจ์ฌ ์ข์์ง๊ณ ! ๐ก
def chat_completion_stream(self, messages, temperature=None, max_tokens=None):
"""
์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์๋ต ๋ฐ๊ธฐ
"""
temperature = temperature or Config.TEMPERATURE
max_tokens = max_tokens or Config.MAX_TOKENS
try:
response = openai.ChatCompletion.create(
model=self.model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
stream=True # ์คํธ๋ฆฌ๋ฐ ํ์ฑํ
)
full_content = ""
for chunk in response:
if chunk.choices[0].delta.get("content"):
content = chunk.choices[0].delta.content
full_content += content
# ์ค์๊ฐ์ผ๋ก ์ถ๋ ฅํ๊ฑฐ๋ ์ฒ๋ฆฌ
print(content, end='', flush=True)
print() # ์ค๋ฐ๊ฟ
return full_content
except Exception as e:
self.logger.error(f"์คํธ๋ฆฌ๋ฐ ์๋ฌ: {str(e)}")
raise
๐ฏ ์ปจํ ์คํธ ๊ด๋ฆฌ ๋ฐ ๋ํ ์ด๋ ฅ
์ฌ๋ฌ ๋ฒ์ API ํธ์ถ์ ํตํด ๋ํ๋ฅผ ์ด์ด๊ฐ๋ ค๋ฉด ์ปจํ ์คํธ๋ฅผ ๊ด๋ฆฌํด์ผ ํด. ์ด์ ๋ํ ๋ด์ฉ์ ๊ธฐ์ตํ๊ณ ์์ด์ผ ์์ฐ์ค๋ฌ์ด ๋ํ๊ฐ ๊ฐ๋ฅํ๊ฑฐ๋ ! ๐ง
class ConversationManager:
def __init__(self, max_history=10):
self.messages = []
self.max_history = max_history
self.client = ChatGPTClient()
def add_system_message(self, content):
"""
์์คํ
๋ฉ์์ง ์ถ๊ฐ
"""
self.messages.append({
"role": "system",
"content": content
})
def add_user_message(self, content):
"""
์ฌ์ฉ์ ๋ฉ์์ง ์ถ๊ฐ
"""
self.messages.append({
"role": "user",
"content": content
})
def get_response(self):
"""
์๋ต ๋ฐ๊ธฐ ๋ฐ ๋ํ ์ด๋ ฅ์ ์ถ๊ฐ
"""
# ์ด๋ ฅ์ด ๋๋ฌด ๊ธธ๋ฉด ์ค๋๋ ๊ฒ๋ถํฐ ์ ๊ฑฐ (์์คํ
๋ฉ์์ง๋ ์ ์ง)
if len(self.messages) > self.max_history:
system_messages = [m for m in self.messages if m["role"] == "system"]
other_messages = [m for m in self.messages if m["role"] != "system"]
self.messages = system_messages + other_messages[-(self.max_history-len(system_messages)):]
response = self.client.chat_completion(self.messages)
# AI ์๋ต์ ์ด๋ ฅ์ ์ถ๊ฐ
self.messages.append({
"role": "assistant",
"content": response['content']
})
return response['content']
def clear_history(self):
"""
๋ํ ์ด๋ ฅ ์ด๊ธฐํ
"""
self.messages = []
def get_conversation_summary(self):
"""
๋ํ ์์ฝ ์์ฑ
"""
if not self.messages:
return "๋ํ ์ด๋ ฅ์ด ์์ต๋๋ค."
conversation_text = "\n".join([
f"{m['role']}: {m['content'][:100]}..."
for m in self.messages
])
summary_messages = [
{"role": "system", "content": "๋ค์ ๋ํ๋ฅผ ๊ฐ๋จํ ์์ฝํด์ฃผ์ธ์."},
{"role": "user", "content": conversation_text}
]
response = self.client.chat_completion(summary_messages, max_tokens=200)
return response['content']
๐ ๋ฐฐ์น ์ฒ๋ฆฌ ์์คํ
์ฌ๋ฌ ์์ ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ฐฐ์น ์์คํ ์ ๋ง๋ค์ด๋ณด์. ์ด๋ ๊ฒ ํ๋ฉด ๋๋์ ์ฝํ ์ธ ๋ฅผ ํ ๋ฒ์ ์์ฑํ ์ ์์ด! ๐
import concurrent.futures
from queue import Queue
import threading
import time
class BatchProcessor:
def __init__(self, max_workers=3, rate_limit=20):
"""
max_workers: ๋์ ์ฒ๋ฆฌ ์์
์
rate_limit: ๋ถ๋น ์ต๋ ์์ฒญ ์
"""
self.max_workers = max_workers
self.rate_limit = rate_limit
self.request_times = Queue()
self.lock = threading.Lock()
self.generator = ContentGenerator()
self.storage = ContentStorage()
self.logger = logging.getLogger(__name__)
def _check_rate_limit(self):
"""
Rate limit ์ฒดํฌ ๋ฐ ๋๊ธฐ
"""
with self.lock:
now = time.time()
# 1๋ถ ์ด์ ์ ์์ฒญ ๊ธฐ๋ก ์ ๊ฑฐ
while not self.request_times.empty():
if now - self.request_times.queue[0] > 60:
self.request_times.get()
else:
break
# Rate limit ์ด๊ณผ ์ ๋๊ธฐ
if self.request_times.qsize() >= self.rate_limit:
oldest_request = self.request_times.queue[0]
wait_time = 60 - (now - oldest_request)
if wait_time > 0:
self.logger.info(f"Rate limit ๋๋ฌ. {wait_time:.1f}์ด ๋๊ธฐ...")
time.sleep(wait_time)
# ํ์ฌ ์์ฒญ ์๊ฐ ๊ธฐ๋ก
self.request_times.put(now)
def process_single_topic(self, topic):
"""
๋จ์ผ ์ฃผ์ ์ฒ๋ฆฌ
"""
try:
self._check_rate_limit()
self.logger.info(f"์ฒ๋ฆฌ ์์: {topic}")
content = self.generator.generate_blog_post(topic)
paths = self.storage.save_blog_post(content)
return {
'topic': topic,
'status': 'success',
'paths': paths,
'tokens': content['metadata']['total_tokens'],
'cost': content['metadata']['estimated_cost']
}
except Exception as e:
self.logger.error(f"์ฒ๋ฆฌ ์คํจ: {topic} - {str(e)}")
return {
'topic': topic,
'status': 'failed',
'error': str(e)
}
def process_batch(self, topics):
"""
์ฌ๋ฌ ์ฃผ์ ๋ฅผ ๋ฐฐ์น๋ก ์ฒ๋ฆฌ
"""
self.logger.info(f"๋ฐฐ์น ์ฒ๋ฆฌ ์์: {len(topics)}๊ฐ ์ฃผ์ ")
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
# ๋ชจ๋ ์์
์ ์ถ
future_to_topic = {
executor.submit(self.process_single_topic, topic): topic
for topic in topics
}
# ์๋ฃ๋ ์์
์์ง
for future in concurrent.futures.as_completed(future_to_topic):
result = future.result()
results.append(result)
# ์งํ ์ํฉ ์ถ๋ ฅ
completed = len(results)
total = len(topics)
self.logger.info(f"์งํ๋ฅ : {completed}/{total} ({completed/total*100:.1f}%)")
# ๊ฒฐ๊ณผ ์์ฝ
successful = sum(1 for r in results if r['status'] == 'success')
failed = sum(1 for r in results if r['status'] == 'failed')
total_tokens = sum(r.get('tokens', 0) for r in results)
total_cost = sum(r.get('cost', 0) for r in results)
summary = {
'total': len(topics),
'successful': successful,
'failed': failed,
'total_tokens': total_tokens,
'total_cost': total_cost,
'results': results
}
self.logger.info(f"๋ฐฐ์น ์ฒ๋ฆฌ ์๋ฃ: ์ฑ๊ณต {successful}, ์คํจ {failed}")
return summary
๐พ ์บ์ฑ ์์คํ
๊ฐ์ ์์ฒญ์ ๋ํด ๋งค๋ฒ API๋ฅผ ํธ์ถํ๋ ๊ฑด ๋นํจ์จ์ ์ด์ผ. ์บ์ฑ์ ๊ตฌํํด์ ๋น์ฉ์ ์ ๊ฐํด๋ณด์! ๐ฐ
import hashlib
import json
import os
from datetime import datetime, timedelta
class ResponseCache:
def __init__(self, cache_dir="cache", ttl_hours=24):
"""
cache_dir: ์บ์ ์ ์ฅ ๋๋ ํ ๋ฆฌ
ttl_hours: ์บ์ ์ ํจ ์๊ฐ (์๊ฐ)
"""
self.cache_dir = cache_dir
self.ttl = timedelta(hours=ttl_hours)
self.logger = logging.getLogger(__name__)
os.makedirs(cache_dir, exist_ok=True)
def _get_cache_key(self, messages, temperature, max_tokens):
"""
์์ฒญ ํ๋ผ๋ฏธํฐ๋ก๋ถํฐ ์บ์ ํค ์์ฑ
"""
# ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฌธ์์ด๋ก ๋ณํ
key_string = json.dumps({
'messages': messages,
'temperature': temperature,
'max_tokens': max_tokens
}, sort_keys=True)
# SHA256 ํด์ ์์ฑ
return hashlib.sha256(key_string.encode()).hexdigest()
def _get_cache_path(self, cache_key):
"""
์บ์ ํ์ผ ๊ฒฝ๋ก ๋ฐํ
"""
return os.path.join(self.cache_dir, f"{cache_key}.json")
def get(self, messages, temperature, max_tokens):
"""
์บ์์์ ์๋ต ๊ฐ์ ธ์ค๊ธฐ
"""
cache_key = self._get_cache_key(messages, temperature, max_tokens)
cache_path = self._get_cache_path(cache_key)
if not os.path.exists(cache_path):
return None
try:
with open(cache_path, 'r', encoding='utf-8') as f:
cache_data = json.load(f)
# ์บ์ ์ ํจ์ฑ ํ์ธ
cached_time = datetime.fromisoformat(cache_data['timestamp'])
if datetime.now() - cached_time > self.ttl:
self.logger.info(f"์บ์ ๋ง๋ฃ: {cache_key[:8]}...")
os.remove(cache_path)
return None
self.logger.info(f"์บ์ ํํธ: {cache_key[:8]}...")
return cache_data['response']
except Exception as e:
self.logger.error(f"์บ์ ์ฝ๊ธฐ ์๋ฌ: {str(e)}")
return None
def set(self, messages, temperature, max_tokens, response):
"""
์๋ต์ ์บ์์ ์ ์ฅ
"""
cache_key = self._get_cache_key(messages, temperature, max_tokens)
cache_path = self._get_cache_path(cache_key)
try:
cache_data = {
'timestamp': datetime.now().isoformat(),
'response': response
}
with open(cache_path, 'w', encoding='utf-8') as f:
json.dump(cache_data, f, ensure_ascii=False, indent=2)
self.logger.info(f"์บ์ ์ ์ฅ: {cache_key[:8]}...")
except Exception as e:
self.logger.error(f"์บ์ ์ ์ฅ ์๋ฌ: {str(e)}")
def clear_expired(self):
"""
๋ง๋ฃ๋ ์บ์ ํ์ผ ์ญ์
"""
count = 0
for filename in os.listdir(self.cache_dir):
if not filename.endswith('.json'):
continue
filepath = os.path.join(self.cache_dir, filename)
try:
with open(filepath, 'r', encoding='utf-8') as f:
cache_data = json.load(f)
cached_time = datetime.fromisoformat(cache_data['timestamp'])
if datetime.now() - cached_time > self.ttl:
os.remove(filepath)
count += 1
except Exception:
continue
self.logger.info(f"๋ง๋ฃ๋ ์บ์ {count}๊ฐ ์ญ์ ")
return count
์ด์ API ํด๋ผ์ด์ธํธ์ ์บ์ฑ์ ํตํฉํด๋ณด์:
class ChatGPTClient:
def __init__(self, use_cache=True):
openai.api_key = Config.OPENAI_API_KEY
self.model = Config.MODEL
self.logger = logging.getLogger(__name__)
self.total_tokens_used = 0
# ์บ์ ์ด๊ธฐํ
self.use_cache = use_cache
if use_cache:
self.cache = ResponseCache()
def chat_completion(self, messages, temperature=None, max_tokens=None):
"""
ChatGPT API ํธ์ถ (์บ์ฑ ํฌํจ)
"""
temperature = temperature or Config.TEMPERATURE
max_tokens = max_tokens or Config.MAX_TOKENS
# ์บ์ ํ์ธ
if self.use_cache:
cached_response = self.cache.get(messages, temperature, max_tokens)
if cached_response:
self.logger.info("์บ์๋ ์๋ต ์ฌ์ฉ (API ํธ์ถ ์์)")
return cached_response
# ์บ์ ๋ฏธ์ค - API ํธ์ถ
for attempt in range(Config.MAX_RETRIES):
try:
response = openai.ChatCompletion.create(
model=self.model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens
)
tokens_used = response.usage.total_tokens
self.total_tokens_used += tokens_used
result = {
'content': response.choices[0].message.content,
'tokens': tokens_used,
'model': response.model
}
# ์บ์์ ์ ์ฅ
if self.use_cache:
self.cache.set(messages, temperature, max_tokens, result)
self.logger.info(f"API ํธ์ถ ์ฑ๊ณต. ์ฌ์ฉ ํ ํฐ: {tokens_used}")
return result
except Exception as e:
# ์๋ฌ ์ฒ๋ฆฌ (์ด์ ๊ณผ ๋์ผ)
...
- ์๊ฐ์ ๋ฏผ๊ฐํ ์ ๋ณด๋ ์บ์ฑํ์ง ์๊ธฐ
- ์ ๊ธฐ์ ์ผ๋ก ์บ์ ํฌ๊ธฐ ๋ชจ๋ํฐ๋ง
- ์บ์ ํํธ์จ์ ์ถ์ ํด์ ํจ๊ณผ ์ธก์
์ ์ค๊ณ๋ ์บ์ฑ ์์คํ ์ API ๋น์ฉ์ 30-50% ์ด์ ์ ๊ฐํ ์ ์์ด! ๐ฐ
๐ ๋ชจ๋ํฐ๋ง ๋ฐ ๋ถ์
์์คํ ์ ์ฑ๋ฅ๊ณผ ๋น์ฉ์ ์ถ์ ํ๋ ๋ชจ๋ํฐ๋ง ์์คํ ์ ๋ง๋ค์ด๋ณด์:
import sqlite3
from datetime import datetime
import pandas as pd
class SystemMonitor:
def __init__(self, db_path="monitoring.db"):
self.db_path = db_path
self.logger = logging.getLogger(__name__)
self._init_database()
def _init_database(self):
"""
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ
"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS api_calls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
model TEXT NOT NULL,
tokens_used INTEGER NOT NULL,
cost REAL NOT NULL,
success BOOLEAN NOT NULL,
error_message TEXT,
response_time REAL
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS content_generation (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
topic TEXT NOT NULL,
total_tokens INTEGER NOT NULL,
total_cost REAL NOT NULL,
sections_count INTEGER NOT NULL,
success BOOLEAN NOT NULL
)
''')
conn.commit()
conn.close()
def log_api_call(self, model, tokens_used, cost, success,
error_message=None, response_time=None):
"""
API ํธ์ถ ๊ธฐ๋ก
"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO api_calls
(timestamp, model, tokens_used, cost, success, error_message, response_time)
VALUES (?, ?, ?, ?, ?, ?, ?)
''', (
datetime.now().isoformat(),
model,
tokens_used,
cost,
success,
error_message,
response_time
))
conn.commit()
conn.close()
def log_content_generation(self, topic, total_tokens, total_cost,
sections_count, success):
"""
์ฝํ
์ธ ์์ฑ ๊ธฐ๋ก
"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO content_generation
(timestamp, topic, total_tokens, total_cost, sections_count, success)
VALUES (?, ?, ?, ?, ?, ?)
''', (
datetime.now().isoformat(),
topic,
total_tokens,
total_cost,
sections_count,
success
))
conn.commit()
conn.close()
def get_daily_stats(self, date=None):
"""
์ผ์ผ ํต๊ณ ์กฐํ
"""
if date is None:
date = datetime.now().date()
conn = sqlite3.connect(self.db_path)
# API ํธ์ถ ํต๊ณ
api_df = pd.read_sql_query(f'''
SELECT
COUNT(*) as total_calls,
SUM(tokens_used) as total_tokens,
SUM(cost) as total_cost,
AVG(response_time) as avg_response_time,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful_calls
FROM api_calls
WHERE DATE(timestamp) = '{date}'
''', conn)
# ์ฝํ
์ธ ์์ฑ ํต๊ณ
content_df = pd.read_sql_query(f'''
SELECT
COUNT(*) as total_generations,
SUM(total_tokens) as total_tokens,
SUM(total_cost) as total_cost,
AVG(sections_count) as avg_sections
FROM content_generation
WHERE DATE(timestamp) = '{date}'
''', conn)
conn.close()
return {
'date': str(date),
'api_stats': api_df.to_dict('records')[0],
'content_stats': content_df.to_dict('records')[0]
}
def get_cost_trend(self, days=7):
"""
๋น์ฉ ์ถ์ธ ๋ถ์
"""
conn = sqlite3.connect(self.db_path)
df = pd.read_sql_query(f'''
SELECT
DATE(timestamp) as date,
SUM(cost) as daily_cost,
SUM(tokens_used) as daily_tokens
FROM api_calls
WHERE timestamp >= datetime('now', '-{days} days')
GROUP BY DATE(timestamp)
ORDER BY date
''', conn)
conn.close()
return df.to_dict('records')
def generate_report(self):
"""
์ข
ํฉ ๋ฆฌํฌํธ ์์ฑ
"""
today_stats = self.get_daily_stats()
cost_trend = self.get_cost_trend()
report = f"""
===== ์์คํ
๋ชจ๋ํฐ๋ง ๋ฆฌํฌํธ =====
๐
๋ ์ง: {today_stats['date']}
๐ API ํธ์ถ ํต๊ณ:
- ์ด ํธ์ถ ์: {today_stats['api_stats']['total_calls']}
- ์ฑ๊ณต๋ฅ : {today_stats['api_stats']['successful_calls'] / today_stats['api_stats']['total_calls'] * 100:.1f}%
- ์ด ํ ํฐ: {today_stats['api_stats']['total_tokens']:,}
- ์ด ๋น์ฉ: ${today_stats['api_stats']['total_cost']:.4f}
- ํ๊ท ์๋ต ์๊ฐ: {today_stats['api_stats']['avg_response_time']:.2f}์ด
๐ ์ฝํ
์ธ ์์ฑ ํต๊ณ:
- ์์ฑ๋ ๊ธ: {today_stats['content_stats']['total_generations']}๊ฐ
- ํ๊ท ์น์
์: {today_stats['content_stats']['avg_sections']:.1f}
- ์ด ํ ํฐ: {today_stats['content_stats']['total_tokens']:,}
- ์ด ๋น์ฉ: ${today_stats['content_stats']['total_cost']:.4f}
๐ ์ต๊ทผ 7์ผ ๋น์ฉ ์ถ์ธ:
"""
for day in cost_trend:
report += f"\n {day['date']}: ${day['daily_cost']:.4f} ({day['daily_tokens']:,} ํ ํฐ)"
return report
๐ ํ๋กฌํํธ ์์ง๋์ด๋ง ๋ง์คํฐํ๊ธฐ
ChatGPT API๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด ํ๋กฌํํธ ์์ง๋์ด๋ง์ด ์ ๋ง ์ค์ํด! ๊ฐ์ ์ง๋ฌธ์ด๋ผ๋ ์ด๋ป๊ฒ ๋ฌผ์ด๋ณด๋๋์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ์ฒ์ฐจ๋ง๋ณ์ด๊ฑฐ๋ . ํ๋กฌํํธ ์์ง๋์ด๋ง์ ํต์ฌ ๊ธฐ๋ฒ๋ค์ ์์๋ณด์! ๐ฏ
โจ ํจ๊ณผ์ ์ธ ํ๋กฌํํธ ์์ฑ ์์น
๋ชจํธํ ์ง์๋ณด๋ค๋ ๊ตฌ์ฒด์ ์ธ ์ง์๊ฐ ํจ์ฌ ์ข์ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๋ด. ์๋ฅผ ๋ค์ด:
โ ๋์ ์: "๋ธ๋ก๊ทธ ๊ธ ์จ์ค"
โ ์ข์ ์: "์ด๋ณด์๋ฅผ ์ํ Python ํ๋ก๊ทธ๋๋ฐ ์ ๋ฌธ ๋ธ๋ก๊ทธ ๊ธ์ ์์ฑํด์ฃผ์ธ์. 1500๋จ์ด ๋ถ๋์ผ๋ก, ์ฝ๋ ์์ 3๊ฐ๋ฅผ ํฌํจํ๊ณ , ์น๊ทผํ ํค์ผ๋ก ์์ฑํด์ฃผ์ธ์."
AI์๊ฒ ํน์ ์ญํ ์ ๋ถ์ฌํ๋ฉด ๋ ์ ๋ฌธ์ ์ธ ๋ต๋ณ์ ์ป์ ์ ์์ด:
"๋น์ ์ 10๋ ๊ฒฝ๋ ฅ์ ์๋์ด ๊ฐ๋ฐ์์ ๋๋ค. ์ฃผ๋์ด ๊ฐ๋ฐ์์๊ฒ ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ํด์ฃผ๋ฏ์ด ๋ค์ ์ฝ๋๋ฅผ ๊ฒํ ํด์ฃผ์ธ์."
์ด๋ ๊ฒ ํ๋ฉด AI๊ฐ ํด๋น ์ญํ ์ ๊ด์ ์์ ๋ต๋ณํ๊ฒ ๋ผ! ๐ญ
๋ณต์กํ ๋ฌธ์ ๋ ๋จ๊ณ๋ณ๋ก ์๊ฐํ๋๋ก ์ ๋ํ๋ฉด ๋ ์ ํํ ๋ต์ ์ป์ ์ ์์ด:
"๋ค์ ๋ฌธ์ ๋ฅผ ๋จ๊ณ๋ณ๋ก ํ์ด์ฃผ์ธ์:
1. ๋จผ์ ๋ฌธ์ ๋ฅผ ๋ถ์ํ๊ณ
2. ๊ฐ๋ฅํ ํด๊ฒฐ ๋ฐฉ๋ฒ๋ค์ ๋์ดํ ํ
3. ๊ฐ ๋ฐฉ๋ฒ์ ์ฅ๋จ์ ์ ๋น๊ตํ๊ณ
4. ์ต์ ์ ํด๊ฒฐ์ฑ ์ ์ ์ํด์ฃผ์ธ์."
์ํ๋ ํ์์ ์์๋ฅผ ๋ณด์ฌ์ฃผ๋ฉด AI๊ฐ ๊ทธ ํจํด์ ๋ฐ๋ผํด:
"๋ค์ ํ์์ผ๋ก ์ ํ ์ค๋ช ์ ์์ฑํด์ฃผ์ธ์:
์์ 1:
์ ํ๋ช : ์ค๋งํธ ์์น
ํต์ฌ ๊ธฐ๋ฅ: ๊ฑด๊ฐ ๋ชจ๋ํฐ๋ง, ์๋ฆผ ์์
ํ๊ฒ: ๊ฑด๊ฐ์ ๊ด์ฌ ์๋ 20-40๋
์ด์ ๋ค์ ์ ํ์ ๋ํด ๊ฐ์ ํ์์ผ๋ก ์์ฑํด์ฃผ์ธ์: [์ ํ ์ ๋ณด]"
๐ง ๊ณ ๊ธ ํ๋กฌํํธ ๊ธฐ๋ฒ
์ด์ ์ข ๋ ๊ณ ๊ธ ๊ธฐ๋ฒ๋ค์ ์ดํด๋ณด์. ์ด๋ฐ ๊ธฐ๋ฒ๋ค์ ์ฌ์ฉํ๋ฉด AI์ ์ฑ๋ฅ์ ๊ทน๋ํํ ์ ์์ด! ๐
class AdvancedPromptBuilder:
"""
๊ณ ๊ธ ํ๋กฌํํธ ์์ฑ ๋๊ตฌ
"""
@staticmethod
def create_structured_prompt(task, context, constraints, output_format):
"""
๊ตฌ์กฐํ๋ ํ๋กฌํํธ ์์ฑ
"""
prompt = f"""
์์
: {task}
๋ฐฐ๊ฒฝ ์ ๋ณด:
{context}
์ ์ฝ ์กฐ๊ฑด:
{constraints}
์ถ๋ ฅ ํ์:
{output_format}
์ ์๊ตฌ์ฌํญ์ ๋ชจ๋ ์ถฉ์กฑํ๋ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํด์ฃผ์ธ์.
"""
return prompt.strip()
@staticmethod
def create_iterative_refinement_prompt(initial_output, feedback):
"""
๋ฐ๋ณต์ ๊ฐ์ ์ ์ํ ํ๋กฌํํธ
"""
prompt = f"""
๋ค์์ ์ด์ ์ ์์ฑํ ๊ฒฐ๊ณผ์
๋๋ค:
{initial_output}
๋ค์ ํผ๋๋ฐฑ์ ๋ฐ์ํด์ ๊ฐ์ ํด์ฃผ์ธ์:
{feedback}
๊ฐ์ ๋ ๋ฒ์ ์ ์์ฑํด์ฃผ์ธ์.
"""
return prompt.strip()
@staticmethod
def create_self_consistency_prompt(question, num_approaches=3):
"""
์๊ธฐ ์ผ๊ด์ฑ ๊ฒ์ฆ์ ์ํ ํ๋กฌํํธ
"""
prompt = f"""
๋ค์ ์ง๋ฌธ์ ๋ํด {num_approaches}๊ฐ์ง ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ๋ต๋ณํด์ฃผ์ธ์:
์ง๋ฌธ: {question}
๊ฐ ์ ๊ทผ ๋ฐฉ์:
1. [์ฒซ ๋ฒ์งธ ๊ด์ ์์์ ๋ต๋ณ]
2. [๋ ๋ฒ์งธ ๊ด์ ์์์ ๋ต๋ณ]
3. [์ธ ๋ฒ์งธ ๊ด์ ์์์ ๋ต๋ณ]
๋ง์ง๋ง์ผ๋ก, ์ธ ๋ต๋ณ์ ์ข
ํฉํด์ ๊ฐ์ฅ ์ ํํ ์ต์ข
๋ต๋ณ์ ์ ์ํด์ฃผ์ธ์.
"""
return prompt.strip()
@staticmethod
def create_critique_and_revise_prompt(content):
"""
๋นํ ํ ์์ ํ๋กฌํํธ
"""
prompt = f"""
๋ค์ ์ฝํ
์ธ ๋ฅผ ๋นํ์ ์ผ๋ก ๊ฒํ ํด์ฃผ์ธ์:
{content}
๊ฒํ ํญ๋ชฉ:
1. ๋
ผ๋ฆฌ์ ์ค๋ฅ๋ ๋ชจ์์ด ์๋๊ฐ?
2. ์ ๋ณด๊ฐ ์ ํํ๊ณ ์ต์ ์ธ๊ฐ?
3. ํํ์ด ๋ช
ํํ๊ณ ์ดํดํ๊ธฐ ์ฌ์ด๊ฐ?
4. ๊ฐ์ ์ด ํ์ํ ๋ถ๋ถ์ ๋ฌด์์ธ๊ฐ?
๋นํ์ ๋ฐํ์ผ๋ก ๊ฐ์ ๋ ๋ฒ์ ์ ์์ฑํด์ฃผ์ธ์.
"""
return prompt.strip()
๐ ํ๋กฌํํธ ์ต์ ํ ์ ๋ต
ํ๋กฌํํธ๋ฅผ ์ต์ ํํ๋ ์ฒด๊ณ์ ์ธ ๋ฐฉ๋ฒ์ ์์๋ณด์:
class PromptOptimizer:
def __init__(self):
self.client = ChatGPTClient()
self.test_results = []
def test_prompt_variations(self, base_prompt, variations, test_input):
"""
์ฌ๋ฌ ํ๋กฌํํธ ๋ณํ์ ํ
์คํธํ๊ณ ๋น๊ต
"""
results = []
for i, variation in enumerate(variations):
print(f"\nํ
์คํธ {i+1}/{len(variations)}: {variation['name']}")
# ํ๋กฌํํธ ์์ฑ
if 'modifier' in variation:
prompt = variation['modifier'](base_prompt)
else:
prompt = base_prompt
messages = [
{"role": "system", "content": prompt},
{"role": "user", "content": test_input}
]
# API ํธ์ถ
start_time = time.time()
response = self.client.chat_completion(messages)
end_time = time.time()
result = {
'name': variation['name'],
'response': response['content'],
'tokens': response['tokens'],
'time': end_time - start_time,
'cost': response['tokens'] * 0.002 / 1000 # ๋๋ต์ ์ธ ๋น์ฉ
}
results.append(result)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
print(f" ํ ํฐ: {result['tokens']}")
print(f" ์๊ฐ: {result['time']:.2f}์ด")
print(f" ๋น์ฉ: ${result['cost']:.4f}")
print(f" ์๋ต ๊ธธ์ด: {len(result['response'])} ๋ฌธ์")
return results
def compare_results(self, results):
"""
ํ
์คํธ ๊ฒฐ๊ณผ ๋น๊ต ๋ถ์
"""
print("\n" + "="*50)
print("๊ฒฐ๊ณผ ๋น๊ต")
print("="*50)
for result in results:
print(f"\n{result['name']}:")
print(f" ํจ์จ์ฑ: {result['tokens']/len(result['response']):.2f} ํ ํฐ/๋ฌธ์")
print(f" ์๋: {result['time']:.2f}์ด")
print(f" ๋น์ฉ: ${result['cost']:.4f}")
# ์ต์ ์ ํ๋กฌํํธ ์ถ์ฒ
best_efficiency = min(results, key=lambda x: x['tokens']/len(x['response']))
best_speed = min(results, key=lambda x: x['time'])
best_cost = min(results, key=lambda x: x['cost'])
print("\n์ถ์ฒ:")
print(f" ํจ์จ์ฑ ์ต๊ณ : {best_efficiency['name']}")
print(f" ์๋ ์ต๊ณ : {best_speed['name']}")
print(f" ๋น์ฉ ์ต์ : {best_cost['name']}")
# ์ฌ์ฉ ์์
optimizer = PromptOptimizer()
base_prompt = "๋ธ๋ก๊ทธ ๊ธ์ ์์ฑํด์ฃผ์ธ์."
variations = [
{
'name': '๊ธฐ๋ณธ',
'modifier': lambda p: p
},
{
'name': '๊ตฌ์ฒด์ ์ง์',
'modifier': lambda p: f"{p} 1000๋จ์ด ๋ถ๋์ผ๋ก, 3๊ฐ์ ์น์
์ผ๋ก ๊ตฌ์ฑํ๊ณ , ๊ฐ ์น์
์ ์์๋ฅผ ํฌํจํด์ฃผ์ธ์."
},
{
'name': '์ญํ ๋ถ์ฌ',
'modifier': lambda p: f"๋น์ ์ ์ ๋ฌธ ๋ธ๋ก๊ฑฐ์
๋๋ค. {p}"
},
{
'name': '๊ตฌ์กฐํ',
'modifier': lambda p: f"""
{p}
๋ค์ ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ผ์ฃผ์ธ์:
1. ๋์
๋ถ (๋ฌธ์ ์ ๊ธฐ)
2. ๋ณธ๋ก (ํด๊ฒฐ ๋ฐฉ๋ฒ)
3. ๊ฒฐ๋ก (์์ฝ ๋ฐ ํ๋ ์ด๊ตฌ)
"""
}
]
test_input = "Python ์ด๋ณด์๋ฅผ ์ํ ๊ฐ์ด๋"
results = optimizer.test_prompt_variations(base_prompt, variations, test_input)
optimizer.compare_results(results)
โ ์ ์ ํ ์ญํ ๊ณผ ์ปจํ ์คํธ ์ ๊ณต
โ ์ํ๋ ์ถ๋ ฅ ํ์ ๊ตฌ์ฒดํ
โ ์์ ์ ๊ณต (ํ์์)
โ ๋จ๊ณ๋ณ ์ฌ๊ณ ์ ๋ (๋ณต์กํ ์์ )
โ ํ ํฐ ์ฌ์ฉ๋ ์ต์ ํ
โ A/B ํ ์คํธ๋ก ํจ๊ณผ ๊ฒ์ฆ
์ข์ ํ๋กฌํํธ๋ API ๋น์ฉ์ ์ ๊ฐํ๋ฉด์๋ ๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๋ด! ๐ฏ
๐ ๋ณด์ ๋ฐ ์๋ฌ ์ฒ๋ฆฌ
์๋ํ ์์คํ ์ ์ด์ํ ๋ ๋ณด์๊ณผ ์๋ฌ ์ฒ๋ฆฌ๋ ์ ๋ง ์ค์ํด! ์ค์ ํ๋ก๋์ ํ๊ฒฝ์์๋ ์์์น ๋ชปํ ์ผ๋ค์ด ๋ง์ด ๋ฐ์ํ๊ฑฐ๋ . ์ด๋ฐ ์ํฉ๋ค์ ์ ๋๋นํด์ผ ์์ ์ ์ธ ์์คํ ์ ๋ง๋ค ์ ์์ด. ๐ก๏ธ
๐จ ํฌ๊ด์ ์ธ ์๋ฌ ์ฒ๋ฆฌ
class RobustAPIClient:
"""
๊ฐ๋ ฅํ ์๋ฌ ์ฒ๋ฆฌ๊ฐ ํฌํจ๋ API ํด๋ผ์ด์ธํธ
"""
def __init__(self):
self.client = ChatGPTClient()
self.logger = logging.getLogger(__name__)
self.error_counts = {}
def safe_api_call(self, messages, max_retries=3, fallback_response=None):
"""
์์ ํ API ํธ์ถ (ํฌ๊ด์ ์๋ฌ ์ฒ๋ฆฌ)
"""
for attempt in range(max_retries):
try:
response = self.client.chat_completion(messages)
return {'success': True, 'data': response}
except openai.error.RateLimitError as e:
self.logger.warning(f"Rate limit ์๋ฌ (์๋ {attempt+1}/{max_retries})")
self._log_error('rate_limit')
if attempt < max_retries - 1:
# ์ง์ ๋ฐฑ์คํ (exponential backoff)
wait_time = (2 ** attempt) * 2
self.logger.info(f"{wait_time}์ด ๋๊ธฐ ํ ์ฌ์๋...")
time.sleep(wait_time)
else:
return self._create_error_response('rate_limit_exceeded', fallback_response)
except openai.error.InvalidRequestError as e:
self.logger.error(f"์๋ชป๋ ์์ฒญ: {str(e)}")
self._log_error('invalid_request')
# ์ฌ์๋ํด๋ ์์ฉ์์ผ๋ฏ๋ก ์ฆ์ ๋ฐํ
return self._create_error_response('invalid_request', fallback_response)
except openai.error.AuthenticationError as e:
self.logger.error(f"์ธ์ฆ ์๋ฌ: {str(e)}")
self._log_error('authentication')
# ์น๋ช
์ ์๋ฌ - ์ฆ์ ๋ฐํ
return self._create_error_response('authentication_failed', fallback_response)
except openai.error.APIError as e:
self.logger.error(f"API ์๋ฌ: {str(e)}")
self._log_error('api_error')
if attempt < max_retries - 1:
time.sleep(5)
else:
return self._create_error_response('api_error', fallback_response)
except openai.error.Timeout as e:
self.logger.warning(f"ํ์์์ (์๋ {attempt+1}/{max_retries})")
self._log_error('timeout')
if attempt < max_retries - 1:
time.sleep(3)
else:
return self._create_error_response('timeout', fallback_response)
except Exception as e:
self.logger.error(f"์์์น ๋ชปํ ์๋ฌ: {str(e)}", exc_info=True)
self._log_error('unknown')
if attempt < max_retries - 1:
time.sleep(2)
else:
return self._create_error_response('unknown_error', fallback_response)
return self._create_error_response('max_retries_exceeded', fallback_response)
def _create_error_response(self, error_type, fallback_response):
"""
์๋ฌ ์๋ต ์์ฑ
"""
response = {
'success': False,
'error_type': error_type,
'timestamp': datetime.now().isoformat()
}
if fallback_response:
response['data'] = fallback_response
response['is_fallback'] = True
return response
def _log_error(self, error_type):
"""
์๋ฌ ๋ฐ์ ํ์ ์ถ์
"""
self.error_counts[error_type] = self.error_counts.get(error_type, 0) + 1
def get_error_statistics(self):
"""
์๋ฌ ํต๊ณ ์กฐํ
"""
total_errors = sum(self.error_counts.values())
stats = {
'total_errors': total_errors,
'error_breakdown': self.error_counts.copy()
}
if total_errors > 0:
stats['error_rates'] = {
error_type: count / total_errors * 100
for error_type, count in self.error_counts.items()
}
return stats
๐ API ํค ๋ณด์ ๊ด๋ฆฌ
import os
import json
from cryptography.fernet import Fernet
class SecureKeyManager:
"""
์์ ํ API ํค ๊ด๋ฆฌ ์์คํ
"""
def __init__(self, key_file=".keys.enc"):
self.key_file = key_file
self.encryption_key = self._get_or_create_encryption_key()
self.cipher = Fernet(self.encryption_key)
def _get_or_create_encryption_key(self):
"""
์ํธํ ํค ๊ฐ์ ธ์ค๊ธฐ ๋๋ ์์ฑ
"""
key_path = ".encryption_key"
if os.path.exists(key_path):
with open(key_path, 'rb') as f:
return f.read()
else:
key = Fernet.generate_key()
with open(key_path, 'wb') as f:
f.write(key)
# ํ์ผ ๊ถํ ์ค์ (Unix ๊ณ์ด)
if os.name != 'nt': # Windows๊ฐ ์๋ ๊ฒฝ์ฐ
os.chmod(key_path, 0o600)
return key
def store_api_key(self, service_name, api_key):
"""
API ํค๋ฅผ ์ํธํํด์ ์ ์ฅ
"""
# ๊ธฐ์กด ํค ๋ก๋
keys = self._load_keys()
# ์ ํค ์ถ๊ฐ
keys[service_name] = api_key
# ์ํธํํด์ ์ ์ฅ
encrypted_data = self.cipher.encrypt(json.dumps(keys).encode())
with open(self.key_file, 'wb') as f:
f.write(encrypted_data)
# ํ์ผ ๊ถํ ์ค์
if os.name != 'nt':
os.chmod(self.key_file, 0o600)
print(f"โ
{service_name} API ํค๊ฐ ์์ ํ๊ฒ ์ ์ฅ๋์์ต๋๋ค.")
def get_api_key(self, service_name):
"""
์ ์ฅ๋ API ํค ๊ฐ์ ธ์ค๊ธฐ
"""
keys = self._load_keys()
if service_name not in keys:
raise ValueError(f"{service_name} API ํค๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.")
return keys[service_name]
def _load_keys(self):
"""
์ํธํ๋ ํค ํ์ผ ๋ก๋
"""
if not os.path.exists(self.key_file):
return {}
try:
with open(self.key_file, 'rb') as f:
encrypted_data = f.read()
decrypted_data = self.cipher.decrypt(encrypted_data)
return json.loads(decrypted_data.decode())
except Exception as e:
print(f"โ ๏ธ ํค ํ์ผ ๋ก๋ ์คํจ: {str(e)}")
return {}
def list_services(self):
"""
์ ์ฅ๋ ์๋น์ค ๋ชฉ๋ก ์กฐํ
"""
keys = self._load_keys()
return list(keys.keys())
def delete_api_key(self, service_name):
"""
API ํค ์ญ์
"""
keys = self._load_keys()
if service_name in keys:
del keys[service_name]
encrypted_data = self.cipher.encrypt(json.dumps(keys).encode())
with open(self.key_file, 'wb') as f:
f.write(encrypted_data)
print(f"โ
{service_name} API ํค๊ฐ ์ญ์ ๋์์ต๋๋ค.")
else:
print(f"โ ๏ธ {service_name} API ํค๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.")
# ์ฌ์ฉ ์์
key_manager = SecureKeyManager()
# API ํค ์ ์ฅ
key_manager.store_api_key("openai", "sk-...")
# API ํค ๊ฐ์ ธ์ค๊ธฐ
api_key = key_manager.get_api_key("openai")
# ์ ์ฅ๋ ์๋น์ค ๋ชฉ๋ก
services = key_manager.list_services()
print(f"์ ์ฅ๋ ์๋น์ค: {services}")
๐ก๏ธ ์ ๋ ฅ ๊ฒ์ฆ ๋ฐ ์๋ํ์ด์ ์ด์
์ฌ์ฉ์ ์ ๋ ฅ์ ๊ทธ๋๋ก API์ ์ ๋ฌํ๋ฉด ์ํํ ์ ์์ด. ์ ๋ ฅ์ ๊ฒ์ฆํ๊ณ ์ ์ ํ๋ ์์คํ ์ ๋ง๋ค์ด๋ณด์:
import re
from typing import Optional
class InputValidator:
"""
์
๋ ฅ ๊ฒ์ฆ ๋ฐ ์๋ํ์ด์ ์ด์
"""
# ๋ฏผ๊ฐํ ์ ๋ณด ํจํด
SENSITIVE_PATTERNS = {
'email': r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
'phone': r'\b\d{2,3}-\d{3,4}-\d{4}\b',
'ssn': r'\b\d{6}-\d{7}\b',
'credit_card': r'\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b',
'api_key': r'\b[A-Za-z0-9]{32,}\b'
}
def __init__(self, max_length=10000):
self.max_length = max_length
self.logger = logging.getLogger(__name__)
def validate_and_sanitize(self, text: str,
remove_sensitive=True,
remove_html=True) -> dict:
"""
์
๋ ฅ ๊ฒ์ฆ ๋ฐ ์๋ํ์ด์ ์ด์
"""
result = {
'is_valid': True,
'sanitized_text': text,
'warnings': [],
'removed_items': []
}
# ๊ธธ์ด ๊ฒ์ฆ
if len(text) > self.max_length:
result['is_valid'] = False
result['warnings'].append(f"์
๋ ฅ์ด ๋๋ฌด ๊น๋๋ค (์ต๋ {self.max_length}์)")
result['sanitized_text'] = text[:self.max_length]
# ๋ฏผ๊ฐํ ์ ๋ณด ์ ๊ฑฐ
if remove_sensitive:
for info_type, pattern in self.SENSITIVE_PATTERNS.items():
matches = re.findall(pattern, result['sanitized_text'])
if matches:
result['removed_items'].extend([
{'type': info_type, 'value': match}
for match in matches
])
result['sanitized_text'] = re.sub(
pattern,
f'[{info_type.upper()}_REMOVED]',
result['sanitized_text']
)
result['warnings'].append(f"{info_type} ์ ๋ณด๊ฐ ์ ๊ฑฐ๋์์ต๋๋ค")
# HTML ํ๊ทธ ์ ๊ฑฐ
if remove_html:
html_pattern = r'<[^>]+>'
if re.search(html_pattern, result['sanitized_text']):
result['sanitized_text'] = re.sub(html_pattern, '', result['sanitized_text'])
result['warnings'].append("HTML ํ๊ทธ๊ฐ ์ ๊ฑฐ๋์์ต๋๋ค")
# ์
์์ ์ธ ํจํด ๊ฒ์ฌ
malicious_patterns = [
r'<script',
r'javascript:',
r'onerror=',
r'onclick='
]
for pattern in malicious_patterns:
if re.search(pattern, result['sanitized_text'], re.IGNORECASE):
result['is_valid'] = False
result['warnings'].append("์ ์ฌ์ ์ผ๋ก ์ํํ ํจํด์ด ๊ฐ์ง๋์์ต๋๋ค")
break
# ๋ก๊น
if result['warnings']:
self.logger.warning(f"์
๋ ฅ ๊ฒ์ฆ ๊ฒฝ๊ณ : {', '.join(result['warnings'])}")
return result
def validate_prompt_injection(self, text: str) -> bool:
"""
ํ๋กฌํํธ ์ธ์ ์
๊ณต๊ฒฉ ๊ฐ์ง
"""
# ์์ฌ์ค๋ฌ์ด ํจํด๋ค
suspicious_patterns = [
r'ignore (previous|above) instructions',
r'disregard (previous|above)',
r'forget (everything|all)',
r'new instructions:',
r'system:',
r'override',
r'admin mode'
]
text_lower = text.lower()
for pattern in suspicious_patterns:
if re.search(pattern, text_lower):
self.logger.warning(f"ํ๋กฌํํธ ์ธ์ ์
์์ฌ: {pattern}")
return False
return True
def sanitize_for_api(self, text: str) -> str:
"""
API ์ ์ก์ ์ํ ํ
์คํธ ์ ์
"""
# ๊ฒ์ฆ ๋ฐ ์๋ํ์ด์ ์ด์
result = self.validate_and_sanitize(text)
if not result['is_valid']:
raise ValueError(f"์
๋ ฅ ๊ฒ์ฆ ์คํจ: {', '.join(result['warnings'])}")
# ํ๋กฌํํธ ์ธ์ ์
๊ฒ์ฌ
if not self.validate_prompt_injection(result['sanitized_text']):
raise ValueError("ํ๋กฌํํธ ์ธ์ ์
๊ณต๊ฒฉ์ด ๊ฐ์ง๋์์ต๋๋ค")
return result['sanitized_text']
# ์ฌ์ฉ ์์
validator = InputValidator()
user_input = """
์๋
ํ์ธ์! ์ ์ด๋ฉ์ผ์ user@example.com์ด๊ณ
์ ํ๋ฒํธ๋ 010-1234-5678์
๋๋ค.
<script>alert('xss')</script>
"""
result = validator.validate_and_sanitize(user_input)
print(f"๊ฒ์ฆ ๊ฒฐ๊ณผ: {result['is_valid']}")
print(f"์ ์ ๋ ํ
์คํธ: {result['sanitized_text']}")
print(f"๊ฒฝ๊ณ : {result['warnings']}")
โ ์ฌ์ฉ์ ์ ๋ ฅ์ ํญ์ ๊ฒ์ฆํ๊ณ ์๋ํ์ด์ฆ
โ ๋ฏผ๊ฐํ ์ ๋ณด๊ฐ API๋ก ์ ์ก๋์ง ์๋๋ก ํํฐ๋ง
โ Rate limiting ๊ตฌํ์ผ๋ก ๊ณผ๋ํ ์ฌ์ฉ ๋ฐฉ์ง
โ ์๋ฌ ๋ฉ์์ง์ ๋ฏผ๊ฐํ ์ ๋ณด ํฌํจ ๊ธ์ง
โ ์ ๊ธฐ์ ์ธ ๋ณด์ ๊ฐ์ฌ ๋ฐ ๋ก๊ทธ ๋ชจ๋ํฐ๋ง
โ HTTPS ์ฌ์ฉ ๋ฐ ํต์ ์ํธํ
โ ์ต์ ๊ถํ ์์น ์ ์ฉ
๋ณด์์ ํ ๋ฒ ์ค์ ํ๊ณ ๋๋๋ ๊ฒ ์๋๋ผ ์ง์์ ์ผ๋ก ๊ด๋ฆฌํด์ผ ํด! ๐
๐ฐ ๋น์ฉ ์ต์ ํ ์ ๋ต
ChatGPT API๋ ์ฌ์ฉํ ๋งํผ ๋น์ฉ์ ์ง๋ถํ๋ ์ข ๋์ ์ผ. ๋ฐ๋ผ์ ๋น์ฉ ์ต์ ํ๋ ์ ๋ง ์ค์ํ ์ฃผ์ ์ผ! ๋๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ๊ฐ์ ๊ธฐ๋ฅ์ ํจ์ฌ ์ ๋ ดํ๊ฒ ๊ตฌํํ ์ ์์ด. ๐ก
๐ ๋น์ฉ ๊ตฌ์กฐ ์ดํดํ๊ธฐ
| ๋ชจ๋ธ | ์ ๋ ฅ ๋น์ฉ (1K ํ ํฐ) | ์ถ๋ ฅ ๋น์ฉ (1K ํ ํฐ) | ํน์ง |
|---|---|---|---|
| GPT-4 | $0.03 | $0.06 | ์ต๊ณ ์ฑ๋ฅ, ๋ณต์กํ ์์ |
| GPT-3.5-turbo | $0.0015 | $0.002 | ๋น ๋ฅด๊ณ ์ ๋ ด, ์ผ๋ฐ ์์ |
| GPT-3.5-turbo-16k | $0.003 | $0.004 | ๊ธด ์ปจํ ์คํธ ์ฒ๋ฆฌ |
*๊ฐ๊ฒฉ์ ๋ณ๋๋ ์ ์์ผ๋ ๊ณต์ ๋ฌธ์๋ฅผ ํ์ธํ์ธ์!
๐ก ๋น์ฉ ์ ๊ฐ ๊ธฐ๋ฒ
class CostOptimizer:
"""
๋น์ฉ ์ต์ ํ ๋๊ตฌ
"""
def __init__(self):
self.logger = logging.getLogger(__name__)
self.cost_tracker = {
'gpt-4': {'input': 0.03, 'output': 0.06},
'gpt-3.5-turbo': {'input': 0.0015, 'output': 0.002}
}
def estimate_cost(self, text, model='gpt-3.5-turbo', is_input=True):
"""
ํ
์คํธ์ ์์ ๋น์ฉ ๊ณ์ฐ
"""
# ํ ํฐ ์ ์ถ์ (์ค์ ๋ก๋ tiktoken ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ๊ถ์ฅ)
estimated_tokens = len(text.split()) * 1.3 # ๋๋ต์ ์ธ ์ถ์
cost_per_token = self.cost_tracker[model]['input' if is_input else 'output']
estimated_cost = (estimated_tokens / 1000) * cost_per_token
return {
'estimated_tokens': int(estimated_tokens),
'estimated_cost': estimated_cost,
'model': model
}
def choose_optimal_model(self, task_complexity, context_length):
"""
์์
์ ์ต์ ์ธ ๋ชจ๋ธ ์ ํ
"""
# ๊ฐ๋จํ ์์
์ GPT-3.5-turbo
if task_complexity == 'simple' and context_length < 4000:
return 'gpt-3.5-turbo'
# ๊ธด ์ปจํ
์คํธ๋ 16k ๋ชจ๋ธ
elif context_length > 4000:
return 'gpt-3.5-turbo-16k'
# ๋ณต์กํ ์์
์ GPT-4
elif task_complexity == 'complex':
return 'gpt-4'
# ๊ธฐ๋ณธ๊ฐ
return 'gpt-3.5-turbo'
def optimize_prompt_length(self, prompt, max_tokens=None):
"""
ํ๋กฌํํธ ๊ธธ์ด ์ต์ ํ
"""
# ๋ถํ์ํ ๊ณต๋ฐฑ ์ ๊ฑฐ
optimized = ' '.join(prompt.split())
# ๋ฐ๋ณต๋๋ ์ง์์ฌํญ ์ ๊ฑฐ
lines = optimized.split('\n')
unique_lines = []
seen = set()
for line in lines:
line_lower = line.lower().strip()
if line_lower and line_lower not in seen:
unique_lines.append(line)
seen.add(line_lower)
optimized = '\n'.join(unique_lines)
# ์ต๋ ํ ํฐ ์ ์ ํ
if max_tokens:
words = optimized.split()
if len(words) > max_tokens * 0.75: # ๋๋ต์ ์ธ ๋ณํ
optimized = ' '.join(words[:int(max_tokens * 0.75)])
optimized += "..."
original_length = len(prompt)
optimized_length = len(optimized)
savings = original_length - optimized_length
self.logger.info(f"ํ๋กฌํํธ ์ต์ ํ: {original_length} -> {optimized_length} ({savings} ๋ฌธ์ ์ ๊ฐ)")
return optimized
def implement_smart_caching(self, cache_strategy='aggressive'):
"""
์ค๋งํธ ์บ์ฑ ์ ๋ต
"""
strategies = {
'aggressive': {
'ttl_hours': 168, # 1์ฃผ์ผ
'cache_threshold': 0.7 # 70% ์ ์ฌ๋๋ฉด ์บ์ ์ฌ์ฉ
},
'moderate': {
'ttl_hours': 24,
'cache_threshold': 0.85
},
'conservative': {
'ttl_hours': 1,
'cache_threshold': 0.95
}
}
return strategies.get(cache_strategy, strategies['moderate'])
def batch_similar_requests(self, requests, similarity_threshold=0.8):
"""
์ ์ฌํ ์์ฒญ๋ค์ ๋ฐฐ์น๋ก ๋ฌถ๊ธฐ
"""
from difflib import SequenceMatcher
batches = []
used = set()
for i, req1 in enumerate(requests):
if i in used:
continue
batch = [req1]
used.add(i)
for j, req2 in enumerate(requests[i+1:], i+1):
if j in used:
continue
# ์ ์ฌ๋ ๊ณ์ฐ
similarity = SequenceMatcher(None, req1, req2).ratio()
if similarity >= similarity_threshold:
batch.append(req2)
used.add(j)
batches.append(batch)
self.logger.info(f"{len(requests)}๊ฐ ์์ฒญ์ {len(batches)}๊ฐ ๋ฐฐ์น๋ก ๊ทธ๋ฃนํ")
return batches
def generate_cost_report(self, usage_data):
"""
๋น์ฉ ๋ฆฌํฌํธ ์์ฑ
"""
total_cost = 0
model_breakdown = {}
for entry in usage_data:
model = entry['model']
tokens = entry['tokens']
if model not in model_breakdown:
model_breakdown[model] = {'tokens': 0, 'cost': 0}
cost = (tokens / 1000) * self.cost_tracker[model]['output']
model_breakdown[model]['tokens'] += tokens
model_breakdown[model]['cost'] += cost
total_cost += cost
report = f"""
===== ๋น์ฉ ๋ฆฌํฌํธ =====
์ด ๋น์ฉ: ${total_cost:.4f}
๋ชจ๋ธ๋ณ ์ฌ์ฉ๋:
"""
for model, data in model_breakdown.items():
report += f"\n {model}:"
report += f"\n ํ ํฐ: {data['tokens']:,}"
report += f"\n ๋น์ฉ: ${data['cost']:.4f}"
report += f"\n ๋น์จ: {data['cost']/total_cost*100:.1f}%"
# ์ต์ ํ ์ ์
report += "\n\n ์ต์ ํ ์ ์:"
if 'gpt-4' in model_breakdown:
gpt4_ratio = model_breakdown['gpt-4']['cost'] / total_cost
if gpt4_ratio > 0.5:
report += "\n โข GPT-4 ์ฌ์ฉ ๋น์จ์ด ๋์ต๋๋ค. ์ผ๋ถ ์์
์ GPT-3.5-turbo๋ก ์ ํ ๊ณ ๋ ค"
avg_tokens = sum(e['tokens'] for e in usage_data) / len(usage_data)
if avg_tokens > 1000:
report += "\n โข ํ๊ท ํ ํฐ ์ฌ์ฉ๋์ด ๋์ต๋๋ค. ํ๋กฌํํธ ์ต์ ํ ๊ถ์ฅ"
return report
# ์ฌ์ฉ ์์
optimizer = CostOptimizer()
# ๋น์ฉ ์ถ์
text = "์ด๊ฒ์ ํ
์คํธ ํ
์คํธ์
๋๋ค..." * 100
cost_estimate = optimizer.estimate_cost(text, model='gpt-3.5-turbo')
print(f"์์ ๋น์ฉ: ${cost_estimate['estimated_cost']:.4f}")
# ์ต์ ๋ชจ๋ธ ์ ํ
optimal_model = optimizer.choose_optimal_model(
task_complexity='simple',
context_length=2000
)
print(f"์ถ์ฒ ๋ชจ๋ธ: {optimal_model}")
# ํ๋กฌํํธ ์ต์ ํ
long_prompt = "๊ฐ์ ๋ด์ฉ์ด ๋ฐ๋ณต๋ฉ๋๋ค. " * 50
optimized_prompt = optimizer.optimize_prompt_length(long_prompt, max_tokens=500)
โ ํ๋กฌํํธ ๊ธธ์ด ์ต์ํ (๋ถํ์ํ ๋ด์ฉ ์ ๊ฑฐ)
โ ์บ์ฑ ์ ๊ทน ํ์ฉ (๋ฐ๋ณต๋๋ ์์ฒญ)
โ ๋ฐฐ์น ์ฒ๋ฆฌ๋ก ํจ์จ์ฑ ํฅ์
โ max_tokens ํ๋ผ๋ฏธํฐ๋ก ์ถ๋ ฅ ๊ธธ์ด ์ ํ
โ temperature ๋ฎ์ถฐ์ ์ผ๊ด๋ ๊ฒฐ๊ณผ ์ป๊ธฐ
โ ์ ๊ธฐ์ ์ธ ๋น์ฉ ๋ชจ๋ํฐ๋ง ๋ฐ ๋ถ์
โ ๊ฐ๋ฐ/ํ ์คํธ ํ๊ฒฝ์์๋ ๋ ์ ๋ ดํ ๋ชจ๋ธ ์ฌ์ฉ
์ด๋ฐ ์ ๋ต๋ค์ ์ ํ์ฉํ๋ฉด ๋น์ฉ์ 50% ์ด์ ์ ๊ฐํ ์ ์์ด! ๐ฏ
๐ ์ค์๊ฐ ๋น์ฉ ๋ชจ๋ํฐ๋ง
class CostMonitor:
"""
์ค์๊ฐ ๋น์ฉ ๋ชจ๋ํฐ๋ง ์์คํ
"""
def __init__(self, daily_limit=10.0, alert_threshold=0.8):
self.daily_limit = daily_limit
self.alert_threshold = alert_threshold
self.today_cost = 0
self.today_date = datetime.now().date()
self.logger = logging.getLogger(__name__)
def track_usage(self, tokens, model):
"""
์ฌ์ฉ๋ ์ถ์
"""
# ๋ ์ง๊ฐ ๋ฐ๋๋ฉด ๋ฆฌ์
current_date = datetime.now().date()
if current_date != self.today_date:
self.today_cost = 0
self.today_date = current_date
# ๋น์ฉ ๊ณ์ฐ
cost_per_token = 0.002 / 1000 # ๊ธฐ๋ณธ๊ฐ
if model == 'gpt-4':
cost_per_token = 0.06 / 1000
cost = tokens * cost_per_token
self.today_cost += cost
# ์๋ฆผ ์ฒดํฌ
usage_ratio = self.today_cost / self.daily_limit
if usage_ratio >= 1.0:
self.logger.error(f"โ ์ผ์ผ ๋น์ฉ ํ๋ ์ด๊ณผ! ${self.today_cost:.4f} / ${self.daily_limit:.2f}")
raise Exception("์ผ์ผ ๋น์ฉ ํ๋ ์ด๊ณผ")
elif usage_ratio >= self.alert_threshold:
self.logger.warning(f"โ ๏ธ ๋น์ฉ ๊ฒฝ๊ณ ! {usage_ratio*100:.1f}% ์ฌ์ฉ ์ค")
return {
'cost': cost,
'today_total': self.today_cost,
'remaining': self.daily_limit - self.today_cost,
'usage_ratio': usage_ratio
}
def get_status(self):
"""
ํ์ฌ ์ํ ์กฐํ
"""
usage_ratio = self.today_cost / self.daily_limit
return {
'date': str(self.today_date),
'used': self.today_cost,
'limit': self.daily_limit,
'remaining': self.daily_limit - self.today_cost,
'usage_percentage': usage_ratio * 100,
'status': 'OK' if usage_ratio < self.alert_threshold else 'WARNING'
}
๐ ์ค์ ํ์ฉ ์ฌ๋ก
์ด๋ก ๊ณผ ์ฝ๋๋ฅผ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ๋ก ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง ๊ตฌ์ฒด์ ์ธ ์ฌ๋ก๋ค์ ์ดํด๋ณด์! ์ด๋ฐ ์ฌ๋ก๋ค์ ์ฐธ๊ณ ํ๋ฉด ๋๋ง์ ์๋ํ ์์คํ ์ ๋ง๋๋ ๋ฐ ํฐ ๋์์ด ๋ ๊ฑฐ์ผ. ๐ฏ
๐ง ์ฌ๋ก 1: ๊ณ ๊ฐ ๋ฌธ์ ์๋ ์๋ต ์์คํ
์ด์ปค๋จธ์ค ํ์ฌ์์ ํ๋ฃจ์ ์๋ฐฑ ๊ฐ์ ๊ณ ๊ฐ ๋ฌธ์๋ฅผ ๋ฐ๋๋ค๊ณ ๊ฐ์ ํด๋ณด์. ์ด๊ฑธ ์๋ํํ๋ฉด ์์ฒญ๋ ์๊ฐ๊ณผ ๋น์ฉ์ ์ ์ฝํ ์ ์์ด!
class CustomerSupportBot:
"""
๊ณ ๊ฐ ๋ฌธ์ ์๋ ์๋ต ์์คํ
"""
def __init__(self):
self.client = ChatGPTClient()
self.validator = InputValidator()
self.logger = logging.getLogger(__name__)
# ๋ฌธ์ ์ ํ๋ณ ํ
ํ๋ฆฟ
self.templates = {
'shipping': "๋ฐฐ์ก ๊ด๋ จ ๋ฌธ์์ ๋ํ ๋ต๋ณ์ ์์ฑํด์ฃผ์ธ์.",
'refund': "ํ๋ถ ๊ด๋ จ ๋ฌธ์์ ๋ํ ๋ต๋ณ์ ์์ฑํด์ฃผ์ธ์.",
'product': "์ ํ ๊ด๋ จ ๋ฌธ์์ ๋ํ ๋ต๋ณ์ ์์ฑํด์ฃผ์ธ์.",
'general': "์ผ๋ฐ ๋ฌธ์์ ๋ํ ๋ต๋ณ์ ์์ฑํด์ฃผ์ธ์."
}
def classify_inquiry(self, inquiry_text):
"""
๋ฌธ์ ์ ํ ๋ถ๋ฅ
"""
messages = [
{"role": "system", "content": "๋น์ ์ ๊ณ ๊ฐ ๋ฌธ์๋ฅผ ๋ถ๋ฅํ๋ ์ ๋ฌธ๊ฐ์
๋๋ค."},
{"role": "user", "content": f"""
๋ค์ ๊ณ ๊ฐ ๋ฌธ์๋ฅผ ๋ถ๋ฅํด์ฃผ์ธ์.
์นดํ
๊ณ ๋ฆฌ: shipping, refund, product, general ์ค ํ๋
๋ฌธ์ ๋ด์ฉ: {inquiry_text}
์นดํ
๊ณ ๋ฆฌ๋ง ๋ต๋ณํด์ฃผ์ธ์.
"""}
]
response = self.client.chat_completion(messages, temperature=0.3)
category = response['content'].strip().lower()
return category if category in self.templates else 'general'
def generate_response(self, inquiry_text, customer_name=None):
"""
์๋ ์๋ต ์์ฑ
"""
# ์
๋ ฅ ๊ฒ์ฆ
sanitized_inquiry = self.validator.sanitize_for_api(inquiry_text)
# ๋ฌธ์ ์ ํ ๋ถ๋ฅ
category = self.classify_inquiry(sanitized_inquiry)
self.logger.info(f"๋ฌธ์ ๋ถ๋ฅ: {category}")
# ์๋ต ์์ฑ
system_prompt = f"""
๋น์ ์ ์น์ ํ๊ณ ์ ๋ฌธ์ ์ธ ๊ณ ๊ฐ ์๋น์ค ๋ด๋น์์
๋๋ค.
๋ค์ ๊ฐ์ด๋๋ผ์ธ์ ๋ฐ๋ผ์ฃผ์ธ์:
- ๊ณต์ํ๊ณ ์น๊ทผํ ํค ์ฌ์ฉ
- ๊ตฌ์ฒด์ ์ด๊ณ ์ค์ฉ์ ์ธ ๋ต๋ณ ์ ๊ณต
- ํ์์ ์ถ๊ฐ ์ ๋ณด ์์ฒญ
- 200-300 ๋จ์ด ๋ถ๋
"""
user_prompt = f"""
๊ณ ๊ฐ ๋ฌธ์:
{sanitized_inquiry}
{self.templates[category]}
"""
if customer_name:
user_prompt = f"{customer_name}๋์ " + user_prompt
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
response = self.client.chat_completion(messages, temperature=0.7)
return {
'category': category,
'response': response['content'],
'tokens_used': response['tokens']
}
def process_inquiry_batch(self, inquiries):
"""
์ฌ๋ฌ ๋ฌธ์๋ฅผ ๋ฐฐ์น๋ก ์ฒ๋ฆฌ
"""
results = []
for inquiry in inquiries:
try:
result = self.generate_response(
inquiry['text'],
inquiry.get('customer_name')
)
results.append({
'inquiry_id': inquiry['id'],
'status': 'success',
**result
})
except Exception as e:
self.logger.error(f"๋ฌธ์ ์ฒ๋ฆฌ ์คํจ: {inquiry['id']} - {str(e)}")
results.append({
'inquiry_id': inquiry['id'],
'status': 'failed',
'error': str(e)
})
return results
# ์ฌ์ฉ ์์
support_bot = CustomerSupportBot()
inquiry = {
'id': 'INQ-001',
'customer_name': '๊น์ฒ ์',
'text': '์ฃผ๋ฌธํ ์ํ์ด ์์ง ๋์ฐฉํ์ง ์์์ต๋๋ค. ๋ฐฐ์ก ์กฐํ ๋ถํ๋๋ฆฝ๋๋ค.'
}
result = support_bot.generate_response(inquiry['text'], inquiry['customer_name'])
print(f"๋ถ๋ฅ: {result['category']}")
print(f"์๋ต:\n{result['response']}")
๐ ์ฌ๋ก 2: ์ฝํ ์ธ ๋ฒ์ญ ๋ฐ ํ์งํ ์์คํ
๊ธ๋ก๋ฒ ์๋น์ค๋ฅผ ์ด์ํ๋ค๋ฉด ์ฝํ ์ธ ๋ฅผ ์ฌ๋ฌ ์ธ์ด๋ก ๋ฒ์ญํด์ผ ํด. ๋จ์ ๋ฒ์ญ์ ๋์ด์ ๋ฌธํ์ ๋งฅ๋ฝ๊น์ง ๊ณ ๋ คํ ํ์งํ๊ฐ ํ์ํ์ง!
class ContentLocalizer:
"""
์ฝํ
์ธ ๋ฒ์ญ ๋ฐ ํ์งํ ์์คํ
"""
def __init__(self):
self.client = ChatGPTClient()
self.cache = ResponseCache(cache_dir="translation_cache", ttl_hours=720) # 30์ผ
self.logger = logging.getLogger(__name__)
# ์ง์ ์ธ์ด ๋ฐ ๋ฌธํ๊ถ ์ ๋ณด
self.locales = {
'ko': {'name': 'ํ๊ตญ์ด', 'culture': 'ํ๊ตญ'},
'en': {'name': 'English', 'culture': 'US'},
'ja': {'name': 'ๆฅๆฌ่ช', 'culture': '์ผ๋ณธ'},
'zh': {'name': 'ไธญๆ', 'culture': '์ค๊ตญ'},
'es': {'name': 'Espaรฑol', 'culture': '์คํ์ธ/๋ผํด์๋ฉ๋ฆฌ์นด'}
}
def translate_with_context(self, text, source_lang, target_lang,
content_type='general', tone='neutral'):
"""
๋ฌธ๋งฅ์ ๊ณ ๋ คํ ๋ฒ์ญ
"""
# ์บ์ ํ์ธ
cache_key = f"{text}_{source_lang}_{target_lang}_{content_type}_{tone}"
system_prompt = f"""
๋น์ ์ ์ ๋ฌธ ๋ฒ์ญ๊ฐ์ด์ ํ์งํ ์ ๋ฌธ๊ฐ์
๋๋ค.
๋ค์ ๊ฐ์ด๋๋ผ์ธ์ ๋ฐ๋ผ์ฃผ์ธ์:
- ์๋ฌธ์ ์๋ฏธ์ ๋์์ค๋ฅผ ์ ํํ ์ ๋ฌ
- {self.locales[target_lang]['culture']} ๋ฌธํ๊ถ์ ๋ง๊ฒ ํํ ์กฐ์
- {tone} ํค ์ ์ง
- ์์ฐ์ค๋ฌ์ด {self.locales[target_lang]['name']} ํํ ์ฌ์ฉ
- ๊ด์ฉ๊ตฌ๋ ๋ฌธํ์ ์ฐธ์กฐ๋ ํ์งํ
"""
user_prompt = f"""
๋ค์ {content_type} ์ฝํ
์ธ ๋ฅผ {source_lang}์์ {target_lang}๋ก ๋ฒ์ญํด์ฃผ์ธ์:
{text}
๋ฒ์ญ๋ฌธ๋ง ์ ๊ณตํด์ฃผ์ธ์.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
response = self.client.chat_completion(messages, temperature=0.3)
return {
'translated_text': response['content'],
'source_lang': source_lang,
'target_lang': target_lang,
'tokens_used': response['tokens']
}
def localize_marketing_content(self, content, target_lang):
"""
๋ง์ผํ
์ฝํ
์ธ ํ์งํ (๋ฌธํ์ ์ ์ ํฌํจ)
"""
system_prompt = f"""
๋น์ ์ ๊ธ๋ก๋ฒ ๋ง์ผํ
์ ๋ฌธ๊ฐ์
๋๋ค.
{self.locales[target_lang]['culture']} ์์ฅ์ ์ํ ๋ง์ผํ
์ฝํ
์ธ ๋ฅผ ์์ฑํด์ฃผ์ธ์.
๊ณ ๋ ค์ฌํญ:
- ํ์ง ๋ฌธํ์ ๊ฐ์น๊ด
- ์ ํธํ๋ ๋ง์ผํ
์คํ์ผ
- ๊ธ๊ธฐ์ฌํญ ๋ฐ ๋ฏผ๊ฐํ ์ฃผ์
- ํจ๊ณผ์ ์ธ ์ค๋ ์ ๋ต
"""
user_prompt = f"""
๋ค์ ๋ง์ผํ
์ฝํ
์ธ ๋ฅผ {self.locales[target_lang]['name']}๋ก ํ์งํํด์ฃผ์ธ์:
{content}
๋จ์ ๋ฒ์ญ์ด ์๋, ํ์ง ์์ฅ์ ์ต์ ํ๋ ๋ฒ์ ์ ์์ฑํด์ฃผ์ธ์.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
response = self.client.chat_completion(messages, temperature=0.7)
return response['content']
def batch_translate(self, texts, source_lang, target_langs):
"""
์ฌ๋ฌ ์ธ์ด๋ก ์ผ๊ด ๋ฒ์ญ
"""
results = {}
for target_lang in target_langs:
self.logger.info(f"๋ฒ์ญ ์ค: {source_lang} -> {target_lang}")
translations = []
for text in texts:
try:
result = self.translate_with_context(
text, source_lang, target_lang
)
translations.append(result['translated_text'])
except Exception as e:
self.logger.error(f"๋ฒ์ญ ์คํจ: {str(e)}")
translations.append(None)
results[target_lang] = translations
return results
def quality_check(self, original, translated, source_lang, target_lang):
"""
๋ฒ์ญ ํ์ง ๊ฒ์ฌ
"""
system_prompt = """
๋น์ ์ ๋ฒ์ญ ํ์ง ํ๊ฐ ์ ๋ฌธ๊ฐ์
๋๋ค.
๋ค์ ๊ธฐ์ค์ผ๋ก ๋ฒ์ญ์ ํ๊ฐํด์ฃผ์ธ์:
1. ์ ํ์ฑ (์๋ฏธ ์ ๋ฌ)
2. ์์ฐ์ค๋ฌ์ (๋ฌธ๋ฒ, ํํ)
3. ๋ฌธํ์ ์ ์ ์ฑ
4. ์ผ๊ด์ฑ
๊ฐ ํญ๋ชฉ์ 1-10์ ์ผ๋ก ํ๊ฐํ๊ณ , ๊ฐ์ ์ ์์ ํด์ฃผ์ธ์.
"""
user_prompt = f"""
์๋ฌธ ({source_lang}):
{original}
๋ฒ์ญ๋ฌธ ({target_lang}):
{translated}
ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ JSON ํ์์ผ๋ก ์ ๊ณตํด์ฃผ์ธ์:
{{
"accuracy": ์ ์,
"naturalness": ์ ์,
"cultural_fit": ์ ์,
"consistency": ์ ์,
"overall": ํ๊ท ์ ์,
"suggestions": ["๊ฐ์ ์ ์1", "๊ฐ์ ์ ์2", ...]
}}
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
response = self.client.chat_completion(messages, temperature=0.3)
try:
import json
quality_report = json.loads(response['content'])
return quality_report
except:
return {'error': 'ํ๊ฐ ๊ฒฐ๊ณผ ํ์ฑ ์คํจ'}
# ์ฌ์ฉ ์์
localizer = ContentLocalizer()
# ๋จ์ผ ๋ฒ์ญ
original_text = "์ฐ๋ฆฌ ์ ํ์ ํ์ ์ ์ธ ๊ธฐ์ ๋ก ๊ณ ๊ฐ์ ์ถ์ ๋ณํ์ํต๋๋ค."
result = localizer.translate_with_context(
original_text,
source_lang='ko',
target_lang='en',
content_type='marketing',
tone='professional'
)
print(f"๋ฒ์ญ: {result['translated_text']}")
# ๋ง์ผํ
์ฝํ
์ธ ํ์งํ
marketing_text = "์ง๊ธ ๊ฐ์
ํ๋ฉด ํน๋ณ ํ ์ธ!"
localized = localizer.localize_marketing_content(marketing_text, 'ja')
print(f"ํ์งํ: {localized}")
๐ ์ฌ๋ก 3: ๋ฐ์ดํฐ ๋ถ์ ๋ฐ ๋ฆฌํฌํธ ์๋ ์์ฑ
๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ณ ์ธ์ฌ์ดํธ๋ฅผ ๋์ถํ๋ ์์ ๋ ์๋ํํ ์ ์์ด! ํนํ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ๋ฐ์ดํฐ ๋ถ์ ์๋ํ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ค๋ฉด ๋ง์ ์์๊ฐ ์์ ๊ฑฐ์ผ.
import pandas as pd
import json
class DataAnalysisBot:
"""
๋ฐ์ดํฐ ๋ถ์ ๋ฐ ๋ฆฌํฌํธ ์๋ ์์ฑ
"""
def __init__(self):
self.client = ChatGPTClient()
self.logger = logging.getLogger(__name__)
def analyze_dataframe(self, df, analysis_type='summary'):
"""
DataFrame ๋ถ์
"""
# ๋ฐ์ดํฐ ์์ฝ ์ ๋ณด ์์ฑ
summary = {
'shape': df.shape,
'columns': df.columns.tolist(),
'dtypes': df.dtypes.astype(str).to_dict(),
'missing_values': df.isnull().sum().to_dict(),
'basic_stats': df.describe().to_dict()
}
# ์ํ ๋ฐ์ดํฐ
sample_data = df.head(5).to_dict('records')
system_prompt = """
๋น์ ์ ๋ฐ์ดํฐ ๋ถ์ ์ ๋ฌธ๊ฐ์
๋๋ค.
์ฃผ์ด์ง ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ณ ์ธ์ฌ์ดํธ๋ฅผ ๋์ถํด์ฃผ์ธ์.
"""
user_prompt = f"""
๋ค์ ๋ฐ์ดํฐ์
์ ๋ถ์ํด์ฃผ์ธ์:
๋ฐ์ดํฐ ์ ๋ณด:
- ํ/์ด: {summary['shape']}
- ์ปฌ๋ผ: {', '.join(summary['columns'])}
์ํ ๋ฐ์ดํฐ:
{json.dumps(sample_data, ensure_ascii=False, indent=2)}
๊ธฐ๋ณธ ํต๊ณ:
{json.dumps(summary['basic_stats'], ensure_ascii=False, indent=2)}
๋ค์ ๋ด์ฉ์ ํฌํจํด์ ๋ถ์ํด์ฃผ์ธ์:
1. ๋ฐ์ดํฐ ๊ฐ์
2. ์ฃผ์ ํน์ง ๋ฐ ํจํด
3. ์ด์์น๋ ํน์ด์ฌํญ
4. ์ค์ฉ์ ์ธ ์ธ์ฌ์ดํธ
5. ์ถ๊ฐ ๋ถ์ ์ ์
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
response = self.client.chat_completion(messages, temperature=0.5)
return {
'analysis': response['content'],
'data_summary': summary
}
def generate_business_report(self, data_dict, report_type='monthly'):
"""
๋น์ฆ๋์ค ๋ฆฌํฌํธ ์์ฑ
"""
system_prompt = f"""
๋น์ ์ ๋น์ฆ๋์ค ์ ๋๋ฆฌ์คํธ์
๋๋ค.
{report_type} ๋ฆฌํฌํธ๋ฅผ ์์ฑํด์ฃผ์ธ์.
๋ฆฌํฌํธ ๊ตฌ์ฑ:
1. ์์ฝ (Executive Summary)
2. ์ฃผ์ ์งํ ๋ถ์
3. ํธ๋ ๋ ๋ฐ ์ธ์ฌ์ดํธ
4. ๊ถ์ฅ ์ฌํญ
5. ๋ค์ ๋จ๊ณ
"""
user_prompt = f"""
๋ค์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ๋ฆฌํฌํธ๋ฅผ ์์ฑํด์ฃผ์ธ์:
{json.dumps(data_dict, ensure_ascii=False, indent=2)}
์ ๋ฌธ์ ์ด๊ณ ์คํ ๊ฐ๋ฅํ ์ธ์ฌ์ดํธ๋ฅผ ์ ๊ณตํด์ฃผ์ธ์.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
response = self.client.chat_completion(messages, temperature=0.6)
return response['content']
def compare_periods(self, current_data, previous_data, metrics):
"""
๊ธฐ๊ฐ๋ณ ๋น๊ต ๋ถ์
"""
system_prompt = """
๋น์ ์ ๋ฐ์ดํฐ ๋น๊ต ๋ถ์ ์ ๋ฌธ๊ฐ์
๋๋ค.
๋ ๊ธฐ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋น๊ตํ๊ณ ๋ณํ๋ฅผ ๋ถ์ํด์ฃผ์ธ์.
"""
comparison = {}
for metric in metrics:
current = current_data.get(metric, 0)
previous = previous_data.get(metric, 0)
if previous != 0:
change_pct = ((current - previous) / previous) * 100
else:
change_pct = 0
comparison[metric] = {
'current': current,
'previous': previous,
'change': current - previous,
'change_pct': change_pct
}
user_prompt = f"""
๋ค์ ์งํ๋ค์ ๋ณํ๋ฅผ ๋ถ์ํด์ฃผ์ธ์:
{json.dumps(comparison, ensure_ascii=False, indent=2)}
๊ฐ ์งํ์ ๋ํด:
1. ๋ณํ์ ์๋ฏธ
2. ๊ฐ๋ฅํ ์์ธ
3. ์์ฌ์
4. ๋์ ๋ฐฉ์
์ ์ ์ํด์ฃผ์ธ์.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
response = self.client.chat_completion(messages, temperature=0.5)
return {
'comparison_data': comparison,
'analysis': response['content']
}
# ์ฌ์ฉ ์์
analyzer = DataAnalysisBot()
# ์ํ ๋ฐ์ดํฐ ์์ฑ
df = pd.DataFrame({
'๋ ์ง': pd.date_range('2024-01-01', periods=100),
'๋งค์ถ': np.random.randint(100000, 500000, 100),
'๋ฐฉ๋ฌธ์': np.random.randint(1000, 5000, 100),
'์ ํ์จ': np.random.uniform(0.01, 0.05, 100)
})
# ๋ฐ์ดํฐ ๋ถ์
result = analyzer.analyze_dataframe(df)
print(result['analysis'])
# ๋น์ฆ๋์ค ๋ฆฌํฌํธ ์์ฑ
monthly_data = {
'์ด๋งค์ถ': 15000000,
'์ ๊ท๊ณ ๊ฐ': 1250,
'์ฌ๊ตฌ๋งค์จ': 0.35,
'ํ๊ท ์ฃผ๋ฌธ๊ธ์ก': 120000
}
report = analyzer.generate_business_report(monthly_data, 'monthly')
print(report)
์๋ฅผ ๋ค์ด:
- ๊ณ ๊ฐ ๋ฌธ์ ์๋ ์๋ต + ๋ฒ์ญ ์์คํ = ๋ค๊ตญ์ด ๊ณ ๊ฐ ์ง์
- ๋ฐ์ดํฐ ๋ถ์ + ์ฝํ ์ธ ์์ฑ = ์๋ ๋ฆฌํฌํธ ์์ฑ ๋ฐ ๋ฐฐํฌ
- ๋ชจ๋ ์์คํ + ๋ชจ๋ํฐ๋ง = ์์ ์๋ํ๋ ๋น์ฆ๋์ค ํ๋ก์ธ์ค
์ฐฝ์์ ์ผ๋ก ์กฐํฉํด์ ๋๋ง์ ๋ ํนํ ์๋ฃจ์ ์ ๋ง๋ค์ด๋ด! ๐
๐ ๋ง๋ฌด๋ฆฌ ๋ฐ ๋ค์ ๋จ๊ณ
์! ์ฌ๊ธฐ๊น์ง ์ ๋ง ๊ธด ์ฌ์ ์ด์์ด. ์ถํํด! ๐ ์ด์ ๋๋ ChatGPT API๋ฅผ ํ์ฉํ ์๋ํ ์์คํ ์ ์ค๊ณํ๊ณ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์์ ํ ์ดํดํ์ด. ๋ฐฐ์ด ๋ด์ฉ์ ๊ฐ๋จํ ์ ๋ฆฌํด๋ณด์:
๐ฏ ํต์ฌ ์์ฝ
- ChatGPT API์ ์๋ ์๋ฆฌ์ ๊ตฌ์ฑ ์์ ์ดํด
- ํ ํฐ ๊ฐ๋ ๊ณผ ๋น์ฉ ๊ตฌ์กฐ ํ์
- ์์ ํ API ํค ๊ด๋ฆฌ ๋ฐฉ๋ฒ
- ๊ธฐ๋ณธ์ ์ธ API ํธ์ถ ๋ฐ ์๋ต ์ฒ๋ฆฌ
- ๋ชจ๋ํ๋ ๊ตฌ์กฐ ์ค๊ณ
- ๋ ์ด์ด๋ณ ์ฑ ์ ๋ถ๋ฆฌ
- ํ์ฅ ๊ฐ๋ฅํ ์ํฌํ๋ก์ฐ ๊ตฌ์ถ
- ๋ณด์๊ณผ ์์ ์ฑ์ ๊ณ ๋ คํ ์ค๊ณ
- API ํด๋ผ์ด์ธํธ ๋ชจ๋ ๊ฐ๋ฐ
- ํ๋กฌํํธ ๊ด๋ฆฌ ์์คํ
- ๋ฐฐ์น ์ฒ๋ฆฌ ๋ฐ ํ ์์คํ
- ์บ์ฑ๊ณผ ์ต์ ํ ๊ธฐ๋ฒ
- ์คํธ๋ฆฌ๋ฐ ์๋ต ์ฒ๋ฆฌ
- ์ปจํ ์คํธ ๊ด๋ฆฌ
- ์๋ฌ ์ฒ๋ฆฌ ๋ฐ ์ฌ์๋ ๋ก์ง
- ๋ชจ๋ํฐ๋ง ๋ฐ ๋ก๊น
- ํ๋กฌํํธ ์์ง๋์ด๋ง ๊ธฐ๋ฒ
- ๋น์ฉ ์ ๊ฐ ๋ฐฉ๋ฒ
- ์ฑ๋ฅ ํ๋
- ํ์ง ๊ด๋ฆฌ
๐ ์ถ๊ฐ ํ์ต ๋ฆฌ์์ค
๋ ๊น์ด ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด ๋ค์ ๋ฆฌ์์ค๋ค์ ์ถ์ฒํด:
| ๋ฆฌ์์ค | ์ค๋ช | ๋์ด๋ |
|---|---|---|
| OpenAI ๊ณต์ ๋ฌธ์ | API ๋ ํผ๋ฐ์ค ๋ฐ ๊ฐ์ด๋ | โญโญ |
| OpenAI Cookbook | ์ค์ ์์ ๋ฐ ๋ฒ ์คํธ ํ๋ํฐ์ค | โญโญโญ |
| Prompt Engineering Guide | ํ๋กฌํํธ ์์ฑ ๊ธฐ๋ฒ | โญโญ |
| LangChain | LLM ์ ํ๋ฆฌ์ผ์ด์ ํ๋ ์์ํฌ | โญโญโญโญ |
| AI ์ปค๋ฎค๋ํฐ | Reddit, Discord ๋ฑ | โญ |
๐ ๋ค์ ๋จ๊ณ ๋ก๋๋งต
์ด์ ๊ธฐ๋ณธ์ ๋ง์คํฐํ์ผ๋, ๋ค์ ๋จ๊ณ๋ก ๋์๊ฐ๋ณด์:
2. ์ค์ ๋ฐ์ดํฐ๋ก ํ ์คํธํ๊ธฐ
3. ๋น์ฉ๊ณผ ์ฑ๋ฅ ๋ชจ๋ํฐ๋งํ๊ธฐ
4. ์ฝ๋ ๋ฆฌํฉํ ๋ง ๋ฐ ์ต์ ํ
์ค๊ธฐ ๋ชฉํ (1-2๊ฐ์)
1. ๋ณต์กํ ์ํฌํ๋ก์ฐ ๊ตฌํ
2. ์ฌ๋ฌ API ํตํฉ (์ด๋ฏธ์ง ์์ฑ, ์์ฑ ์ธ์ ๋ฑ)
3. ํ๋ก๋์ ํ๊ฒฝ ๋ฐฐํฌ
4. ์ฌ์ฉ์ ํผ๋๋ฐฑ ์์ง ๋ฐ ๊ฐ์
์ฅ๊ธฐ ๋ชฉํ (3-6๊ฐ์)
1. ํ์ฅ ๊ฐ๋ฅํ ์๋น์ค๋ก ๋ฐ์
2. ๊ณ ๊ธ AI ๊ธฐ๋ฅ ์ถ๊ฐ (Fine-tuning, RAG ๋ฑ)
3. ๋น์ฆ๋์ค ๋ชจ๋ธ ๊ตฌ์ถ
4. ์ปค๋ฎค๋ํฐ ๊ธฐ์ฌ ๋ฐ ์ง์ ๊ณต์
๐ช ์ค์ฒ ๊ณผ์
๋ฐฐ์ด ๋ด์ฉ์ ์ค์ ๋ก ์ ์ฉํด๋ณด๋ ๊ฒ ๊ฐ์ฅ ์ค์ํด! ๋ค์ ๊ณผ์ ๋ค์ ์๋ํด๋ด:
- ๊ฐ๋จํ ์ฑ๋ด ๋ง๋ค๊ธฐ
- ํ ์คํธ ์์ฝ ๋๊ตฌ ๊ฐ๋ฐ
- ์๋ ์ด๋ฉ์ผ ๋ต์ฅ ์์คํ
- ํค์๋ ์ถ์ถ๊ธฐ
- ๋ธ๋ก๊ทธ ์๋ ์์ฑ ์์คํ (์ฐ๋ฆฌ๊ฐ ๋ง๋ ๊ฒ ๊ฐ์ )
- ๋ค๊ตญ์ด ๋ฒ์ญ ์๋น์ค
- ๊ณ ๊ฐ ๋ฌธ์ ์๋ ๋ถ๋ฅ ๋ฐ ์๋ต
- ๋ฐ์ดํฐ ๋ถ์ ๋ฆฌํฌํธ ์๋ํ
- AI ๊ธฐ๋ฐ ์ฝํ ์ธ ๊ด๋ฆฌ ์์คํ
- ๊ฐ์ธํ๋ ํ์ต ๋์ฐ๋ฏธ
- ์๋ํ๋ ๋ง์ผํ ์บ ํ์ธ ๊ด๋ฆฌ
- ์ง๋ฅํ ๋น์ฆ๋์ค ์ธํ ๋ฆฌ์ ์ค ํ๋ซํผ
๐ ๋ง์ง๋ง ์กฐ์ธ
์๋ํ ์์คํ
์ ๋ง๋ค ๋ ๊ฐ์ฅ ์ค์ํ ๊ฑด ์ค์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ด์ผ. ๊ธฐ์ ์ ์ํ ๊ธฐ์ ์ด ์๋๋ผ, ์ฌ๋๋ค์ ์ถ์ ์ค์ง์ ์ผ๋ก ๊ฐ์ ํ๋ ์๋ฃจ์
์ ๋ง๋ค์ด์ผ ํด. ๐ก
์์์ ์๊ฒ ํ๋, ๊พธ์คํ ๊ฐ์ ํด๋๊ฐ. ์๋ฒฝํ ์์คํ
์ ์ฒ์๋ถํฐ ๋ง๋ค๋ ค๊ณ ํ์ง ๋ง๊ณ , MVP(Minimum Viable Product)๋ฅผ ๋น ๋ฅด๊ฒ ๋ง๋ค์ด์ ํผ๋๋ฐฑ์ ๋ฐ๊ณ ๋ฐ๋ณต์ ์ผ๋ก ๊ฐ์ ํ๋ ๊ฒ ํจ์ฌ ํจ๊ณผ์ ์ด์ผ. ๐
๊ทธ๋ฆฌ๊ณ ํญ์ ๋น์ฉ๊ณผ ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํด. AI๋ ๊ฐ๋ ฅํ์ง๋ง ๋น์ฉ์ด ๋ค๊ธฐ ๋๋ฌธ์, ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ ์ ๋ง ์ค์ํด. ์บ์ฑ, ๋ฐฐ์น ์ฒ๋ฆฌ, ์ ์ ํ ๋ชจ๋ธ ์ ํ ๋ฑ์ผ๋ก ๋น์ฉ์ ํฌ๊ฒ ์ค์ผ ์ ์๋ค๋ ๊ฑธ ์์ง ๋ง! ๐ฐ
๋ณด์๋ ์ ๋ ๊ฐ๊ณผํ๋ฉด ์ ๋ผ. API ํค ๊ด๋ฆฌ, ์
๋ ฅ ๊ฒ์ฆ, ๋ฏผ๊ฐํ ์ ๋ณด ๋ณดํธ ๋ฑ์ ์ฒ์๋ถํฐ ์ ๋๋ก ๊ตฌํํด์ผ ํด. ๋์ค์ ๋ณด์ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ์์ตํ๊ธฐ๊ฐ ์ ๋ง ์ด๋ ค์. ๐
๋ง์ง๋ง์ผ๋ก, ์ปค๋ฎค๋ํฐ์ ํจ๊ป ์ฑ์ฅํด. ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ๊ฒฝํ์ ๊ณต์ ํ๊ณ , ์คํ์์ค ํ๋ก์ ํธ์ ๊ธฐ์ฌํ๊ณ , ์ง๋ฌธํ๊ณ ๋ต๋ณํ๋ฉด์ ๋ฐฐ์๋๊ฐ. ํผ์์๋ ํ๊ณ๊ฐ ์์ง๋ง, ํจ๊ปํ๋ฉด ํจ์ฌ ๋น ๋ฅด๊ฒ ์ฑ์ฅํ ์ ์์ด! ๐ค
โ ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ์๋ฃ
โ ๊ธฐ๋ณธ API ํธ์ถ ํ ์คํธ ์ฑ๊ณต
โ ๊ฐ๋จํ ์๋ํ ํ๋ก์ ํธ ์์ฑ
โ ์๋ฌ ์ฒ๋ฆฌ ๋ฐ ๋ก๊น ๊ตฌํ
โ ๋น์ฉ ๋ชจ๋ํฐ๋ง ์์คํ ๊ตฌ์ถ
โ ๋ณด์ ์กฐ์น ์ ์ฉ
โ ์ค์ ํ๋ก์ ํธ ๊ณํ ์๋ฆฝ
๋ชจ๋ ํญ๋ชฉ์ ์ฒดํฌํ๋ค๋ฉด, ์ด์ ์ง์ง ์์์ด์ผ! ๐
์ฌ๊ธฐ๊น์ง ๊ธด ๊ธ์ ์ฝ์ด์ค์ ์ ๋ง ๊ณ ๋ง์! ์ด ๊ฐ์ด๋๊ฐ ๋์ AI ์๋ํ ์ฌ์ ์ ๋์์ด ๋์์ผ๋ฉด ์ข๊ฒ ์ด. ๊ถ๊ธํ ์ ์ด ์๊ฑฐ๋ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ๋งํ๋ ๋ถ๋ถ์ด ์๋ค๋ฉด, ์ปค๋ฎค๋ํฐ์์ ์ง๋ฌธํ๊ฑฐ๋ ๊ณต์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด๋ด. ๐
๊ทธ๋ฆฌ๊ณ ๋๋ง์ ๋ฉ์ง ์๋ํ ์์คํ
์ ๋ง๋ค์๋ค๋ฉด, ๊ผญ ๋ค๋ฅธ ์ฌ๋๋ค๊ณผ ๊ณต์ ํด์ค! ๋์ ๊ฒฝํ์ด ๋ค๋ฅธ ๋๊ตฐ๊ฐ์๊ฒ๋ ํฐ ๋์์ด ๋ ์ ์์ด. ์ฐ๋ฆฌ ๋ชจ๋ ํจ๊ป ์ฑ์ฅํ๋ ๊ฑฐ์ผ! ๐ฑ
์, ์ด์ ์ฝ๋ฉ์ ์์ํ ์๊ฐ์ด์ผ! ํ์ดํ
! ๐ชโจ
๐ ์ถํํฉ๋๋ค! ๐
ChatGPT API ์๋ํ ์์คํ ์ค๊ณ ๋ง์คํฐ ๊ณผ์ ์ ์๋ฃํ์ต๋๋ค!
์ด์ ๋น์ ์ AI ์๋ํ ์ ๋ฌธ๊ฐ์ ๋๋ค. ๐
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.