File size: 5,256 Bytes
49ec9dc
 
9e12771
49ec9dc
 
 
 
9e12771
49ec9dc
 
 
 
9e12771
49ec9dc
9e12771
 
 
49ec9dc
9e12771
 
49ec9dc
 
9e12771
49ec9dc
 
 
 
9e12771
49ec9dc
 
 
 
 
 
 
 
9e12771
49ec9dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8b70177
49ec9dc
9e12771
49ec9dc
 
 
 
 
 
 
 
 
 
9e12771
49ec9dc
 
 
9e12771
 
49ec9dc
 
9e12771
49ec9dc
 
 
 
9e12771
 
49ec9dc
 
6b59d85
49ec9dc
 
6b59d85
49ec9dc
 
6b59d85
 
9e12771
6b59d85
9e12771
 
 
 
 
 
 
 
6b59d85
 
 
 
 
49ec9dc
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# img_bot.py
import discord, os, io, re, asyncio, logging, requests, replicate, subprocess
from transformers import pipeline as transformers_pipeline   # λ²ˆμ—­ νŒŒμ΄ν”„λΌμΈ

# ── ν™˜κ²½ λ³€μˆ˜ ────────────────────────────────────────────────
TOKEN       = os.getenv("DISCORD_TOKEN")                     # Discord 봇 토큰
CHANNEL_ID  = int(os.getenv("DISCORD_CHANNEL_ID"))           # κ°μ‹œν•  채널 ID
REPL_TOKEN  = (os.getenv("OPENAI_API_KEY") or "").strip()    # Replicate 토큰(동일 λ³€μˆ˜ μ‚¬μš©)
HF_TOKEN    = (os.getenv("HF_TOKEN") or "").strip()          # Hugging Face Personal Access Token

if not TOKEN or not CHANNEL_ID:
    raise RuntimeError("DISCORD_TOKEN κ³Ό DISCORD_CHANNEL_ID ν™˜κ²½ λ³€μˆ˜λ₯Ό λͺ¨λ‘ μ§€μ •ν•˜μ„Έμš”.")

if not REPL_TOKEN:
    raise RuntimeError(
        "OPENAI_API_KEY ν™˜κ²½ λ³€μˆ˜μ— Replicate Personal Access Token 값을 λ„£μ–΄μ£Όμ„Έμš”."
    )

# Replicate λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ°Έμ‘°ν•˜λ„λ‘ 토큰 μ£Όμž…
os.environ["REPLICATE_API_TOKEN"] = REPL_TOKEN

# ── λͺ¨λΈ ────────────────────────────────────────────────────
MODEL = "luma/ray-flash-2-540p"  # ν…μŠ€νŠΈ-투-λΉ„λ””μ˜€ λͺ¨λΈ (540p)

# ── λ²ˆμ—­ νŒŒμ΄ν”„λΌμΈ (CPU) ───────────────────────────────────
translator_kwargs = {"device": -1}
if HF_TOKEN:
    translator_kwargs["token"] = HF_TOKEN        # 인증 토큰 전달

translator = transformers_pipeline(
    "translation",
    model="Helsinki-NLP/opus-mt-ko-en",
    **translator_kwargs
)

def ko2en(text: str) -> str:
    """ν•œκΈ€ 포함 μ‹œ μ˜μ–΄ λ²ˆμ—­, κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ 원문 λ°˜ν™˜."""
    if re.search(r"[κ°€-힣]", text):
        try:
            return translator(text, max_length=512)[0]["translation_text"].strip()
        except Exception as e:
            logging.warning(f"λ²ˆμ—­ μ‹€νŒ¨, 원문 μ‚¬μš©: {e}")
    return text

# ── λ‘œκΉ… ────────────────────────────────────────────────────
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[logging.StreamHandler()]
)

# ── Discord μ„€μ • ────────────────────────────────────────────
intents = discord.Intents.default()
intents.message_content = True  # λ©”μ‹œμ§€ μ½˜ν…μΈ  읽기

class ImageBot(discord.Client):  # 이름 μœ μ§€
    async def on_ready(self):
        logging.info(f"Logged in as {self.user} (id={self.user.id})")
        # web.py 병렬 μ‹€ν–‰
        try:
            subprocess.Popen(["python", "web.py"])
            logging.info("web.py server has been started.")
        except Exception as e:
            logging.warning(f"web.py μ‹€ν–‰ μ‹€νŒ¨: {e}")

    async def on_message(self, message: discord.Message):
        # 봇 μžμ‹ μ˜ λ©”μ‹œμ§€ ν˜Ήμ€ λŒ€μƒ μ•„λ‹Œ 채널 β†’ λ¬΄μ‹œ
        if message.author.id == self.user.id or message.channel.id != CHANNEL_ID:
            return

        prompt = message.content.strip()
        if not prompt:
            return

        prompt_en = ko2en(prompt)  # ν•œκΈ€μ΄λ©΄ μ˜μ–΄λ‘œ λ³€ν™˜
        await message.channel.typing()

        # ── Replicate 호좜 ──────────────────────────────────
        def run_replicate():
            # ν•„μš”ν•œ 경우 input λ”•μ…”λ„ˆλ¦¬μ— duration, seed λ“± μΆ”κ°€ κ°€λŠ₯
            return replicate.run(MODEL, input={"prompt": prompt_en})

        try:
            output = await asyncio.get_running_loop().run_in_executor(None, run_replicate)
        except Exception as e:
            logging.error(f"Replicate error: {e}")
            await message.reply("⚠️ λΉ„λ””μ˜€ 생성 μ‹€νŒ¨!")
            return

        # ── λΉ„λ””μ˜€ Discord 전솑 ─────────────────────────────
        try:
            # replicate.run κ²°κ³Όκ°€ list/tuple 이면 첫 번째 μš”μ†Œ μ‚¬μš©
            if isinstance(output, (list, tuple)):
                output = output[0]

            # URL(str) β†’ λ‹€μš΄λ‘œλ“œ, bytes/file-like β†’ κ·ΈλŒ€λ‘œ
            if isinstance(output, str):
                data = requests.get(output).content
            else:
                data = output.read() if hasattr(output, "read") else output

            video_file = discord.File(io.BytesIO(data), filename="output.mp4")
            await message.reply(files=[video_file])
        except Exception as e:
            logging.warning(f"λΉ„λ””μ˜€ 처리 μ‹€νŒ¨: {e}")
            await message.reply("⚠️ λΉ„λ””μ˜€λ₯Ό 전솑할 수 μ—†μŠ΅λ‹ˆλ‹€.")

# ── μ‹€ν–‰ ────────────────────────────────────────────────────
if __name__ == "__main__":
    replicate.Client(api_token=REPL_TOKEN)  # Replicate 인증
    ImageBot(intents=intents).run(TOKEN)