Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# img_bot.py
|
2 |
+
import discord, os, io, re, asyncio, logging, requests, replicate, subprocess
|
3 |
+
from transformers import pipeline as transformers_pipeline # λ²μ νμ΄νλΌμΈ
|
4 |
+
|
5 |
+
# ββ νκ²½ λ³μ ββββββββββββββββββββββββββββββββββββββββββββββββ
|
6 |
+
TOKEN = os.getenv("DISCORD_TOKEN") # Discord λ΄ ν ν°
|
7 |
+
CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID")) # κ°μν μ±λ ID
|
8 |
+
REPL_TOKEN = (os.getenv("OPENAI_API_KEY") or "").strip() # Replicate ν ν°(λμΌ λ³μ μ¬μ©)
|
9 |
+
HF_TOKEN = (os.getenv("HF_TOKEN") or "").strip() # Hugging Face Personal Access Token
|
10 |
+
|
11 |
+
if not TOKEN or not CHANNEL_ID:
|
12 |
+
raise RuntimeError("DISCORD_TOKEN κ³Ό DISCORD_CHANNEL_ID νκ²½ λ³μλ₯Ό λͺ¨λ μ§μ νμΈμ.")
|
13 |
+
|
14 |
+
if not REPL_TOKEN:
|
15 |
+
raise RuntimeError(
|
16 |
+
"OPENAI_API_KEY νκ²½ λ³μμ Replicate Personal Access Token κ°μ λ£μ΄μ£ΌμΈμ."
|
17 |
+
)
|
18 |
+
|
19 |
+
# Replicate λΌμ΄λΈλ¬λ¦¬κ° μ°Έμ‘°νλλ‘ ν ν° μ£Όμ
|
20 |
+
os.environ["REPLICATE_API_TOKEN"] = REPL_TOKEN
|
21 |
+
|
22 |
+
# ββ λͺ¨λΈ ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
23 |
+
MODEL = (
|
24 |
+
"bytedance/sdxl-lightning-4step:"
|
25 |
+
"6f7a773af6fc3e8de9d5a3c00be77c17308914bf67772726aff83496ba1e3bbe"
|
26 |
+
)
|
27 |
+
|
28 |
+
# ββ λ²μ νμ΄νλΌμΈ (CPU) βββββββββββββββββββββββββββββββββββ
|
29 |
+
translator_kwargs = {"device": -1}
|
30 |
+
if HF_TOKEN:
|
31 |
+
translator_kwargs["token"] = HF_TOKEN # μΈμ¦ ν ν° μ λ¬
|
32 |
+
|
33 |
+
translator = transformers_pipeline(
|
34 |
+
"translation",
|
35 |
+
model="Helsinki-NLP/opus-mt-ko-en",
|
36 |
+
**translator_kwargs
|
37 |
+
)
|
38 |
+
|
39 |
+
def ko2en(text: str) -> str:
|
40 |
+
"""νκΈ ν¬ν¨ μ μμ΄ λ²μ, κ·Έλ μ§ μμΌλ©΄ μλ¬Έ λ°ν."""
|
41 |
+
if re.search(r"[κ°-ν£]", text):
|
42 |
+
try:
|
43 |
+
return translator(text, max_length=512)[0]["translation_text"].strip()
|
44 |
+
except Exception as e:
|
45 |
+
logging.warning(f"λ²μ μ€ν¨, μλ¬Έ μ¬μ©: {e}")
|
46 |
+
return text
|
47 |
+
|
48 |
+
# ββ λ‘κΉ
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
49 |
+
logging.basicConfig(
|
50 |
+
level=logging.INFO,
|
51 |
+
format="%(asctime)s [%(levelname)s] %(message)s",
|
52 |
+
handlers=[logging.StreamHandler()]
|
53 |
+
)
|
54 |
+
|
55 |
+
# ββ Discord μ€μ ββββββββββββββββββββββββββββββββββββββββββββ
|
56 |
+
intents = discord.Intents.default()
|
57 |
+
intents.message_content = True # λ©μμ§ μ½ν
μΈ μ½κΈ°
|
58 |
+
|
59 |
+
class ImageBot(discord.Client):
|
60 |
+
async def on_ready(self):
|
61 |
+
logging.info(f"Logged in as {self.user} (id={self.user.id})")
|
62 |
+
# web.py λ³λ ¬ μ€ν
|
63 |
+
try:
|
64 |
+
subprocess.Popen(["python", "web.py"])
|
65 |
+
logging.info("web.py server has been started.")
|
66 |
+
except Exception as e:
|
67 |
+
logging.warning(f"web.py μ€ν μ€ν¨: {e}")
|
68 |
+
|
69 |
+
async def on_message(self, message: discord.Message):
|
70 |
+
# λ΄ μμ μ λ©μμ§ νΉμ λμ μλ μ±λ β 무μ
|
71 |
+
if message.author.id == self.user.id or message.channel.id != CHANNEL_ID:
|
72 |
+
return
|
73 |
+
|
74 |
+
prompt = message.content.strip()
|
75 |
+
if not prompt:
|
76 |
+
return
|
77 |
+
|
78 |
+
prompt_en = ko2en(prompt) # νκΈμ΄λ©΄ μμ΄λ‘ λ³ν
|
79 |
+
await message.channel.typing()
|
80 |
+
|
81 |
+
# ββ Replicate νΈμΆ ββββββββββββββββββββββββββββββββββ
|
82 |
+
def run_replicate():
|
83 |
+
return list(replicate.run(MODEL, input={"prompt": prompt_en}))
|
84 |
+
|
85 |
+
try:
|
86 |
+
images = await asyncio.get_running_loop().run_in_executor(None, run_replicate)
|
87 |
+
except Exception as e:
|
88 |
+
logging.error(f"Replicate error: {e}")
|
89 |
+
await message.reply("β οΈ μ΄λ―Έμ§ μμ± μ€ν¨!")
|
90 |
+
return
|
91 |
+
|
92 |
+
# ββ μ΄λ―Έμ§ Discord μ μ‘ βββββββββββββββββββββββββββββ
|
93 |
+
files = []
|
94 |
+
for idx, item in enumerate(images):
|
95 |
+
try:
|
96 |
+
data = item.read() if hasattr(item, "read") else requests.get(item).content
|
97 |
+
files.append(discord.File(io.BytesIO(data), filename=f"img_{idx}.png"))
|
98 |
+
except Exception as e:
|
99 |
+
logging.warning(f"[IMG {idx}] μ²λ¦¬ μ€ν¨: {e}")
|
100 |
+
|
101 |
+
await message.reply(
|
102 |
+
files=files if files else None,
|
103 |
+
content=None if files else "β οΈ μ΄λ―Έμ§λ₯Ό μ μ‘ν μ μμ΅λλ€."
|
104 |
+
)
|
105 |
+
|
106 |
+
# ββ μ€ν ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
107 |
+
if __name__ == "__main__":
|
108 |
+
replicate.Client(api_token=REPL_TOKEN) # Replicate μΈμ¦
|
109 |
+
ImageBot(intents=intents).run(TOKEN)
|