seawolf2357 commited on
Commit
7edf3cc
โ€ข
1 Parent(s): b4bdc7a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -61
app.py CHANGED
@@ -1,9 +1,11 @@
1
  import discord
2
  import logging
3
  import os
 
4
  import asyncio
5
  from huggingface_hub import InferenceClient
6
  from googleapiclient.discovery import build
 
7
  from dotenv import load_dotenv
8
 
9
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
@@ -29,9 +31,6 @@ youtube_service = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY)
29
  # ํŠน์ • ์ฑ„๋„ ID
30
  SPECIFIC_CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
31
 
32
- # ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์ €์žฅํ•  ์ „์—ญ ๋ณ€์ˆ˜
33
- conversation_history = []
34
-
35
  class MyClient(discord.Client):
36
  def __init__(self, *args, **kwargs):
37
  super().__init__(*args, **kwargs)
@@ -43,7 +42,7 @@ class MyClient(discord.Client):
43
  # ๋ด‡์ด ์‹œ์ž‘๋  ๋•Œ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†ก
44
  channel = self.get_channel(SPECIFIC_CHANNEL_ID)
45
  if channel:
46
- await channel.send("ํŠธ๋ Œ๋“œ ๋ณด๊ณ  ์‹ถ์€ ์ฃผ์ œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”. ์˜ˆ) ์ตœ์‹  ํ…Œํฌ ๋‰ด์Šค")
47
 
48
  async def on_message(self, message):
49
  if message.author == self.user:
@@ -54,18 +53,17 @@ class MyClient(discord.Client):
54
  return
55
  self.is_processing = True
56
  try:
57
- # ์ฃผ์ œ ํ‚ค์›Œ๋“œ ์ถ”์ถœ
58
- keywords = await extract_keywords(message)
59
- if keywords:
60
- # YouTube API๋กœ ์ตœ์‹  ํŠธ๋ Œ๋“œ ๋ฐ ์ธ๊ธฐ ๋น„๋””์˜ค ๊ฒ€์ƒ‰
61
- video_details = await search_trending_videos(keywords)
62
- if video_details:
63
- # ์š”์ฒญ์ž์™€์˜ ์“ฐ๋ ˆ๋“œ ์ƒ์„ฑ ๋ฐ ๊ฒฐ๊ณผ ์ „์†ก
64
- await create_thread_and_send_results(message, keywords, video_details)
65
  else:
66
- await message.channel.send(f"**{keywords}**์— ๋Œ€ํ•œ ์ตœ์‹  ํŠธ๋ Œ๋“œ ๋น„๋””์˜ค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
67
  else:
68
- await message.channel.send("ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
69
  finally:
70
  self.is_processing = False
71
 
@@ -75,56 +73,84 @@ class MyClient(discord.Client):
75
  isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
76
  )
77
 
78
- async def extract_keywords(message):
79
- user_input = message.content
80
- system_prompt = "๋‹ค์Œ ๋ฌธ์žฅ์˜ ์˜๋ฏธ์— ๋งž๋Š” ์˜๋ฌธ ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”์ถœํ•˜์„ธ์š”: "
81
-
82
- logging.debug(f'Extracting keywords from user input: {user_input}')
83
-
84
- messages = [{"role": "system", "content": system_prompt + user_input}]
85
- logging.debug(f'Messages to be sent to the model: {messages}')
86
-
87
- loop = asyncio.get_event_loop()
88
- response = await loop.run_in_executor(None, lambda: hf_client.chat_completion(
89
- messages, max_tokens=10, temperature=0.7, top_p=0.85))
90
-
91
- # Hugging Face ์‘๋‹ต ํŒŒ์‹ฑ
92
- if response.choices and response.choices[0].message:
93
- keywords = response.choices[0].message['content'].strip()
94
- else:
95
- keywords = ""
96
- logging.debug(f'Extracted keywords: {keywords}')
97
- return keywords
98
-
99
- async def search_trending_videos(keywords):
100
- response = youtube_service.search().list(
101
- q=keywords,
 
 
 
 
 
 
 
 
 
 
 
102
  part='snippet',
103
- type='video',
104
- order='viewCount', # ์ธ๊ธฐ ์žˆ๋Š” ๋น„๋””์˜ค ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ
105
- maxResults=5 # ์›ํ•˜๋Š” ๊ฒฐ๊ณผ ์ˆ˜
106
  ).execute()
107
-
108
- video_details = []
109
  for item in response.get('items', []):
110
- video_details.append({
111
- 'title': item['snippet']['title'],
112
- 'url': f"https://www.youtube.com/watch?v={item['id']['videoId']}",
113
- 'description': item['snippet']['description'],
114
- 'thumbnail': item['snippet']['thumbnails']['high']['url']
115
- })
116
- return video_details
117
-
118
- async def create_thread_and_send_results(message, keywords, video_details):
119
- # ์“ฐ๋ ˆ๋“œ ์ƒ์„ฑ
120
- thread = await message.channel.create_thread(name=f"{message.author.name}์˜ ํŠธ๋ Œ๋“œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ", message=message)
121
- if video_details:
122
- message_content = f"**{keywords}**์— ๋Œ€ํ•œ ์ตœ์‹  ํŠธ๋ Œ๋“œ ๋น„๋””์˜ค {len(video_details)}๊ฐœ๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค:"
123
- await thread.send(message_content)
124
- for video in video_details:
125
- embed = discord.Embed(title=video['title'], description=video['description'], url=video['url'])
126
- embed.set_thumbnail(url=video['thumbnail'])
127
- await thread.send(embed=embed)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  if __name__ == "__main__":
130
  discord_client = MyClient(intents=intents)
 
1
  import discord
2
  import logging
3
  import os
4
+ import re
5
  import asyncio
6
  from huggingface_hub import InferenceClient
7
  from googleapiclient.discovery import build
8
+ from youtube_transcript_api import YouTubeTranscriptApi
9
  from dotenv import load_dotenv
10
 
11
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
 
31
  # ํŠน์ • ์ฑ„๋„ ID
32
  SPECIFIC_CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
33
 
 
 
 
34
  class MyClient(discord.Client):
35
  def __init__(self, *args, **kwargs):
36
  super().__init__(*args, **kwargs)
 
42
  # ๋ด‡์ด ์‹œ์ž‘๋  ๋•Œ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†ก
43
  channel = self.get_channel(SPECIFIC_CHANNEL_ID)
44
  if channel:
45
+ await channel.send("์œ ํŠœ๋ธŒ ๋น„๋””์˜ค URL์„ ์ž…๋ ฅํ•˜๋ฉด, ์ž๋ง‰๊ณผ ๋Œ“๊ธ€์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ต๊ธ€์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.")
46
 
47
  async def on_message(self, message):
48
  if message.author == self.user:
 
53
  return
54
  self.is_processing = True
55
  try:
56
+ video_id = extract_video_id(message.content)
57
+ if video_id:
58
+ transcript = await get_video_transcript(video_id)
59
+ comments = await get_video_comments(video_id)
60
+ if comments and transcript:
61
+ replies = await generate_replies(comments, transcript)
62
+ await create_thread_and_send_replies(message, video_id, comments, replies)
 
63
  else:
64
+ await message.channel.send("์ž๋ง‰์ด๋‚˜ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
65
  else:
66
+ await message.channel.send("์œ ํšจํ•œ ์œ ํŠœ๋ธŒ ๋น„๋””์˜ค URL์„ ์ œ๊ณตํ•ด ์ฃผ์„ธ์š”.")
67
  finally:
68
  self.is_processing = False
69
 
 
73
  isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
74
  )
75
 
76
+ def extract_video_id(url):
77
+ """
78
+ YouTube ๋น„๋””์˜ค URL์—์„œ ๋น„๋””์˜ค ID๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
79
+ """
80
+ video_id = None
81
+ youtube_regex = (
82
+ r'(https?://)?(www\.)?'
83
+ '(youtube|youtu|youtube-nocookie)\.(com|be)/'
84
+ '(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})')
85
+
86
+ match = re.match(youtube_regex, url)
87
+ if match:
88
+ video_id = match.group(6)
89
+ logging.debug(f'Extracted video ID: {video_id}')
90
+ return video_id
91
+
92
+ async def get_video_transcript(video_id):
93
+ """
94
+ YouTube ๋น„๋””์˜ค์˜ ์ž๋ง‰์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
95
+ """
96
+ try:
97
+ transcript = YouTubeTranscriptApi.get_transcript(video_id)
98
+ transcript_text = " ".join([entry['text'] for entry in transcript])
99
+ logging.debug(f'Fetched transcript: {transcript_text}')
100
+ return transcript_text
101
+ except Exception as e:
102
+ logging.error(f'Error fetching transcript: {e}')
103
+ return None
104
+
105
+ async def get_video_comments(video_id):
106
+ """
107
+ YouTube ๋น„๋””์˜ค์˜ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
108
+ """
109
+ comments = []
110
+ response = youtube_service.commentThreads().list(
111
  part='snippet',
112
+ videoId=video_id,
113
+ maxResults=100 # ์ตœ๋Œ€ 100๊ฐœ์˜ ๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ
 
114
  ).execute()
115
+
 
116
  for item in response.get('items', []):
117
+ comment = item['snippet']['topLevelComment']['snippet']['textOriginal']
118
+ comments.append(comment)
119
+
120
+ logging.debug(f'Fetched comments: {comments}')
121
+ return comments
122
+
123
+ async def generate_replies(comments, transcript):
124
+ """
125
+ ๋Œ“๊ธ€๊ณผ ์ž๋ง‰์„ ๊ธฐ๋ฐ˜์œผ๋กœ LLM ๋‹ต๊ธ€์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
126
+ """
127
+ replies = []
128
+ for comment in comments:
129
+ messages = [
130
+ {"role": "system", "content": f"๋น„๋””์˜ค ์ž๋ง‰: {transcript}"},
131
+ {"role": "user", "content": comment}
132
+ ]
133
+ loop = asyncio.get_event_loop()
134
+ response = await loop.run_in_executor(None, lambda: hf_client.chat_completion(
135
+ messages, max_tokens=50, temperature=0.7, top_p=0.85))
136
+
137
+ if response.choices and response.choices[0].message:
138
+ reply = response.choices[0].message['content'].strip()
139
+ else:
140
+ reply = "๋‹ต๊ธ€์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
141
+ replies.append(reply)
142
+
143
+ logging.debug(f'Generated replies: {replies}')
144
+ return replies
145
+
146
+ async def create_thread_and_send_replies(message, video_id, comments, replies):
147
+ """
148
+ ๋Œ“๊ธ€๊ณผ ๋‹ต๊ธ€์„ ์ƒˆ๋กœ์šด ์“ฐ๋ ˆ๋“œ์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
149
+ """
150
+ thread = await message.channel.create_thread(name=f"{message.author.name}์˜ ๋Œ“๊ธ€ ๋‹ต๊ธ€", message=message)
151
+ for comment, reply in zip(comments, replies):
152
+ embed = discord.Embed(description=f"**๋Œ“๊ธ€**: {comment}\n**๋‹ต๊ธ€**: {reply}")
153
+ await thread.send(embed=embed)
154
 
155
  if __name__ == "__main__":
156
  discord_client = MyClient(intents=intents)