fantos's picture
Update app.py
6659834 verified
raw
history blame
5.74 kB
# img_bot.py
import discord, os, io, re, random, asyncio, logging, requests, replicate, subprocess
from transformers import pipeline as transformers_pipeline # λ²ˆμ—­ νŒŒμ΄ν”„λΌμΈ
from gradio_client import Client, handle_file # NEW ─ Gradio API
# ── ν™˜κ²½ λ³€μˆ˜ ────────────────────────────────────────────────
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
# ── Gradio μ„œλ²„ μ—”λ“œν¬μΈνŠΈ ──────────────────────────────────
GRADIO_URL = "http://211.233.58.201:7896" # μ„œλ²„ μ£Όμ†Œ
GRADIO_API = "/generate_image" # μ‚¬μš©ν•  ν•¨μˆ˜ 이름
# ── λ²ˆμ—­ νŒŒμ΄ν”„λΌμΈ (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()
intents.message_content = True # λ©”μ‹œμ§€ 읽기 (Portalμ—μ„œ ON ν•„μš”)
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_raw = message.content.strip()
if not prompt_raw:
return
prompt_en = ko2en(prompt_raw) # ν•œκΈ€ β†’ μ˜μ–΄
await message.channel.typing()
# ── Gradio 호좜 ────────────────────────────────────
def generate_image():
client = Client(GRADIO_URL)
seed = random.randint(0, 2**32 - 1)
result = client.predict(
prompt=prompt_en,
width=768,
height=768,
guidance=3.5,
inference_steps=30,
seed=seed,
do_img2img=False,
init_image=None, # img2img μ‚¬μš© μ•ˆ 함
image2image_strength=0.8,
resize_img=True,
api_name=GRADIO_API
)
return result[0] # dict (path / url)
try:
img_info = await asyncio.get_running_loop().run_in_executor(None, generate_image)
except Exception as e:
logging.error(f"Gradio API error: {e}")
await message.reply("⚠️ 이미지 생성 μ‹€νŒ¨!")
return
# ── 이미지 Discord 전솑 ─────────────────────────────
files = []
try:
if img_info.get("path"): # μ„œλ²„κ°€ 파일 경둜둜 λ°˜ν™˜
with open(img_info["path"], "rb") as f:
files.append(discord.File(io.BytesIO(f.read()), filename="generated.webp"))
elif img_info.get("url"): # URL λ˜λŠ” base64
data = requests.get(img_info["url"]).content
files.append(discord.File(io.BytesIO(data), filename="generated.webp"))
except Exception as e:
logging.warning(f"이미지 처리 μ‹€νŒ¨: {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)