연간 $1.75에 네온에 물든 Last.fm Roast Bot 만들기

발행: (2026년 1월 16일 오전 07:04 GMT+9)
9 min read
원문: Dev.to

Source: Dev.to

위에 제공된 Source 링크만으로는 번역할 본문 내용을 확인할 수 없습니다. 번역이 필요한 전체 텍스트(코드 블록을 제외한 본문)를 복사해서 알려주시면, 요청하신 대로 한국어로 번역해 드리겠습니다.

Bot 만들기 🤖

Poe에 가서 그들의 ScriptBot 기능을 사용해 새로운 봇을 만들었습니다. 대략 다음과 같은 특정 시스템 프롬프트를 제공했습니다:

“당신은 허세 부리는 음악 평론가입니다. 당신의 일은 Last.fm 프로필을 분석하고 가차 없이 비난하는 것입니다. 비꼬고, 속어를 사용하며, 절대 물러서지 마세요.”

ScriptBot과 여러 차례 반복 작업을 거쳐 결과에 만족할 때까지 진행한 뒤, 저는 인텔리전스(lastfm-roaster)를 얻었지만, Poe에서 나온 출력을 제 이메일로 전달해야 했습니다.

Poe bot screenshot

Keys and Secrets 🗝️

우리는 GitHub Actions를 사용해 이 작업을 실행할 예정이며, API 키를 안전하게 보관해야 합니다. 스크립트에 비밀번호를 직접 하드코딩하지 마세요!

1️⃣ 키 가져오기

얻는 방법
Poe API Key로 이동하여 키를 복사합니다.
Gmail App PasswordGoogle 계정 → 보안 → 2단계 인증 → 앱 비밀번호에서 “Mail”용 16자리 비밀번호를 생성합니다.

2️⃣ GitHub에 저장하기

  1. GitHub에서 비공개 새 저장소를 만듭니다.
  2. Settings → Secrets and variables → Actions 로 이동합니다.
  3. 다음 세 개의 시크릿을 추가합니다:
  • POE_API_KEY
  • EMAIL_ADDRESS
  • EMAIL_PASSWORD

GitHub 시크릿 스크린샷

3단계: 코드 🐍

requirements.txt

openai
markdown

(네, 우리는 openai를 사용합니다! Poe의 API는 OpenAI 클라이언트와 호환되어 사용이 매우 간편합니다. Gemini 2.5 Flash는 Poe API를 통해 참조되므로 별도의 키를 관리할 필요가 없습니다.)

“Neon” 스크립트 – lastfm_roast.py

import os
import smtplib
import markdown
import re
import itertools
from email.message import EmailMessage
from openai import OpenAI

# Configs (loaded safely from GitHub Secrets)
POE_API_KEY = os.environ.get("POE_API_KEY")
EMAIL_ADDRESS = os.environ.get("EMAIL_ADDRESS")
EMAIL_PASSWORD = os.environ.get("EMAIL_PASSWORD")
LASTFM_URL = "https://www.last.fm/user/profoundlypaige"

# --- NEON PALETTE ---
# A list of bright colors that look good on dark backgrounds
# (Pink, Cyan, Green, Orange, Purple, Yellow)
COLORS = ["#FF79C6", "#8BE9FD", "#50FA7B", "#FFB86C", "#BD93F9", "#F1FA8C"]

def get_roast():
    """Pings the Poe API to get the roast."""
    client = OpenAI(api_key=POE_API_KEY, base_url="https://api.poe.com/v1")
    try:
        print("🔥 Fetching roast from Poe...")
        response = client.chat.completions.create(
            model="lastfm-roaster",
            messages=[{"role": "user", "content": f"Roast my music taste: {LASTFM_URL}"}],
        )
        return response.choices[0].message.content
    except Exception as e:
        return f"Error fetching roast: {e}"

def inject_colors(html_content):
    """
    Finds every <b> tag and injects a different color from the palette.
    """
    color_cycle = itertools.cycle(COLORS)

    def replace_match(match):
        next_color = next(color_cycle)
        # Returns <b style="color: #...">...</b>
        return f''

    # Regex to replace <b> with the colored version
    return re.sub(r'', replace_match, html_content)

def create_html_email(roast_text):
    # 1. Convert Markdown to basic HTML
    raw_html = markdown.markdown(roast_text)

    # 2. Inject the rotating neon colors into bold tags
    colorful_html = inject_colors(raw_html)

    # 3. Wrap in the styled container
    html_template = f"""
    
    
    
    
        body {{ margin: 0; padding: 0; background-color: #121212; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; }}
        .container {{
            max-width: 600px;
            margin: 40px auto;
            background-color: #1e1e1e;
            border-radius: 8px;
            padding: 20px;
            color: #f8f8f2;
        }}
        a {{ color: #8be9fd; }}
    
    
    
        
            {colorful_html}
        
    
    
    """
    return html_template

def send_email(html_content):
    msg = EmailMessage()
    msg["Subject"] = "Your Daily Last.fm Roast"
    msg["From"] = EMAIL_ADDRESS
    msg["To"] = EMAIL_ADDRESS
    msg.set_content("Your email client does not support HTML.", subtype="plain")
    msg.add_alternative(html_content, subtype="html")

    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp:
        smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
        smtp.send_message(msg)
        print("📧 Email sent!")

if __name__ == "__main__":
    roast = get_roast()
    html_email = create_html_email(roast)
    send_email(html_email)

GitHub Actions 워크플로우

.github/workflows/roast.yml 파일을 생성합니다:

name: Daily Last.fm Roast

on:
  schedule:
    - cron: "0 8 * * *"   # Runs every day at 08:00 UTC
  workflow_dispatch:      # Allows manual runs

jobs:
  roast:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Run roast script
        env:
          POE_API_KEY: ${{ secrets.POE_API_KEY }}
          EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }}
          EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }}
        run: python lastfm_roast.py

TL;DR

  1. Create a Poe ScriptBot (lastfm-roaster).
  2. Store API keys in GitHub Secrets.
  3. Write lastfm_roast.py – fetches a roast, injects neon colors, and emails it.
  4. Add a GitHub Actions workflow to run the script daily.

이제는 그 부끄러운 트랙을 숨길 필요가 없습니다 – 매일 풍자적이고 색상이 튀는 굴욕을 한 번씩 받아서 친구들과 공유할 수 있습니다. 즐기세요!

정리된 마크다운 내용

CSS 및 HTML 템플릿

    .container {
        max-width: 800px;
        margin: 0 auto;
        background: #1e1e1e;
        color: #d1d5db;
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        border-radius: 16px;
        overflow: hidden;
        box-shadow: 0 10px 30px rgba(0,0,0,0.5);
        border: 1px solid #333;
    }

    .header {
        background: linear-gradient(135deg, #2b2b2b 0%, #1a1a1a 100%);
        padding: 30px;
        text-align: center;
        border-bottom: 2px solid #333;
    }

    /* Gradient title text */
    .header h1 {
        margin: 0;
        font-size: 28px;
        letter-spacing: 2px;
        text-transform: uppercase;
        background: -webkit-linear-gradient(#FF79C6, #8BE9FD);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .content {
        padding: 30px;
        color: #d1d5db;
        line-height: 1.7;
        font-size: 16px;
    }

    h2 {
        color: #ffffff;
        border-left: 5px solid #BD93F9; /* Purple accent */
        padding-left: 15px;
        margin-top: 30px;
        text-transform: uppercase;
        font-size: 18px;
        letter-spacing: 1px;
    }

    ul { padding-left: 20px; }
    li { margin-bottom: 10px; }

    /* Link styles */
    a {
        color: #8BE9FD;
        text-decoration: none;
        border-bottom: 1px dotted #8BE9FD;
    }

    .footer {
        background-color: #121212;
        padding: 20px;
        text-align: center;
        font-size: 12px;
        color: #555;
    }

Source: … (keep this line exactly as it appears in the original)

🔥 데일리 번

{colorful_html}

Poe API, Gemini 2.5 Flash, 그리고 GitHub Actions가 신선하게 제공됩니다.

당신의 비극적인 Last.fm 프로필 보기

파이썬 이메일 전송 스크립트

def create_html_email(roast_text):
    html_template = f"""
    
    
    
        
        Daily Roast
        {CSS_BLOCK}
    
    
        
            
                

🔥 일일 번

            {colorful_html}
        
        
            Poe API, Gemini 2.5 Flash, 그리고 GitHub Actions가 신선하게 제공됩니다

            [당신의 비극적인 Last.fm 프로필 보기]({LASTFM_URL})
        
    


"""
return html_template

def send_email(roast_text): msg = EmailMessage() msg[“Subject”] = “Your Daily Last.fm Roast 🎸” msg[“From”] = EMAIL_ADDRESS msg[“To”] = EMAIL_ADDRESS msg.set_content(roast_text) msg.add_alternative(create_html_email(roast_text), subtype=‘html’)

try:
    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp:
        smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
        smtp.send_message(msg)
    print("✅ Email sent successfully!")
except Exception as e:
    print(f"❌ Failed to send email: {e}")

if name == “main”: roast = get_roast() send_email(roast)


### GitHub Actions로 자동화 🤖  

Create `.github/workflows/daily_roast.yml`:

```yaml
name: Daily Lastfm Roast
on:
  schedule:
    - cron: '0 12 * * *' # Noon UTC, every day

jobs:
  roast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: '3.9'
      - run: pip install -r requirements.txt
      - run: python lastfm_roast.py
        env:
          POE_API_KEY: ${{ secrets.POE_API_KEY }}
          EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }}
          EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }}

이게 가치 있을까? 💸

This is my favorite part. Poe charges Compute Points to run the model (I used Gemini 2.5 Flash). After a few test runs I logged the costs:

지표
모델Gemini 2.5 Flash
요청당 비용~161 Compute Points
달러 비용~$0.0048 per roast

연간 비용:

$0.0048 × 365 days = $1.75

$1.75 per year – 2달러도 안 되는 비용으로 최첨단 LLM을 이용해 청취 트렌드를 분석하고, 매일 아침 당신의 인디 팝 취향이 “파생되고 슬프다”고 말해줍니다. 높은 ROI! 📈

결과: 전과 후

전 (채팅 인터페이스):

  • 앱에 갇혀 있음.
  • 공유하기 어려움.
  • 단순 마크다운 텍스트.

후 (네온 업그레이드):

Neon email card

이제 이메일은 세련된 다크‑모드 카드 형태로 표시됩니다. 밴드 이름(조롱 대상)은 핑크, 시안, 그린으로 강조되어 누구를 비난당하고 있는지 한눈에 파악할 수 있습니다. 이메일이기 때문에 로스트를 바로 친구에게 전달해 그들도 당신의 고통을 함께 웃을 수 있습니다.

마무리

# (Custom Bot + API + HTML Generation + Actions)

This is my go‑to setup for almost all of my personal automation. It’s robust, free to host, and creates genuinely fun daily interactions.

언급된 저장소


시도해 보셨다면 댓글로 알려주시거나, AI가 만든 최악의 로스트를 공유해주세요. 즐거운 코딩 되세요! ✨

Back to Blog

관련 글

더 보기 »

기술은 구원자가 아니라 촉진자다

왜 사고의 명확성이 사용하는 도구보다 더 중요한가? Technology는 종종 마법 스위치처럼 취급된다—켜기만 하면 모든 것이 개선된다. 새로운 software, ...

에이전틱 코딩에 입문하기

Copilot Agent와의 경험 나는 주로 GitHub Copilot을 사용해 인라인 편집과 PR 리뷰를 수행했으며, 대부분의 사고는 내 머리로 했습니다. 최근 나는 t...