seawolf2357 commited on
Commit
b27279e
ยท
verified ยท
1 Parent(s): 302cdd6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -220
app.py CHANGED
@@ -217,223 +217,4 @@ async def post_replies_to_youtube(video_id, comments, replies):
217
 
218
  if __name__ == "__main__":
219
  discord_client = MyClient(intents=intents)
220
- discord_client.run(os.getenv('DISCORD_TOKEN')) ์ด ์ฝ”๋“œ๋ฅผ ๊ธฐ์–ตํ•˜๋ผ: ์ตœ์ข…์ ์œผ๋กœ ๋‹ต๊ธ€ ์ด ์ž‘์„ฑ๋˜์—ˆ์ง€๋งŒ ์œ ํŠœ๋ธŒ์— ๋“ฑ๋ก์ด ์•ˆ๋˜๊ณ  ์žˆ๋‹ค.import discord
221
- import logging
222
- import os
223
- import re
224
- import asyncio
225
- import json
226
- import subprocess
227
- from huggingface_hub import InferenceClient
228
- from googleapiclient.discovery import build
229
- from google.oauth2.credentials import Credentials
230
- from google_auth_oauthlib.flow import InstalledAppFlow
231
- from google.auth.transport.requests import Request
232
- from youtube_transcript_api import YouTubeTranscriptApi
233
- from youtube_transcript_api.formatters import TextFormatter
234
- from dotenv import load_dotenv
235
-
236
- # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
237
- load_dotenv()
238
-
239
- # JSON_TOKEN.json ํŒŒ์ผ์˜ ๊ฒฝ๋กœ
240
- credentials_path = 'JSON_TOKEN.json'
241
- token_path = 'token.json'
242
-
243
- # ๋กœ๊น… ์„ค์ •
244
- logging.basicConfig(level=logging.DEBUG, format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', handlers=[logging.StreamHandler()])
245
-
246
- # ์ธํ…ํŠธ ์„ค์ •
247
- intents = discord.Intents.default()
248
- intents.message_content = True
249
- intents.messages = True
250
- intents.guilds = True
251
- intents.guild_messages = True
252
-
253
- # ์ถ”๋ก  API ํด๋ผ์ด์–ธํŠธ ์„ค์ •
254
- hf_client = InferenceClient("CohereForAI/c4ai-command-r-plus", token=os.getenv("HF_TOKEN"))
255
-
256
- # OAuth 2.0 ์ธ์ฆ ์„ค์ •
257
- SCOPES = ["https://www.googleapis.com/auth/youtube.force-ssl"]
258
- creds = None
259
-
260
- if os.path.exists(token_path):
261
- creds = Credentials.from_authorized_user_file(token_path, SCOPES)
262
- if not creds or not creds.valid:
263
- if creds and creds.expired and creds.refresh_token:
264
- creds.refresh(Request())
265
- else:
266
- flow = InstalledAppFlow.from_client_secrets_file(credentials_path, SCOPES)
267
- creds = flow.run_local_server(port=0)
268
- with open(token_path, 'w') as token:
269
- token.write(creds.to_json())
270
-
271
- youtube_service = build('youtube', 'v3', credentials=creds)
272
-
273
- # ํŠน์ • ์ฑ„๋„ ID
274
- SPECIFIC_CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
275
-
276
- class MyClient(discord.Client):
277
- def __init__(self, *args, **kwargs):
278
- super().__init__(*args, **kwargs)
279
- self.is_processing = False
280
-
281
- async def on_ready(self):
282
- logging.info(f'{self.user}๋กœ ๋กœ๊ทธ์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!')
283
-
284
- # web.py ํŒŒ์ผ ์‹คํ–‰
285
- subprocess.Popen(["python", "web.py"])
286
- logging.info("Web.py server has been started.")
287
-
288
- # ๋ด‡์ด ์‹œ์ž‘๋  ๋•Œ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†ก
289
- channel = self.get_channel(SPECIFIC_CHANNEL_ID)
290
- if channel:
291
- await channel.send("์œ ํŠœ๋ธŒ ๋น„๋””์˜ค URL์„ ์ž…๋ ฅํ•˜๋ฉด, ์ž๋ง‰๊ณผ ๋Œ“๊ธ€์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ต๊ธ€์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.")
292
-
293
- async def on_message(self, message):
294
- if message.author == self.user:
295
- return
296
- if not self.is_message_in_specific_channel(message):
297
- return
298
- if self.is_processing:
299
- return
300
- self.is_processing = True
301
- try:
302
- video_id = extract_video_id(message.content)
303
- if video_id:
304
- transcript = await get_best_available_transcript(video_id)
305
- comments = await get_video_comments(video_id)
306
- if comments and transcript:
307
- replies = await generate_replies(comments, transcript)
308
- await create_thread_and_send_replies(message, video_id, comments, replies)
309
- await post_replies_to_youtube(video_id, comments, replies)
310
- else:
311
- await message.channel.send("์ž๋ง‰์ด๋‚˜ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
312
- else:
313
- await message.channel.send("์œ ํšจํ•œ ์œ ํŠœ๋ธŒ ๋น„๋””์˜ค URL์„ ์ œ๊ณตํ•ด ์ฃผ์„ธ์š”.")
314
- finally:
315
- self.is_processing = False
316
-
317
- def is_message_in_specific_channel(self, message):
318
- # ๋ฉ”์‹œ์ง€๊ฐ€ ์ง€์ •๋œ ์ฑ„๋„์ด๊ฑฐ๋‚˜, ํ•ด๋‹น ์ฑ„๋„์˜ ์“ฐ๋ ˆ๋“œ์ธ ๊ฒฝ์šฐ True ๋ฐ˜ํ™˜
319
- return message.channel.id == SPECIFIC_CHANNEL_ID or (
320
- isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
321
- )
322
-
323
- def extract_video_id(url):
324
- """
325
- YouTube ๋น„๋””์˜ค URL์—์„œ ๋น„๋””์˜ค ID๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
326
- """
327
- video_id = None
328
- youtube_regex = (
329
- r'(https?://)?(www\.)?'
330
- '(youtube|youtu|youtube-nocookie)\.(com|be)/'
331
- '(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})')
332
-
333
- match = re.match(youtube_regex, url)
334
- if match:
335
- video_id = match.group(6)
336
- logging.debug(f'Extracted video ID: {video_id}')
337
- return video_id
338
-
339
- async def get_best_available_transcript(video_id):
340
- """
341
- YouTube ๋น„๋””์˜ค์˜ ์ž๋ง‰์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
342
- """
343
- try:
344
- # ํ•œ๊ตญ์–ด ์ž๋ง‰ ์‹œ๋„
345
- transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ko'])
346
- except Exception as e:
347
- logging.warning(f'Error fetching Korean transcript: {e}')
348
- try:
349
- # ํ•œ๊ตญ๏ฟฝ๏ฟฝ ์ž๋ง‰์ด ์—†์œผ๋ฉด ์˜์–ด ์ž๋ง‰ ์‹œ๋„
350
- transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['en'])
351
- except Exception as e:
352
- logging.warning(f'Error fetching English transcript: {e}')
353
- try:
354
- # ์˜์–ด ์ž๋ง‰๋„ ์—†์œผ๋ฉด ๋‹ค๋ฅธ ์–ธ์–ด ์ž๋ง‰ ์‹œ๋„
355
- transcripts = YouTubeTranscriptApi.list_transcripts(video_id)
356
- transcript = transcripts.find_manually_created_transcript().fetch()
357
- except Exception as e:
358
- logging.error(f'Error fetching alternative transcript: {e}')
359
- return None
360
-
361
- # ์ž๋ง‰ ํฌ๋งทํŒ…
362
- formatter = TextFormatter()
363
- transcript_text = formatter.format_transcript(transcript)
364
- logging.debug(f'Fetched transcript: {transcript_text}')
365
- return transcript_text
366
-
367
- async def get_video_comments(video_id):
368
- """
369
- YouTube ๋น„๋””์˜ค์˜ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
370
- """
371
- comments = []
372
- response = youtube_service.commentThreads().list(
373
- part='snippet',
374
- videoId=video_id,
375
- maxResults=100 # ์ตœ๋Œ€ 100๊ฐœ์˜ ๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ
376
- ).execute()
377
-
378
- for item in response.get('items', []):
379
- comment = item['snippet']['topLevelComment']['snippet']['textOriginal']
380
- comment_id = item['snippet']['topLevelComment']['id']
381
- comments.append((comment, comment_id)) # ๋Œ“๊ธ€๊ณผ ๋Œ“๊ธ€ ID๋ฅผ ํ•จ๊ป˜ ์ €์žฅ
382
-
383
- logging.debug(f'Fetched comments: {comments}')
384
- return comments
385
-
386
- async def generate_replies(comments, transcript):
387
- """
388
- ๋Œ“๊ธ€๊ณผ ์ž๋ง‰์„ ๊ธฐ๋ฐ˜์œผ๋กœ LLM ๋‹ต๊ธ€์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
389
- """
390
- replies = []
391
- for comment, _ in comments:
392
- messages = [
393
- {"role": "system", "content": f"๋น„๋””์˜ค ์ž๋ง‰: {transcript}"},
394
- {"role": "user", "content": comment}
395
- ]
396
- loop = asyncio.get_event_loop()
397
- response = await loop.run_in_executor(None, lambda: hf_client.chat_completion(
398
- messages, max_tokens=400, temperature=0.7, top_p=0.85)) # max_tokens ๊ฐ’์„ ์กฐ์ •
399
-
400
- if response.choices and response.choices[0].message:
401
- reply = response.choices[0].message['content'].strip()
402
- else:
403
- reply = "๋‹ต๊ธ€์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
404
- replies.append(reply)
405
-
406
- logging.debug(f'Generated replies: {replies}')
407
- return replies
408
-
409
- async def create_thread_and_send_replies(message, video_id, comments, replies):
410
- """
411
- ๋Œ“๊ธ€๊ณผ ๋‹ต๊ธ€์„ ์ƒˆ๋กœ์šด ์“ฐ๋ ˆ๋“œ์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
412
- """
413
- thread = await message.channel.create_thread(name=f"{message.author.name}์˜ ๋Œ“๊ธ€ ๋‹ต๊ธ€", message=message)
414
- for (comment, _), reply in zip(comments, replies):
415
- embed = discord.Embed(description=f"**๋Œ“๊ธ€**: {comment}\n**๋‹ต๊ธ€**: {reply}")
416
- await thread.send(embed=embed)
417
-
418
- async def post_replies_to_youtube(video_id, comments, replies):
419
- """
420
- ์ƒ์„ฑ๋œ ๋‹ต๊ธ€์„ YouTube ๋Œ“๊ธ€๋กœ ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค.
421
- """
422
- for (comment, comment_id), reply in zip(comments, replies):
423
- try:
424
- youtube_service.comments().insert(
425
- part='snippet',
426
- body={
427
- 'snippet': {
428
- 'parentId': comment_id,
429
- 'textOriginal': reply
430
- }
431
- }
432
- ).execute()
433
- logging.debug(f'Posted reply to comment: {comment_id}')
434
- except Exception as e:
435
- logging.error(f'Error posting reply to comment {comment_id}: {e}')
436
-
437
- if __name__ == "__main__":
438
- discord_client = MyClient(intents=intents)
439
- discord_client.run(os.getenv('DISCORD_TOKEN')) # ์ด ์ฝ”๋“œ๋ฅผ ๊ธฐ์–ตํ•˜๋ผ: ์ตœ์ข…์ ์œผ๋กœ ๋‹ต๊ธ€ ์ด ์ž‘์„ฑ๋˜์—ˆ์ง€๋งŒ ์œ ํŠœ๋ธŒ์— ๋“ฑ๋ก์ด ์•ˆ๋˜๊ณ  ์žˆ๋‹ค.
 
217
 
218
  if __name__ == "__main__":
219
  discord_client = MyClient(intents=intents)
220
+ discord_client.run(os.getenv('DISCORD_TOKEN')) ์ด ์ฝ”๋“œ๋ฅผ ๊ธฐ์–ตํ•˜๋ผ: ์ตœ์ข…์ ์œผ๋กœ ๋‹ต๊ธ€ ์ด ์ž‘์„ฑ๋˜์—ˆ์ง€๋งŒ ์œ ํŠœ๋ธŒ์— ๋“ฑ๋ก์ด ์•ˆ๋˜๊ณ  ์žˆ๋‹ค.