peekabook-api / app /simulation /user_sim.py
lael
feat: initial deploy
3960e2b
Raw
History Blame Contribute Delete
3.5 kB
import os
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
PERSONA_TEMPLATES = {
"์ง์žฅ์ธ_SFํŒฌ": {
"age_group": "30๋Œ€ ์ดˆ๋ฐ˜",
"job": "IT ์Šคํƒ€ํŠธ์—… ๊ฐœ๋ฐœ์ž, ํ‰์ผ์—” ๋ฐ”๋น ์„œ ์ฃผ๋ง์— ๋ชฐ์•„ ์ฝ๋Š” ํŽธ",
"favorite_genre": "SF, ํ…Œํฌ ์Šค๋ฆด๋Ÿฌ",
"reading_frequency": "ํ•œ ๋‹ฌ์— 1~2๊ถŒ",
"mood": "๋จธ๋ฆฌ๋ฅผ ๋น„์šฐ๊ณ  ์‹ถ์–ด์„œ ๊ฐ€๋ณ๊ฒŒ ์ฝํžˆ๋Š” ์ฑ…์„ ์›ํ•จ",
"disliked_genre": "๋กœ๋งจ์Šค, ์ž๊ธฐ๊ณ„๋ฐœ",
"reading_experience": "์ตœ๊ทผ์— 'ํ”„๋กœ์ ํŠธ ํ—ค์ผ๋ฉ”๋ฆฌ'๋ฅผ ์ฝ๊ณ  ์žฌ๋ฏธ์žˆ์—ˆ์Œ"
},
"๋Œ€ํ•™์ƒ_๋ฌธํ•™ํŒฌ": {
"age_group": "20๋Œ€ ์ดˆ๋ฐ˜",
"job": "๋Œ€ํ•™๊ต ๊ตญ๋ฌธํ•™๊ณผ ์žฌํ•™ ์ค‘",
"favorite_genre": "ํ•œ๊ตญ ํ˜„๋Œ€์†Œ์„ค, ์‹œ",
"reading_frequency": "์ผ์ฃผ์ผ์— 1๊ถŒ ์ด์ƒ",
"mood": "๊ฐ์„ฑ์ ์ด๊ณ  ๋ฌธ์žฅ์ด ์•„๋ฆ„๋‹ค์šด ์ฑ…์„ ์›ํ•จ",
"disliked_genre": "ํŒํƒ€์ง€, ๋ฌดํ˜‘",
"reading_experience": "ํ•œ๊ฐ• ์ž‘๊ฐ€์˜ ์ฑ„์‹์ฃผ์˜์ž๋ฅผ ์ฝ๊ณ  ๊นŠ์€ ์ธ์ƒ์„ ๋ฐ›์Œ"
},
"์ค‘๋…„_์—ญ์‚ฌ_๋น„๋ฌธํ•™": {
"age_group": "40๋Œ€ ์ค‘๋ฐ˜",
"job": "์ค‘ํ•™๊ต ์—ญ์‚ฌ ๊ต์‚ฌ",
"favorite_genre": "์—ญ์‚ฌ, ๊ต์–‘ ๋น„๋ฌธํ•™",
"reading_frequency": "ํ•œ ๋‹ฌ์— 3~4๊ถŒ",
"mood": "์ˆ˜์—…์— ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํฅ๋ฏธ๋กœ์šด ์—ญ์‚ฌ ์ด์•ผ๊ธฐ",
"disliked_genre": "๊ณตํฌ, ์˜ค์ปฌํŠธ",
"reading_experience": "์œ ๋ฐœ ํ•˜๋ผ๋ฆฌ์˜ ์‚ฌํ”ผ์—”์Šค๋ฅผ ์ธ์ƒ ๊นŠ๊ฒŒ ์ฝ์Œ"
}
}
class UserSimAgent:
"""
CRS ์‹œ์Šคํ…œ์˜ ํ”„๋กœํŒŒ์ผ๋ง ์งˆ๋ฌธ์— ํŽ˜๋ฅด์†Œ๋‚˜ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™ ์‘๋‹ตํ•˜๋Š” ์—์ด์ „ํŠธ.
"""
SYSTEM_PROMPT_TEMPLATE = """\
๋‹น์‹ ์€ ๋„์„œ ์ถ”์ฒœ ์ฑ—๋ด‡๊ณผ ๋Œ€ํ™”ํ•˜๋Š” ์‹ค์ œ ์‚ฌ์šฉ์ž๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ์—์ด์ „ํŠธ์ž…๋‹ˆ๋‹ค.
## ๋‹น์‹ ์˜ ํŽ˜๋ฅด์†Œ๋‚˜
{persona_str}
## ํ–‰๋™ ๊ทœ์น™
1. ์œ„ ํŽ˜๋ฅด์†Œ๋‚˜์— ์ถฉ์‹คํ•˜๊ฒŒ ๋‹ต๋ณ€ํ•˜์„ธ์š”.
2. ์‹ค์ œ ์‚ฌ๋žŒ์ฒ˜๋Ÿผ ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ๊ตฌ์–ด์ฒด๋กœ ๋‹ต๋ณ€ํ•˜์„ธ์š”. (๋‹จ๋‹ต ๊ฐ€๋Šฅ)
3. ํŽ˜๋ฅด์†Œ๋‚˜์— ์—†๋Š” ์ •๋ณด๋Š” ํŽ˜๋ฅด์†Œ๋‚˜์™€ ์ผ๊ด€๋œ ๋ฐฉํ–ฅ์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋งŒ๋“ค์–ด๋‚ด์„ธ์š”.
4. ์ฑ—๋ด‡์˜ ์งˆ๋ฌธ์—๋งŒ ๋‹ตํ•˜์„ธ์š”. ์ฑ… ์ถ”์ฒœ์„ ๋จผ์ € ์š”์ฒญํ•˜์ง€ ๋งˆ์„ธ์š”.
5. ๋‹ต๋ณ€์€ 1~3๋ฌธ์žฅ ์ด๋‚ด๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ.
"""
def __init__(self, persona: dict, model: str = "gpt-4o-mini", verbose: bool = True):
self.persona = persona
self.model = model
self.verbose = verbose
self.history = []
self.turn_count = 0
persona_str = "\n".join(f"- {k}: {v}" for k, v in persona.items())
self.system_prompt = self.SYSTEM_PROMPT_TEMPLATE.format(persona_str=persona_str)
self.client = OpenAI()
def answer(self, question: str) -> str:
self.turn_count += 1
self.history.append({"role": "user", "content": question})
if self.verbose:
print(f"\n[Turn {self.turn_count}]")
print(f" CRS : {question}")
messages = [
{"role": "system", "content": self.system_prompt},
*self.history,
]
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=0.7,
)
answer_text = response.choices[0].message.content.strip()
self.history.append({"role": "assistant", "content": answer_text})
if self.verbose:
print(f" USER : {answer_text}")
return answer_text
def get_history(self) -> list:
return self.history