File size: 5,025 Bytes
49ec9dc
 
898a986
49ec9dc
 
898a986
 
9d6ae27
 
 
49ec9dc
 
 
 
898a986
49ec9dc
9d6ae27
49ec9dc
0b58fc4
 
49ec9dc
 
 
 
0b58fc4
49ec9dc
9d6ae27
49ec9dc
 
 
9d6ae27
49ec9dc
 
 
 
 
 
 
 
9d6ae27
 
49ec9dc
9d6ae27
49ec9dc
9d6ae27
 
 
 
 
 
49ec9dc
 
 
 
 
 
 
 
 
 
 
 
9d6ae27
 
 
49ec9dc
 
 
2edcd19
 
49ec9dc
 
9d6ae27
49ec9dc
 
9d6ae27
49ec9dc
9d6ae27
49ec9dc
 
 
 
 
 
 
 
9d6ae27
49ec9dc
 
 
 
0b58fc4
49ec9dc
 
 
9d6ae27
 
49ec9dc
 
 
9d6ae27
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
# 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 토큰
USE_MSG_INTENT = os.getenv("MESSAGE_CONTENT_INTENT", "1") != "0"  # 1=ON(κΈ°λ³Έ), 0=OFF

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 값을 λ„£μ–΄μ£Όμ„Έμš”.")

os.environ["REPLICATE_API_TOKEN"] = REPL_TOKEN       # Replicate κ°€ μ°Έμ‘°ν•  토큰

# ── 이미지 생성 λͺ¨λΈ (Flux Schnell) ─────────────────────────
MODEL = "black-forest-labs/flux-schnell"

# ── λ²ˆμ—­ νŒŒμ΄ν”„λΌμΈ (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")

# ── Discord μΈν…νŠΈ μ„€μ • ────────────────────────────────────
intents = discord.Intents.default()
if USE_MSG_INTENT:
    intents.message_content = True
    logging.info("Message Content Intent = ON  "
                 "(Developer Portal β†’ Bot β†’ Privileged Intents μ—μ„œ ON ν•„μš”)")
else:
    logging.info("Message Content Intent = OFF  (MESSAGE_CONTENT_INTENT=0)")

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 not USE_MSG_INTENT:
            return
        if message.author.id == self.user.id or message.channel.id != CHANNEL_ID:
            return

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

        prompt_en = ko2en(prompt_raw)
        await message.channel.typing()

        # ── Replicate μš”μ²­ ─────────────────────────────────
        def run_replicate():
            return list(replicate.run(MODEL, input={"prompt": prompt_en}))

        try:
            images = 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 전솑 ──────────────────────────────────
        files = []
        for idx, item in enumerate(images):
            try:
                data = item.read() if hasattr(item, "read") else requests.get(item).content
                files.append(discord.File(io.BytesIO(data), filename=f"img_{idx}.webp"))
            except Exception as e:
                logging.warning(f"[IMG {idx}] 처리 μ‹€νŒ¨: {e}")

        await message.reply(files=files if files else None,
                            content=None if files else "⚠️ 이미지λ₯Ό 전솑할 수 μ—†μŠ΅λ‹ˆλ‹€.")

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