seawolf2357 commited on
Commit
829fd20
โ€ข
1 Parent(s): 029f929

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +6 -67
app.py CHANGED
@@ -3,13 +3,9 @@ import logging
3
  import os
4
  import re
5
  import asyncio
6
- import json
7
  import subprocess
8
  from huggingface_hub import InferenceClient
9
  from googleapiclient.discovery import build
10
- from google.oauth2.credentials import Credentials
11
- from google_auth_oauthlib.flow import InstalledAppFlow
12
- from google.auth.transport.requests import Request
13
  from youtube_transcript_api import YouTubeTranscriptApi
14
  from youtube_transcript_api.formatters import TextFormatter
15
  from dotenv import load_dotenv
@@ -17,10 +13,6 @@ from dotenv import load_dotenv
17
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
18
  load_dotenv()
19
 
20
- # JSON_TOKEN.json ํŒŒ์ผ์˜ ๊ฒฝ๋กœ
21
- credentials_path = 'JSON_TOKEN.json'
22
- token_path = 'token.json'
23
-
24
  # ๋กœ๊น… ์„ค์ •
25
  logging.basicConfig(level=logging.DEBUG, format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', handlers=[logging.StreamHandler()])
26
 
@@ -34,22 +26,9 @@ intents.guild_messages = True
34
  # ์ถ”๋ก  API ํด๋ผ์ด์–ธํŠธ ์„ค์ •
35
  hf_client = InferenceClient("CohereForAI/c4ai-command-r-plus", token=os.getenv("HF_TOKEN"))
36
 
37
- # OAuth 2.0 ์ธ์ฆ ์„ค์ •
38
- SCOPES = ["https://www.googleapis.com/auth/youtube.force-ssl"]
39
- creds = None
40
-
41
- if os.path.exists(token_path):
42
- creds = Credentials.from_authorized_user_file(token_path, SCOPES)
43
- if not creds or not creds.valid:
44
- if creds and creds.expired and creds.refresh_token:
45
- creds.refresh(Request())
46
- else:
47
- flow = InstalledAppFlow.from_client_secrets_file(credentials_path, SCOPES)
48
- creds = flow.run_local_server(port=0)
49
- with open(token_path, 'w') as token:
50
- token.write(creds.to_json())
51
-
52
- youtube_service = build('youtube', 'v3', credentials=creds)
53
 
54
  # ํŠน์ • ์ฑ„๋„ ID
55
  SPECIFIC_CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_ID"))
@@ -87,7 +66,6 @@ class MyClient(discord.Client):
87
  if comments and transcript:
88
  replies = await generate_replies(comments, transcript)
89
  await create_thread_and_send_replies(message, video_id, comments, replies)
90
- await post_replies_to_youtube(video_id, comments, replies)
91
  else:
92
  await message.channel.send("์ž๋ง‰์ด๋‚˜ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
93
  else:
@@ -96,15 +74,11 @@ class MyClient(discord.Client):
96
  self.is_processing = False
97
 
98
  def is_message_in_specific_channel(self, message):
99
- # ๋ฉ”์‹œ์ง€๊ฐ€ ์ง€์ •๋œ ์ฑ„๋„์ด๊ฑฐ๋‚˜, ํ•ด๋‹น ์ฑ„๋„์˜ ์“ฐ๋ ˆ๋“œ์ธ ๊ฒฝ์šฐ True ๋ฐ˜ํ™˜
100
  return message.channel.id == SPECIFIC_CHANNEL_ID or (
101
  isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
102
  )
103
 
104
  def extract_video_id(url):
105
- """
106
- YouTube ๋น„๋””์˜ค URL์—์„œ ๋น„๋””์˜ค ID๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
107
- """
108
  video_id = None
109
  youtube_regex = (
110
  r'(https?://)?(www\.)?'
@@ -118,37 +92,27 @@ def extract_video_id(url):
118
  return video_id
119
 
120
  async def get_best_available_transcript(video_id):
121
- """
122
- YouTube ๋น„๋””์˜ค์˜ ์ž๋ง‰์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
123
- """
124
  try:
125
- # ํ•œ๊ตญ์–ด ์ž๋ง‰ ์‹œ๋„
126
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ko'])
127
  except Exception as e:
128
  logging.warning(f'Error fetching Korean transcript: {e}')
129
  try:
130
- # ํ•œ๊ตญ์–ด ์ž๋ง‰์ด ์—†์œผ๋ฉด ์˜์–ด ์ž๋ง‰ ์‹œ๋„
131
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['en'])
132
  except Exception as e:
133
  logging.warning(f'Error fetching English transcript: {e}')
134
  try:
135
- # ์˜์–ด ์ž๋ง‰๋„ ์—†์œผ๋ฉด ๋‹ค๋ฅธ ์–ธ์–ด ์ž๋ง‰ ์‹œ๋„
136
  transcripts = YouTubeTranscriptApi.list_transcripts(video_id)
137
  transcript = transcripts.find_manually_created_transcript().fetch()
138
  except Exception as e:
139
  logging.error(f'Error fetching alternative transcript: {e}')
140
  return None
141
 
142
- # ์ž๋ง‰ ํฌ๋งทํŒ…
143
  formatter = TextFormatter()
144
  transcript_text = formatter.format_transcript(transcript)
145
  logging.debug(f'Fetched transcript: {transcript_text}')
146
  return transcript_text
147
 
148
  async def get_video_comments(video_id):
149
- """
150
- YouTube ๋น„๋””์˜ค์˜ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
151
- """
152
  comments = []
153
  response = youtube_service.commentThreads().list(
154
  part='snippet',
@@ -159,15 +123,12 @@ async def get_video_comments(video_id):
159
  for item in response.get('items', []):
160
  comment = item['snippet']['topLevelComment']['snippet']['textOriginal']
161
  comment_id = item['snippet']['topLevelComment']['id']
162
- comments.append((comment, comment_id)) # ๋Œ“๊ธ€๊ณผ ๋Œ“๊ธ€ ID๋ฅผ ํ•จ๊ป˜ ์ €์žฅ
163
 
164
  logging.debug(f'Fetched comments: {comments}')
165
  return comments
166
 
167
  async def generate_replies(comments, transcript):
168
- """
169
- ๋Œ“๊ธ€๊ณผ ์ž๋ง‰์„ ๊ธฐ๋ฐ˜์œผ๋กœ LLM ๋‹ต๊ธ€์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
170
- """
171
  replies = []
172
  for comment, _ in comments:
173
  messages = [
@@ -176,7 +137,7 @@ async def generate_replies(comments, transcript):
176
  ]
177
  loop = asyncio.get_event_loop()
178
  response = await loop.run_in_executor(None, lambda: hf_client.chat_completion(
179
- messages, max_tokens=400, temperature=0.7, top_p=0.85)) # max_tokens ๊ฐ’์„ ์กฐ์ •
180
 
181
  if response.choices and response.choices[0].message:
182
  reply = response.choices[0].message['content'].strip()
@@ -188,33 +149,11 @@ async def generate_replies(comments, transcript):
188
  return replies
189
 
190
  async def create_thread_and_send_replies(message, video_id, comments, replies):
191
- """
192
- ๋Œ“๊ธ€๊ณผ ๋‹ต๊ธ€์„ ์ƒˆ๋กœ์šด ์“ฐ๋ ˆ๋“œ์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
193
- """
194
  thread = await message.channel.create_thread(name=f"{message.author.name}์˜ ๋Œ“๊ธ€ ๋‹ต๊ธ€", message=message)
195
  for (comment, _), reply in zip(comments, replies):
196
  embed = discord.Embed(description=f"**๋Œ“๊ธ€**: {comment}\n**๋‹ต๊ธ€**: {reply}")
197
  await thread.send(embed=embed)
198
 
199
- async def post_replies_to_youtube(video_id, comments, replies):
200
- """
201
- ์ƒ์„ฑ๋œ ๋‹ต๊ธ€์„ YouTube ๋Œ“๊ธ€๋กœ ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค.
202
- """
203
- for (comment, comment_id), reply in zip(comments, replies):
204
- try:
205
- youtube_service.comments().insert(
206
- part='snippet',
207
- body={
208
- 'snippet': {
209
- 'parentId': comment_id,
210
- 'textOriginal': reply
211
- }
212
- }
213
- ).execute()
214
- logging.debug(f'Posted reply to comment: {comment_id}')
215
- except Exception as e:
216
- logging.error(f'Error posting reply to comment {comment_id}: {e}')
217
-
218
  if __name__ == "__main__":
219
  discord_client = MyClient(intents=intents)
220
- discord_client.run(os.getenv('DISCORD_TOKEN')) #์ด ์ฝ”๋“œ๋ฅผ ๊ธฐ์–ตํ•˜๋ผ: ์ตœ์ข…์ ์œผ๋กœ ๋‹ต๊ธ€ ์ด ์ž‘์„ฑ๋˜์—ˆ์ง€๋งŒ ์œ ํŠœ๋ธŒ์— ๋“ฑ๋ก์ด ์•ˆ๋˜๊ณ  ์žˆ๋‹ค.
 
3
  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
10
  from youtube_transcript_api.formatters import TextFormatter
11
  from dotenv import load_dotenv
 
13
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
14
  load_dotenv()
15
 
 
 
 
 
16
  # ๋กœ๊น… ์„ค์ •
17
  logging.basicConfig(level=logging.DEBUG, format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', handlers=[logging.StreamHandler()])
18
 
 
26
  # ์ถ”๋ก  API ํด๋ผ์ด์–ธํŠธ ์„ค์ •
27
  hf_client = InferenceClient("CohereForAI/c4ai-command-r-plus", token=os.getenv("HF_TOKEN"))
28
 
29
+ # YouTube API ์„ค์ •
30
+ API_KEY = os.getenv("YOUTUBE_API_KEY")
31
+ youtube_service = build('youtube', 'v3', developerKey=API_KEY)
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  # ํŠน์ • ์ฑ„๋„ ID
34
  SPECIFIC_CHANNEL_ID = int(os.getenv("DISCORD_CHANNEL_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:
 
74
  self.is_processing = False
75
 
76
  def is_message_in_specific_channel(self, message):
 
77
  return message.channel.id == SPECIFIC_CHANNEL_ID or (
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 = (
84
  r'(https?://)?(www\.)?'
 
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):
 
 
 
116
  comments = []
117
  response = youtube_service.commentThreads().list(
118
  part='snippet',
 
123
  for item in response.get('items', []):
124
  comment = item['snippet']['topLevelComment']['snippet']['textOriginal']
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):
 
 
 
132
  replies = []
133
  for comment, _ in comments:
134
  messages = [
 
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()
 
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'))