seawolf2357 commited on
Commit
3cbcff7
Β·
verified Β·
1 Parent(s): 829fd20

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -19
app.py CHANGED
@@ -4,6 +4,7 @@ import os
4
  import re
5
  import asyncio
6
  import subprocess
 
7
  from huggingface_hub import InferenceClient
8
  from googleapiclient.discovery import build
9
  from youtube_transcript_api import YouTubeTranscriptApi
@@ -33,17 +34,27 @@ youtube_service = build('youtube', 'v3', developerKey=API_KEY)
33
  # νŠΉμ • 채널 ID
34
  SPECIFIC_CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
35
 
 
 
 
 
 
 
36
  class MyClient(discord.Client):
37
  def __init__(self, *args, **kwargs):
38
  super().__init__(*args, **kwargs)
39
  self.is_processing = False
 
40
 
41
  async def on_ready(self):
42
  logging.info(f'{self.user}둜 λ‘œκ·ΈμΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€!')
43
 
44
  # web.py 파일 μ‹€ν–‰
45
  subprocess.Popen(["python", "web.py"])
46
- logging.info("Web.py server has been started.")
 
 
 
47
 
48
  # 봇이 μ‹œμž‘λ  λ•Œ μ•ˆλ‚΄ λ©”μ‹œμ§€λ₯Ό 전솑
49
  channel = self.get_channel(SPECIFIC_CHANNEL_ID)
@@ -65,7 +76,7 @@ class MyClient(discord.Client):
65
  comments = await get_video_comments(video_id)
66
  if comments and transcript:
67
  replies = await generate_replies(comments, transcript)
68
- await create_thread_and_send_replies(message, video_id, comments, replies)
69
  else:
70
  await message.channel.send("μžλ§‰μ΄λ‚˜ λŒ“κΈ€μ„ κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€.")
71
  else:
@@ -78,6 +89,12 @@ class MyClient(discord.Client):
78
  isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
79
  )
80
 
 
 
 
 
 
 
81
  def extract_video_id(url):
82
  video_id = None
83
  youtube_regex = (
@@ -88,28 +105,28 @@ def extract_video_id(url):
88
  match = re.match(youtube_regex, url)
89
  if match:
90
  video_id = match.group(6)
91
- logging.debug(f'Extracted video ID: {video_id}')
92
  return video_id
93
 
94
  async def get_best_available_transcript(video_id):
95
  try:
96
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ko'])
97
  except Exception as e:
98
- logging.warning(f'Error fetching Korean transcript: {e}')
99
  try:
100
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['en'])
101
  except Exception as e:
102
- logging.warning(f'Error fetching English transcript: {e}')
103
  try:
104
  transcripts = YouTubeTranscriptApi.list_transcripts(video_id)
105
  transcript = transcripts.find_manually_created_transcript().fetch()
106
  except Exception as e:
107
- logging.error(f'Error fetching alternative transcript: {e}')
108
  return None
109
 
110
  formatter = TextFormatter()
111
  transcript_text = formatter.format_transcript(transcript)
112
- logging.debug(f'Fetched transcript: {transcript_text}')
113
  return transcript_text
114
 
115
  async def get_video_comments(video_id):
@@ -125,7 +142,7 @@ async def get_video_comments(video_id):
125
  comment_id = item['snippet']['topLevelComment']['id']
126
  comments.append((comment, comment_id))
127
 
128
- logging.debug(f'Fetched comments: {comments}')
129
  return comments
130
 
131
  async def generate_replies(comments, transcript):
@@ -135,25 +152,59 @@ async def generate_replies(comments, transcript):
135
  {"role": "system", "content": f"λΉ„λ””μ˜€ μžλ§‰: {transcript}"},
136
  {"role": "user", "content": comment}
137
  ]
138
- loop = asyncio.get_event_loop()
139
- response = await loop.run_in_executor(None, lambda: hf_client.chat_completion(
140
- messages, max_tokens=400, temperature=0.7, top_p=0.85))
141
-
142
- if response.choices and response.choices[0].message:
143
- reply = response.choices[0].message['content'].strip()
144
- else:
145
- reply = "닡글을 생성할 수 μ—†μŠ΅λ‹ˆλ‹€."
 
 
 
146
  replies.append(reply)
147
 
148
- logging.debug(f'Generated replies: {replies}')
149
  return replies
150
 
151
- async def create_thread_and_send_replies(message, video_id, comments, replies):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  thread = await message.channel.create_thread(name=f"{message.author.name}의 λŒ“κΈ€ λ‹΅κΈ€", message=message)
153
- for (comment, _), reply in zip(comments, replies):
 
 
154
  embed = discord.Embed(description=f"**λŒ“κΈ€**: {comment}\n**λ‹΅κΈ€**: {reply}")
155
  await thread.send(embed=embed)
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  if __name__ == "__main__":
158
  discord_client = MyClient(intents=intents)
159
  discord_client.run(os.getenv('DISCORD_TOKEN'))
 
4
  import re
5
  import asyncio
6
  import subprocess
7
+ import aiohttp
8
  from huggingface_hub import InferenceClient
9
  from googleapiclient.discovery import build
10
  from youtube_transcript_api import YouTubeTranscriptApi
 
34
  # νŠΉμ • 채널 ID
35
  SPECIFIC_CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
36
 
37
+ # μ›Ήν›… URL μ„€μ •
38
+ WEBHOOK_URL = "https://connect.pabbly.com/workflow/sendwebhookdata/IjU3NjUwNTY1MDYzMjA0MzA1MjY4NTUzMDUxMzUi_pc"
39
+
40
+ # 전솑 μ‹€νŒ¨ μ‹œ μž¬μ‹œλ„ 횟수
41
+ MAX_RETRIES = 3
42
+
43
  class MyClient(discord.Client):
44
  def __init__(self, *args, **kwargs):
45
  super().__init__(*args, **kwargs)
46
  self.is_processing = False
47
+ self.session = None
48
 
49
  async def on_ready(self):
50
  logging.info(f'{self.user}둜 λ‘œκ·ΈμΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€!')
51
 
52
  # web.py 파일 μ‹€ν–‰
53
  subprocess.Popen(["python", "web.py"])
54
+ logging.info("Web.py μ„œλ²„κ°€ μ‹œμž‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€.")
55
+
56
+ # aiohttp ν΄λΌμ΄μ–ΈνŠΈ μ„Έμ…˜ 생성
57
+ self.session = aiohttp.ClientSession()
58
 
59
  # 봇이 μ‹œμž‘λ  λ•Œ μ•ˆλ‚΄ λ©”μ‹œμ§€λ₯Ό 전솑
60
  channel = self.get_channel(SPECIFIC_CHANNEL_ID)
 
76
  comments = await get_video_comments(video_id)
77
  if comments and transcript:
78
  replies = await generate_replies(comments, transcript)
79
+ await create_thread_and_send_replies(message, video_id, comments, replies, self.session)
80
  else:
81
  await message.channel.send("μžλ§‰μ΄λ‚˜ λŒ“κΈ€μ„ κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€.")
82
  else:
 
89
  isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
90
  )
91
 
92
+ async def close(self):
93
+ # aiohttp ν΄λΌμ΄μ–ΈνŠΈ μ„Έμ…˜ μ’…λ£Œ
94
+ if self.session:
95
+ await self.session.close()
96
+ await super().close()
97
+
98
  def extract_video_id(url):
99
  video_id = None
100
  youtube_regex = (
 
105
  match = re.match(youtube_regex, url)
106
  if match:
107
  video_id = match.group(6)
108
+ logging.debug(f'μΆ”μΆœλœ λΉ„λ””μ˜€ ID: {video_id}')
109
  return video_id
110
 
111
  async def get_best_available_transcript(video_id):
112
  try:
113
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ko'])
114
  except Exception as e:
115
+ logging.warning(f'ν•œκ΅­μ–΄ μžλ§‰ κ°€μ Έμ˜€κΈ° 였λ₯˜: {e}')
116
  try:
117
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['en'])
118
  except Exception as e:
119
+ logging.warning(f'μ˜μ–΄ μžλ§‰ κ°€μ Έμ˜€κΈ° 였λ₯˜: {e}')
120
  try:
121
  transcripts = YouTubeTranscriptApi.list_transcripts(video_id)
122
  transcript = transcripts.find_manually_created_transcript().fetch()
123
  except Exception as e:
124
+ logging.error(f'λŒ€μ²΄ μžλ§‰ κ°€μ Έμ˜€κΈ° 였λ₯˜: {e}')
125
  return None
126
 
127
  formatter = TextFormatter()
128
  transcript_text = formatter.format_transcript(transcript)
129
+ logging.debug(f'κ°€μ Έμ˜¨ μžλ§‰: {transcript_text}')
130
  return transcript_text
131
 
132
  async def get_video_comments(video_id):
 
142
  comment_id = item['snippet']['topLevelComment']['id']
143
  comments.append((comment, comment_id))
144
 
145
+ logging.debug(f'κ°€μ Έμ˜¨ λŒ“κΈ€: {comments}')
146
  return comments
147
 
148
  async def generate_replies(comments, transcript):
 
152
  {"role": "system", "content": f"λΉ„λ””μ˜€ μžλ§‰: {transcript}"},
153
  {"role": "user", "content": comment}
154
  ]
155
+ try:
156
+ loop = asyncio.get_event_loop()
157
+ response = await loop.run_in_executor(None, lambda: hf_client.chat_completion(
158
+ messages, max_tokens=250, temperature=0.7, top_p=0.85))
159
+ if response.choices and response.choices[0].message:
160
+ reply = response.choices[0].message['content'].strip()
161
+ else:
162
+ reply = "닡글을 생성할 수 μ—†μŠ΅λ‹ˆλ‹€."
163
+ except Exception as e:
164
+ logging.error(f"API 호좜 쀑 였λ₯˜ λ°œμƒ: {e}")
165
+ reply = "μ„œλ²„ 였λ₯˜λ‘œ 인해 닡글을 생성할 수 μ—†μŠ΅λ‹ˆλ‹€."
166
  replies.append(reply)
167
 
168
+ logging.debug(f'μƒμ„±λœ λ‹΅κΈ€: {replies}')
169
  return replies
170
 
171
+
172
+ async def send_webhook_data(session, chunk_data, chunk_number):
173
+ for attempt in range(MAX_RETRIES):
174
+ try:
175
+ async with session.post(WEBHOOK_URL, json=chunk_data) as resp:
176
+ if resp.status == 200:
177
+ logging.info(f"μ›Ήν›…μœΌλ‘œ 데이터 전솑 성곡: {chunk_number} 번째 μ‹œλ„")
178
+ return True # 성곡 μ‹œ μ’…λ£Œ
179
+ else:
180
+ logging.error(f"μ›Ήν›…μœΌλ‘œ 데이터 전솑 μ‹€νŒ¨: {resp.status}, {chunk_number} 번째 μ‹œλ„")
181
+ except aiohttp.ClientError as e:
182
+ logging.error(f"μ›Ήν›… 전솑 쀑 였λ₯˜ λ°œμƒ: {e}, {chunk_number} 번째 μ‹œλ„")
183
+ await asyncio.sleep(1) # μž¬μ‹œλ„ 전에 μž μ‹œ λŒ€κΈ°
184
+
185
+ return False # μž¬μ‹œλ„ 횟수 초과 μ‹œ μ‹€νŒ¨λ‘œ κ°„μ£Ό
186
+
187
+ async def create_thread_and_send_replies(message, video_id, comments, replies, session):
188
  thread = await message.channel.create_thread(name=f"{message.author.name}의 λŒ“κΈ€ λ‹΅κΈ€", message=message)
189
+ webhook_data = {"video_id": video_id, "replies": []}
190
+
191
+ for (comment, comment_id), reply in zip(comments, replies):
192
  embed = discord.Embed(description=f"**λŒ“κΈ€**: {comment}\n**λ‹΅κΈ€**: {reply}")
193
  await thread.send(embed=embed)
194
 
195
+ # μ›Ήν›… 데이터 μ€€λΉ„ (comment id 포함)
196
+ webhook_data["replies"].append({"comment": comment, "reply": reply, "comment_id": comment_id})
197
+
198
+ # 데이터λ₯Ό μ—¬λŸ¬ 번 λ‚˜λˆ„μ–΄ 전솑
199
+ chunk_size = 1 # 전솑할 λ°μ΄ν„°μ˜ 개수λ₯Ό 1둜 μ„€μ •ν•˜μ—¬ 각 데이터λ₯Ό λ³„λ„λ‘œ 전솑
200
+ for i in range(0, len(webhook_data["replies"]), chunk_size):
201
+ chunk = webhook_data["replies"][i:i+chunk_size]
202
+ chunk_data = {"video_id": video_id, "replies": chunk}
203
+
204
+ success = await send_webhook_data(session, chunk_data, i // chunk_size + 1)
205
+ if not success:
206
+ logging.error(f"데이터 전솑 μ‹€νŒ¨: {i // chunk_size + 1} 번째 청크")
207
+
208
  if __name__ == "__main__":
209
  discord_client = MyClient(intents=intents)
210
  discord_client.run(os.getenv('DISCORD_TOKEN'))