File size: 5,868 Bytes
49ec9dc
b0940a1
 
7b7fd88
b0940a1
49ec9dc
 
444fc48
 
 
 
49ec9dc
 
 
 
7b7fd88
49ec9dc
3241add
49ec9dc
7b7fd88
554c43d
 
49ec9dc
c80bb75
49ec9dc
7b7fd88
 
 
 
49ec9dc
 
444fc48
 
 
 
 
c80bb75
444fc48
 
 
 
 
 
49ec9dc
 
9d6ae27
3241add
 
49ec9dc
ded0e5f
49ec9dc
b0940a1
49ec9dc
 
 
 
 
 
 
 
 
 
 
 
 
7b7fd88
2edcd19
 
49ec9dc
 
c80bb75
49ec9dc
 
c80bb75
6659834
 
444fc48
c80bb75
b6dfa24
b0940a1
 
b6dfa24
444fc48
6659834
b0940a1
49ec9dc
 
6659834
b0940a1
49ec9dc
6659834
49ec9dc
 
 
7b7fd88
49ec9dc
b0940a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49ec9dc
c80bb75
 
 
 
49ec9dc
 
 
b0940a1
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# img_bot.py
import discord, os, io, re, random, asyncio, logging, requests, replicate, subprocess, base64
from urllib.parse import urljoin
from transformers import pipeline as transformers_pipeline
from gradio_client import Client

# ── ν™˜κ²½ λ³€μˆ˜ ────────────────────────────────────────────────
TOKEN       = os.getenv("DISCORD_TOKEN")
CHANNEL_ID  = int(os.getenv("DISCORD_CHANNEL_ID"))
REPL_TOKEN  = (os.getenv("OPENAI_API_KEY") or "").strip()
HF_TOKEN    = (os.getenv("HF_TOKEN") or "").strip()

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 λ―Έμ‚¬μš©)

# ── Gradio μ„œλ²„ ─────────────────────────────────────────────
GRADIO_URL  = "http://211.233.58.201:7971"
GRADIO_API  = "/process_and_save_image"

# ── λ²ˆμ—­ νŒŒμ΄ν”„λΌμΈ (CPU) ───────────────────────────────────
translator = transformers_pipeline(
    "translation",
    model="Helsinki-NLP/opus-mt-ko-en",
    device=-1,
    **({"token": HF_TOKEN} if HF_TOKEN else {})
)

async def ko2en_async(text: str) -> str:
    if not re.search(r"[κ°€-힣]", text):
        return text
    loop = asyncio.get_running_loop()
    try:
        return await loop.run_in_executor(
            None,
            lambda: translator(text, max_length=256, num_beams=1)[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})")
        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_raw = message.content.strip()
        if not prompt_raw:
            return

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

        # ── Gradio 호좜 ────────────────────────────────────
        def generate_image():
            client = Client(GRADIO_URL)
            return client.predict(
                height=768,
                width=768,
                steps=30,
                scales=3.5,
                prompt=prompt_en,
                seed=random.randint(0, 2**32 - 1),
                api_name=GRADIO_API
            )[0]  # list β†’ dict

        try:
            img_info = await asyncio.get_running_loop().run_in_executor(None, generate_image)
            logging.info(f"Gradio result: {img_info}")
        except Exception as e:
            logging.error(f"Gradio API error: {e}")
            await message.reply("⚠️ 이미지 생성 μ‹€νŒ¨!")
            return

        # ── Discord 전솑 ──────────────────────────────────
        files = []
        data = None

        # 1️⃣ url ν•„λ“œ μš°μ„ 
        url = img_info.get("url")
        if url:
            if url.startswith("data:"):  # base64 data URI
                b64 = re.sub(r"^data:image/[^;]+;base64,", "", url)
                try:
                    data = base64.b64decode(b64)
                except Exception as e:
                    logging.warning(f"base64 λ””μ½”λ”© μ‹€νŒ¨: {e}")
            else:
                if url.startswith("/"):  # μƒλŒ€ URL
                    url = urljoin(GRADIO_URL, url)
                try:
                    data = requests.get(url, timeout=10).content
                except Exception as e:
                    logging.warning(f"URL λ‹€μš΄λ‘œλ“œ μ‹€νŒ¨: {e}")

        # 2️⃣ path ν•„λ“œ (파일 μ‘΄μž¬ν•  λ•Œλ§Œ)
        if data is None:
            path = img_info.get("path")
            if path and os.path.isfile(path):
                try:
                    with open(path, "rb") as f:
                        data = f.read()
                except Exception as e:
                    logging.warning(f"파일 μ—΄κΈ° μ‹€νŒ¨: {e}")

        if data:
            files.append(discord.File(io.BytesIO(data), filename="generated.webp"))

        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)