File size: 4,998 Bytes
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 |
# 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 = (
"bytedance/sdxl-lightning-4step:"
"6f7a773af6fc3e8de9d5a3c00be77c17308914bf67772726aff83496ba1e3bbe"
)
# ββ λ²μ νμ΄νλΌμΈ (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():
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}.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) # Replicate μΈμ¦
ImageBot(intents=intents).run(TOKEN)
|