File size: 4,009 Bytes
dedc913
3a2e476
407a575
5601761
 
 
 
dedc913
5601761
 
 
 
 
 
 
 
 
 
 
 
dedc913
 
 
 
 
5601761
3a2e476
 
 
 
 
440418c
5601761
440418c
5601761
08baccf
dedc913
 
 
5601761
3a2e476
 
 
 
 
74ccf1c
dedc913
5601761
dedc913
 
12bb502
dedc913
 
 
e882cc6
dedc913
e882cc6
5601761
dedc913
 
4261e38
dc80b35
5601761
 
 
4261e38
dedc913
 
 
4261e38
5601761
dedc913
 
 
 
 
 
3a2e476
4261e38
5601761
 
 
 
0926d14
5601761
34428f1
5601761
dedc913
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
# img_bot.py
import discord, os, io, asyncio, logging, requests, replicate, subprocess

# ── ν™˜κ²½ λ³€μˆ˜ ────────────────────────────────────────────────
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 토큰(동일 λ³€μˆ˜ μ‚¬μš©)

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 = (
    "bytedance/sdxl-lightning-4step:"
    "6f7a773af6fc3e8de9d5a3c00be77c17308914bf67772726aff83496ba1e3bbe"
)

# ── λ‘œκΉ… ────────────────────────────────────────────────────
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

        await message.channel.typing()

        # ── Replicate 호좜 ──────────────────────────────────
        def run_replicate():
            return list(replicate.run(MODEL, input={"prompt": prompt}))

        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}.png"))
            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)  # 인증
    ImageBot(intents=intents).run(TOKEN)