fantos commited on
Commit
c3a9e90
·
verified ·
1 Parent(s): 2cfdf65

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -72
app.py CHANGED
@@ -1,10 +1,15 @@
1
  # img_bot.py
2
- import discord, os, io, re, random, asyncio, logging, requests, replicate, subprocess, base64
3
  from urllib.parse import urljoin, quote_plus
 
 
 
 
4
  from transformers import pipeline as transformers_pipeline
5
  from gradio_client import Client
 
6
 
7
- # ── 환경 변수 ────────────────────────────────────────────────
8
  TOKEN = os.getenv("DISCORD_TOKEN")
9
  CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
10
  REPL_TOKEN = (os.getenv("OPENAI_API_KEY") or "").strip()
@@ -14,14 +19,13 @@ if not TOKEN or not CHANNEL_ID:
14
  raise RuntimeError("DISCORD_TOKEN 과 DISCORD_CHANNEL_ID 환경 변수를 모두 지정하세요.")
15
  if not REPL_TOKEN:
16
  raise RuntimeError("OPENAI_API_KEY 에 Replicate Personal Access Token 값을 넣어주세요.")
 
17
 
18
- os.environ["REPLICATE_API_TOKEN"] = REPL_TOKEN # 구조 유지 (Replicate 미사용)
19
-
20
- # ── Gradio 서버 ─────────────────────────────────────────────
21
- GRADIO_URL = "http://211.233.58.201:7971"
22
- GRADIO_API = "/process_and_save_image"
23
 
24
- # ── 번역 파이프라인 (CPU) ───────────────────────────────────
25
  translator = transformers_pipeline(
26
  "translation",
27
  model="Helsinki-NLP/opus-mt-ko-en",
@@ -30,7 +34,7 @@ translator = transformers_pipeline(
30
  )
31
 
32
  async def ko2en_async(text: str) -> str:
33
- """한글 포함 시 비동기 영어 번역."""
34
  if not re.search(r"[가-힣]", text):
35
  return text
36
  loop = asyncio.get_running_loop()
@@ -43,12 +47,14 @@ async def ko2en_async(text: str) -> str:
43
  logging.warning(f"번역 실패, 원문 사용: {e}")
44
  return text
45
 
46
- # ── 로깅 ────────────────────────────────────────────────────
47
- logging.basicConfig(level=logging.INFO,
 
48
  format="%(asctime)s [%(levelname)s] %(message)s",
49
- handlers=[logging.StreamHandler()])
 
50
 
51
- # ── Discord 인텐트 ──────────────────────────────────────────
52
  intents = discord.Intents.default()
53
  intents.message_content = True
54
 
@@ -72,7 +78,7 @@ class ImageBot(discord.Client):
72
  prompt_en = await ko2en_async(prompt_raw)
73
  await message.channel.typing()
74
 
75
- # ── Gradio 호출 ────────────────────────────────────
76
  def generate_image():
77
  client = Client(GRADIO_URL)
78
  return client.predict(
@@ -83,75 +89,69 @@ class ImageBot(discord.Client):
83
  prompt=prompt_en,
84
  seed=random.randint(0, 2**32 - 1),
85
  api_name=GRADIO_API
86
- ) # ❗ 리스트나 dict·str 그대로 반환
87
 
88
  try:
89
- img_info = await asyncio.get_running_loop().run_in_executor(None, generate_image)
90
- logging.info(f"Gradio result type={type(img_info)} → {img_info}")
91
  except Exception as e:
92
  logging.error(f"Gradio API error: {e}")
93
  await message.reply("⚠️ 이미지 생성 실패!")
94
  return
95
 
96
- # ── Discord 파일 준비 ──────────────────────────────
97
- data = None
98
- filename = "generated.webp"
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
- def download(url: str) -> bytes | None:
101
- try:
102
- return requests.get(url, timeout=10).content
103
- except Exception as err:
104
- logging.warning(f"URL 다운로드 실패({url}): {err}")
105
- return None
106
-
107
- # `img_info` 가 리스트면 첫 요소 사용
108
- if isinstance(img_info, list) and img_info:
109
- img_info = img_info[0]
110
-
111
- # ② dict
112
- if isinstance(img_info, dict):
113
- # url 우선
114
- url = img_info.get("url")
115
- if url:
116
- if url.startswith("data:"):
117
- try:
118
- data = base64.b64decode(re.sub(r"^data:image/[^;]+;base64,", "", url))
119
- except Exception as e:
120
- logging.warning(f"base64 디코딩 실패: {e}")
121
- else:
122
- if url.startswith("/"):
123
- url = urljoin(GRADIO_URL, url)
124
- data = download(url)
125
- # path 보조
126
- if data is None:
127
- path = img_info.get("path")
128
- if path:
129
- # 원격 Gradio 파일 end-point
130
- remote_url = urljoin(GRADIO_URL, f"/gradio_api/file={quote_plus(path)}")
131
- data = download(remote_url) or (open(path, "rb").read() if os.path.isfile(path) else None)
132
-
133
- # ③ str (로컬 경로/URL/data URI)
134
- elif isinstance(img_info, str):
135
- s = img_info.strip()
136
- if s.startswith("data:"):
137
  try:
138
- data = base64.b64decode(re.sub(r"^data:image/[^;]+;base64,", "", s))
139
- except Exception as e:
140
- logging.warning(f"base64 디코딩 실패: {e}")
141
- elif s.startswith("http"):
142
- data = download(s)
143
- else:
144
- # 원격 파일로 간주
145
- remote_url = urljoin(GRADIO_URL, f"/gradio_api/file={quote_plus(s)}")
146
- data = download(remote_url) or (open(s, "rb").read() if os.path.isfile(s) else None)
147
-
148
- # ── Discord 전송 ──────────────────────────────────
149
- if data:
150
- await message.reply(files=[discord.File(io.BytesIO(data), filename=filename)])
151
- else:
152
  await message.reply("⚠️ 이미지를 전송할 수 없습니다.")
 
153
 
154
- # ── 실행 ────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
155
  if __name__ == "__main__":
156
  replicate.Client(api_token=REPL_TOKEN) # 구조 유지
157
  ImageBot(intents=intents).run(TOKEN)
 
1
  # img_bot.py
2
+ import os, io, re, random, asyncio, logging, subprocess, base64
3
  from urllib.parse import urljoin, quote_plus
4
+
5
+ import discord
6
+ import requests
7
+ import replicate
8
  from transformers import pipeline as transformers_pipeline
9
  from gradio_client import Client
10
+ from PIL import Image # WEBP → PNG 변환용
11
 
12
+ # ────────────────── 환경 변수 ──────────────────
13
  TOKEN = os.getenv("DISCORD_TOKEN")
14
  CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
15
  REPL_TOKEN = (os.getenv("OPENAI_API_KEY") or "").strip()
 
19
  raise RuntimeError("DISCORD_TOKEN 과 DISCORD_CHANNEL_ID 환경 변수를 모두 지정하세요.")
20
  if not REPL_TOKEN:
21
  raise RuntimeError("OPENAI_API_KEY 에 Replicate Personal Access Token 값을 넣어주세요.")
22
+ os.environ["REPLICATE_API_TOKEN"] = REPL_TOKEN # Replicate 미사용이지만 구조 유지
23
 
24
+ # ────────────────── Gradio 서버 ─────────────────
25
+ GRADIO_URL = "http://211.233.58.201:7971"
26
+ GRADIO_API = "/process_and_save_image"
 
 
27
 
28
+ # ────────────────── 번역 파이프라인 ─────────────
29
  translator = transformers_pipeline(
30
  "translation",
31
  model="Helsinki-NLP/opus-mt-ko-en",
 
34
  )
35
 
36
  async def ko2en_async(text: str) -> str:
37
+ """한글 포함 시 영어 번역(비동기)."""
38
  if not re.search(r"[가-힣]", text):
39
  return text
40
  loop = asyncio.get_running_loop()
 
47
  logging.warning(f"번역 실패, 원문 사용: {e}")
48
  return text
49
 
50
+ # ────────────────── 로깅 ────────────────────────
51
+ logging.basicConfig(
52
+ level=logging.INFO,
53
  format="%(asctime)s [%(levelname)s] %(message)s",
54
+ handlers=[logging.StreamHandler()]
55
+ )
56
 
57
+ # ────────────────── Discord 클라이언트 ──────────
58
  intents = discord.Intents.default()
59
  intents.message_content = True
60
 
 
78
  prompt_en = await ko2en_async(prompt_raw)
79
  await message.channel.typing()
80
 
81
+ # ───────────── Gradio 호출 ──────────────
82
  def generate_image():
83
  client = Client(GRADIO_URL)
84
  return client.predict(
 
89
  prompt=prompt_en,
90
  seed=random.randint(0, 2**32 - 1),
91
  api_name=GRADIO_API
92
+ )
93
 
94
  try:
95
+ result = await asyncio.get_running_loop().run_in_executor(None, generate_image)
 
96
  except Exception as e:
97
  logging.error(f"Gradio API error: {e}")
98
  await message.reply("⚠️ 이미지 생성 실패!")
99
  return
100
 
101
+ # Gradio 결과 list / dict / str 중 첫 요소로 정규화
102
+ if isinstance(result, list):
103
+ result = result[0]
104
+
105
+ # ────────────��� URL 있으면 링크로 전송 ─────────────
106
+ url = None
107
+ if isinstance(result, dict):
108
+ url = result.get("url")
109
+ if url and url.startswith("/"):
110
+ url = urljoin(GRADIO_URL, url)
111
+ elif isinstance(result, str) and result.startswith(("http", "/")):
112
+ url = result if result.startswith("http") else urljoin(GRADIO_URL, result)
113
+
114
+ if url:
115
+ await message.reply(content=url) # Discord가 embed 미리보기
116
+ return
117
 
118
+ # ───────────── 첨부 파일 준비 ─────────────
119
+ data = None
120
+ # dict → path
121
+ if isinstance(result, dict):
122
+ path = result.get("path")
123
+ if path:
124
+ # Gradio 파일 다운로드 우선
125
+ remote = urljoin(GRADIO_URL, f"/gradio_api/file={quote_plus(path)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  try:
127
+ data = requests.get(remote, timeout=10).content
128
+ except Exception:
129
+ if os.path.isfile(path):
130
+ with open(path, "rb") as f:
131
+ data = f.read()
132
+ # str → data URI
133
+ elif isinstance(result, str) and result.startswith("data:"):
134
+ try:
135
+ b64 = re.sub(r"^data:image/[^;]+;base64,", "", result)
136
+ data = base64.b64decode(b64)
137
+ except Exception as e:
138
+ logging.warning(f"base64 디코딩 실패: {e}")
139
+
140
+ if not data:
141
  await message.reply("⚠️ 이미지를 전송할 수 없습니다.")
142
+ return
143
 
144
+ # ───────────── WEBP → PNG 변환 (미리보기용) ─────────────
145
+ buf = io.BytesIO()
146
+ try:
147
+ Image.open(io.BytesIO(data)).convert("RGB").save(buf, format="PNG")
148
+ buf.seek(0)
149
+ await message.reply(files=[discord.File(buf, filename="image.png")])
150
+ except Exception:
151
+ # 변환 실패 시 원본 그대로
152
+ await message.reply(files=[discord.File(io.BytesIO(data), filename="image.webp")])
153
+
154
+ # ────────────────── 실행 ────────────────────────
155
  if __name__ == "__main__":
156
  replicate.Client(api_token=REPL_TOKEN) # 구조 유지
157
  ImageBot(intents=intents).run(TOKEN)