샘플 작업

[python, 샘플] 오늘의 운세 (OpenAI 활용)

woopii 2025. 4. 6. 20:57

개요

재미 삼아 만든 오늘의 운세.

OpenAI를 활용해 띠별, 별자리별 운세데이터 생성.

 

  • OpenAI통해서 오늘 날짜 기준으로 띠별, 별자리별 운세데이터 생성.
  • JSON 형식으로 변환.
  • DB 저장.

 

구현 방식

1. 띠별, 별자리별 운세데이터 생성.

  • OpenAI 통해서 오늘 날짜 기준으로 띠별, 별자리별 운세데이터 생성.
    • API_key 정보는 코드안에 넣지 않고 따로 관리 (샘플에선 txt파일로 관리, AWS로 관리하는 방법도 있음)
    • 역활과 목표 전달
      • 역활 (system) 에서는 모델의 마인드셋을 위한 다음을 정의
        • 너는 누구인지 (역할 정의)
        • 무엇을 해야 하는지 (목표/작업 지시)
        • 응답 형식이나 톤, 언어 등 스타일 가이드 (Json 포맷 등 지정)
      • 지침 (instruction, user)
        • 사용자가 모델에게 실제 작업 요청이나 정보 입력을 하는 부분
  • 날짜는 현재 날짜의 월/일을 기준으로 동적으로 생성.

 

2. JSON 변환 및 저장

  • 운세 데이터를 날짜, 제목, 링크, 띠별 내용 구조로 JSON 포맷으로 정리.
  • DB에 저장
    • Json을 MongoDB에 저장 (MongoDB Atlas)
    • 이부분은 샘플에 없음 

 

샘플 코드

import os
from openai import OpenAI
from datetime import datetime
import json

from db import save_contents

# ::::: [def] :::::

# 파일에서 API_KEY 반환
def getApiKeyFromFile () -> str:
    # 현재 스크립트의 디렉토리 경로
    current_directory = os.path.dirname(os.path.abspath(__file__))
    
    # 파일 경로 생성
    file_path = os.path.join(current_directory, "api_key.txt")

    try:
        # 파일 읽기
        with open(file_path, 'r') as file:
            return file.readline().strip()  # 첫 번째 줄 읽기 및 공백 제거
    except FileNotFoundError:
        raise FileNotFoundError("api_key.txt 파일을 찾을 수 없습니다.")
    except Exception as e:
        raise Exception(f"파일 읽기 중 오류가 발생했습니다: {e}") 
    
# 시스템 메시지 세팅
def get_system_message():
    return """
    당신은 운세 전문가 AI입니다.

    아래 두 가지 항목에 대한 오늘의 운세를 JSON 형식으로 생성하십시오:

    1. 띠별 운세 (12간지): 
    - 각 띠(쥐, 소, 호랑이, 토끼, 용, 뱀, 말, 양, 원숭이, 닭, 개, 돼지)에 대해
    - 해당 띠에 속하는 주요 출생 연도별 운세도 포함시켜 주세요. (예: 쥐띠 - 1948, 1960, 1972, 1984, 1996)

    2. 별자리 운세:
    - 양자리, 황소자리, 쌍둥이자리, 게자리, 사자자리, 처녀자리, 천칭자리, 전갈자리, 사수자리, 염소자리, 물병자리, 물고기자리

    반드시 다음 JSON 형태로 응답하세요:

    {
        "date": "YYYYMMDD",
        "horoscope": {
            "chinese_zodiac": {
                "쥐": {
                    "1984": "운세 내용...",
                    "1996": "운세 내용...",
                    ...
                },
                ...
            },
            "zodiac_sign": {
                "양자리": "운세 내용...",
                ...
            }
        }
    }
    """

# instructions 세팅
def get_instructions():
    today = datetime.today().strftime("%Y년 %m월 %d일")
    return f"""
    오늘은 {today}입니다. 위의 형식에 맞게 띠별과 별자리별 운세를 제공해주세요.
    """

# OpenAI API를 사용하여 비용을 계산하는 함수
def calculate_cost(usage, model="gpt-4o"):
    if model == "gpt-4o":
        prompt_cost_per_1k = 0.005
        completion_cost_per_1k = 0.015
    else:
        raise ValueError("지원하지 않는 모델입니다.")

    prompt_tokens = usage.prompt_tokens
    completion_tokens = usage.completion_tokens

    prompt_cost = (prompt_tokens / 1000) * prompt_cost_per_1k
    completion_cost = (completion_tokens / 1000) * completion_cost_per_1k
    total_cost = prompt_cost + completion_cost

    return round(total_cost, 6)

# OpenAI API를 사용하여 오늘의 띠별 및 별자리 운세를 가져오는 함수
def get_daily_horoscope():
    openai_api_key = getApiKeyFromFile()
    client = OpenAI(api_key=openai_api_key)

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": get_system_message()},
            {"role": "user", "content": get_instructions()}
        ]
    )

    usage = response.usage
    print("##### Total costs :", calculate_cost(usage, model="gpt-4o"))

    return response.choices[0].message.content

# respose에서 json 코드 블록이 있다면 제거
def clean_json_response(text: str) -> str:
    """
    OpenAI 응답에서 markdown 코드 블록(```json ... ```)을 제거함
    """
    if text.startswith("```json"):
        text = text.replace("```json", "", 1)
    elif text.startswith("```"):
        text = text.replace("```", "", 1)

    text = text.strip()

    if text.endswith("```"):
        text = text[:-3].strip()

    return text


try:
    result = get_daily_horoscope()
    result_parsed_json = clean_json_response(result)

    parsed = json.loads(result_parsed_json)
    print(json.dumps(parsed, indent=4, ensure_ascii=False))

    save_contents(parsed)

except Exception as e:
    print("오류 발생:", e)

 

 

느낀점

역활만 잘 세팅하면, 너무 편하게 데이터를 추출해준다.

위 샘플에서는 띠별, 별자리별 운세 데이터를 요청했는데,

토큰 수가 좀 많은 편이라 대략 한번 호출에 0.02, 0.03달러 정도가 나온다,

지금 환율로는 30~45원 정도인거 같다.

은근 비싸다.

 

호출해서 DB에 담을거라 하루 한번 호출이겠지만, 토큰이 많은 응답의 경우,

비용을 조심해야겠다