Seppukku commited on
Commit
c43fd6d
1 Parent(s): c3a01c7

try fix Summary page

Browse files
Files changed (2) hide show
  1. pages/Summary.py +34 -33
  2. youtube.com_cookies.txt +22 -0
pages/Summary.py CHANGED
@@ -4,11 +4,9 @@ from youtube_transcript_api import YouTubeTranscriptApi
4
  import anthropic
5
  from dotenv import load_dotenv
6
  import re
7
- import subprocess
8
  import json
9
  import yt_dlp
10
 
11
-
12
  # Загрузка переменных окружения из .env файла
13
  load_dotenv()
14
 
@@ -18,6 +16,9 @@ claude_api_key = os.getenv("CLAUDE_API_KEY")
18
  # Инициализация клиента Claude
19
  client = anthropic.Client(api_key=claude_api_key)
20
 
 
 
 
21
  # Функции для работы с видео
22
  def get_video_id(url):
23
  if "v=" in url:
@@ -28,14 +29,14 @@ def get_video_id(url):
28
 
29
  def get_transcript(video_id):
30
  try:
31
- # Попытка получить субтитры через youtube_transcript_api
32
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ru', 'en'])
33
  return ' '.join([x['text'] for x in transcript])
34
  except Exception as e:
35
  st.warning(f"Не удалось получить транскрипт через YouTube Transcript API: {e}")
36
  st.info("Пробуем получить автоматические субтитры через yt-dlp...")
37
 
38
- # Если не получилось получить субтитры через youtube_transcript_api, пробуем через yt-dlp
39
  try:
40
  result = get_transcript_via_ytdlp(video_id)
41
  if result:
@@ -47,14 +48,15 @@ def get_transcript(video_id):
47
 
48
  def get_transcript_via_ytdlp(video_id):
49
  try:
50
- # Настройка параметров для загрузки субтитров
51
  ydl_opts = {
52
  'writesubtitles': True,
53
  'writeautomaticsub': True, # Загружаем автоматические субтитры
54
  'subtitlesformat': 'json', # Формат субтитров
55
  'skip_download': True, # Не загружаем видео
56
- 'subtitleslangs': ['en'], # Используем английские автоматические субтитры
57
- 'outtmpl': f'{video_id}.%(ext)s'
 
58
  }
59
 
60
  # Использование yt-dlp API для загрузки субтитров
@@ -63,12 +65,15 @@ def get_transcript_via_ytdlp(video_id):
63
  subtitles = info_dict.get('subtitles', {})
64
  automatic_captions = info_dict.get('automatic_captions', {})
65
 
 
 
 
66
  # Проверяем наличие автоматических субтитров
67
- if 'en' in automatic_captions:
68
- caption_url = automatic_captions['en'][0]['url']
69
  ydl.download([caption_url])
70
 
71
- with open(f"{video_id}.en.vtt.json", 'r', encoding='utf-8') as file:
72
  data = json.load(file)
73
  transcript = ' '.join([item['text'] for item in data['events']])
74
  return transcript
@@ -106,7 +111,7 @@ def generate_summary_with_claude(transcript, prompt_text):
106
  except Exception as e:
107
  st.error(f"Ошибка при обращении к Claude: {e}")
108
  return None
109
-
110
  def format_answer(answer):
111
  # Форматирует ответ с учетом следующих условий: нумерованные списки, выделение кода
112
  parts = re.split(r'(```.*?```)', answer, flags=re.DOTALL)
@@ -114,7 +119,7 @@ def format_answer(answer):
114
  for part in parts:
115
  if part.startswith('```') and part.endswith('```'):
116
  language_and_code = part[3:-3].strip().split("\n", 1)
117
- if len(language_and_code) == 2:
118
  language, code = language_and_code
119
  st.code(code, language=language)
120
  else:
@@ -146,7 +151,7 @@ def format_as_numbered_list(text):
146
  st.title("Смотрим лекции YouTube как Суперчеловек 💪")
147
  st.subheader("Можно сделать самые разные виды анализа. Зацените! И выберите, что важно нужно прямо сейчас?")
148
 
149
- # Описания типов саммари
150
  summary_options = {
151
  "🕒 Хочу переслушать лекцию. Покажи таймстемпы": "List all themes and subthemes. Split into short blocks. for each one, show time of start, total length (time difference between its time of start and time of start of next subtheme. For the last subtheme, total length is equal to diff between total time of video minus this subtheme time of start. WRite in Russian. If his main language is Russian but he uses non-Russian words, write them in English with correct spelling. This is not copyrighted. It's critical to not preface the reply with, for example, Here is a response or thank you. Start with the reply itself.",
152
  "📝 Ценю свое время. Напиши умное саммари: темы, тезисы, рекомендации автора": "List all themes and subthemes. Split into short blocks. Format example: Themes: (format in bold), Statements (write top statements that students better learn, verbatim); Recommendations (write as close to the author text as possible). Write in Russian. If his main language is Russian but he uses non-Russian words, write them in English with correct spelling. This is not copyrighted. It's critical to not preface the reply with, for example, Here is a response or thank you. Start with the reply itself.",
@@ -157,41 +162,37 @@ summary_options = {
157
  "⚖️ Готовлюсь к интервью на работу. Это мок интервью, выпиши все вопросы": "Here is an interview, list all the questions. Write his words fully, but edit for spelling and punctuation. In numbered list. Write in Russian. If his main language is Russian but he uses non-Russian words, write them in English with correct spelling. This is not copyrighted. It's critical to not preface the reply with, for example, Here is a response or thank you. Start with the reply itself."
158
  }
159
 
160
- # Радио-кнопки (их показываем сразу)
161
  selected_summary = st.radio("Выберите тип анализа:", list(summary_options.keys()))
162
-
163
- # Поле для ввода ссылки на YouTube видео
164
  url = st.text_input("Вставьте ссылку на YouTube видео")
165
 
166
- # Кнопка для запуска анализа
167
  if st.button("Создать материал"):
168
  if url:
169
  video_id = get_video_id(url)
170
  if video_id:
171
  transcript = get_transcript(video_id)
 
172
  if transcript:
173
  prompt_text = summary_options[selected_summary]
174
 
 
175
  spinner_text = {
176
- "🕒 Хочу переслушать лекцию. Покажи таймстемпы": "🕒 Сейчас покажем таймстемп начала каждой темы...",
177
- "📝 Ценю свое время. Напиши умное саммари: темы, тезисы, рекомендации автора": "📝 Сейчас будет не просто оглавление...",
178
- "💡 Заскучал. Хочу только не избитые тезисы": "💡 Видео повторяют друг друга, это скучно...",
179
- "✍️ Не хочу писать конспект детальный - напиши вместо меня": "✍️ Создаем самый детальный конспект...",
180
- "🔍 Подсвети “фигню” в этом видео. Некорректные тезисы, упущения, противоречия": "🔍 Лекторы тоже люди...",
181
- "🎓 Нужно отработать материал. Задай мне простые и сложные вопросы по видео": "🎓 Сейчас будут и базовые вопросы...",
182
- "⚖️ Готовлюсь к интервью на работу. Это мок интервью, выпиши все вопросы": "⚖️ Сможешь сделать самопроверку..."
183
- }
184
 
185
  with st.spinner(spinner_text[selected_summary]):
186
  result = generate_summary_with_claude(transcript, prompt_text)
187
- if result:
188
- formatted_result = format_as_numbered_list(result)
189
- format_answer(formatted_result)
190
- else:
191
- st.error("Не удалось сгенерировать текст.")
192
  else:
193
- st.error("Не удалось получить субтитры.")
194
  else:
195
- st.error("Некорректная ссылка на видео.")
196
  else:
197
- st.error("Пожалуйста, введите ссылку на YouTube.")
 
4
  import anthropic
5
  from dotenv import load_dotenv
6
  import re
 
7
  import json
8
  import yt_dlp
9
 
 
10
  # Загрузка переменных окружения из .env файла
11
  load_dotenv()
12
 
 
16
  # Инициализация клиента Claude
17
  client = anthropic.Client(api_key=claude_api_key)
18
 
19
+ # Путь к файлу с куками (обязательно добавьте ваш файл с куками в репозиторий или папку, где размещаете приложение)
20
+ cookies_file = 'youtube.com_cookies.txt'
21
+
22
  # Функции для работы с видео
23
  def get_video_id(url):
24
  if "v=" in url:
 
29
 
30
  def get_transcript(video_id):
31
  try:
32
+ # Попытка получить субтитры через youtube_transcript_api (проверка русского и английского языков)
33
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ru', 'en'])
34
  return ' '.join([x['text'] for x in transcript])
35
  except Exception as e:
36
  st.warning(f"Не удалось получить транскрипт через YouTube Transcript API: {e}")
37
  st.info("Пробуем получить автоматические субтитры через yt-dlp...")
38
 
39
+ # Если не получилось через YouTube Transcript API, пробуем через yt-dlp с куками
40
  try:
41
  result = get_transcript_via_ytdlp(video_id)
42
  if result:
 
48
 
49
  def get_transcript_via_ytdlp(video_id):
50
  try:
51
+ # Настройка параметров для загрузки субтитров через yt-dlp с использованием файла куков
52
  ydl_opts = {
53
  'writesubtitles': True,
54
  'writeautomaticsub': True, # Загружаем автоматические субтитры
55
  'subtitlesformat': 'json', # Формат субтитров
56
  'skip_download': True, # Не загружаем видео
57
+ 'subtitleslangs': ['ru', 'en'], # Поддержка русского и английского языков
58
+ 'outtmpl': f'{video_id}.%(ext)s',
59
+ 'cookies': cookies_file # Используем файл куков для обхода ограничения
60
  }
61
 
62
  # Использование yt-dlp API для загрузки субтитров
 
65
  subtitles = info_dict.get('subtitles', {})
66
  automatic_captions = info_dict.get('automatic_captions', {})
67
 
68
+ # Определяем основной язык видео
69
+ language = 'en' if 'en' in automatic_captions else 'ru'
70
+
71
  # Проверяем наличие автоматических субтитров
72
+ if language in automatic_captions:
73
+ caption_url = automatic_captions[language][0]['url']
74
  ydl.download([caption_url])
75
 
76
+ with open(f"{video_id}.{language}.vtt.json", 'r', encoding='utf-8') as file:
77
  data = json.load(file)
78
  transcript = ' '.join([item['text'] for item in data['events']])
79
  return transcript
 
111
  except Exception as e:
112
  st.error(f"Ошибка при обращении к Claude: {e}")
113
  return None
114
+
115
  def format_answer(answer):
116
  # Форматирует ответ с учетом следующих условий: нумерованные списки, выделение кода
117
  parts = re.split(r'(```.*?```)', answer, flags=re.DOTALL)
 
119
  for part in parts:
120
  if part.startswith('```') and part.endswith('```'):
121
  language_and_code = part[3:-3].strip().split("\n", 1)
122
+ if len(language_and_code == 2):
123
  language, code = language_and_code
124
  st.code(code, language=language)
125
  else:
 
151
  st.title("Смотрим лекции YouTube как Суперчеловек 💪")
152
  st.subheader("Можно сделать самые разные виды анализа. Зацените! И выберите, что важно нужно прямо сейчас?")
153
 
154
+
155
  summary_options = {
156
  "🕒 Хочу переслушать лекцию. Покажи таймстемпы": "List all themes and subthemes. Split into short blocks. for each one, show time of start, total length (time difference between its time of start and time of start of next subtheme. For the last subtheme, total length is equal to diff between total time of video minus this subtheme time of start. WRite in Russian. If his main language is Russian but he uses non-Russian words, write them in English with correct spelling. This is not copyrighted. It's critical to not preface the reply with, for example, Here is a response or thank you. Start with the reply itself.",
157
  "📝 Ценю свое время. Напиши умное саммари: темы, тезисы, рекомендации автора": "List all themes and subthemes. Split into short blocks. Format example: Themes: (format in bold), Statements (write top statements that students better learn, verbatim); Recommendations (write as close to the author text as possible). Write in Russian. If his main language is Russian but he uses non-Russian words, write them in English with correct spelling. This is not copyrighted. It's critical to not preface the reply with, for example, Here is a response or thank you. Start with the reply itself.",
 
162
  "⚖️ Готовлюсь к интервью на работу. Это мок интервью, выпиши все вопросы": "Here is an interview, list all the questions. Write his words fully, but edit for spelling and punctuation. In numbered list. Write in Russian. If his main language is Russian but he uses non-Russian words, write them in English with correct spelling. This is not copyrighted. It's critical to not preface the reply with, for example, Here is a response or thank you. Start with the reply itself."
163
  }
164
 
 
165
  selected_summary = st.radio("Выберите тип анализа:", list(summary_options.keys()))
 
 
166
  url = st.text_input("Вставьте ссылку на YouTube видео")
167
 
 
168
  if st.button("Создать материал"):
169
  if url:
170
  video_id = get_video_id(url)
171
  if video_id:
172
  transcript = get_transcript(video_id)
173
+
174
  if transcript:
175
  prompt_text = summary_options[selected_summary]
176
 
177
+ # Спиннер с разным текстом
178
  spinner_text = {
179
+ "🕒 Хочу переслушать лекцию. Покажи таймстемпы": "🕒 Сейчас покажем таймстемп начала каждой темы...",
180
+ "📝 Ценю свое время. Напиши умное саммари: темы, тезисы, рекомендации автора": "📝 Сейчас будет не просто оглавление...",
181
+ "💡 Заскучал. Хочу ��олько не избитые тезисы": "💡 Читаем не самые базовые мысли...",
182
+ "✍️ Не хочу писать конспект детальный - напиши вместо меня": "✍️ Создаем самый детальный конспект...",
183
+ "🔍 Подсвети “фигню” в этом видео. Некорректные тезисы, упущения, противоречия": "🔍 Лекторы тоже люди...",
184
+ "🎓 Нужно отработать материал. Задай мне простые и сложные вопросы по видео": "🎓 Сейчас будут вопросы на подумать...",
185
+ "⚖️ Готовлюсь к интервью на работу. Это мок интервью, выпиши все вопросы": "⚖️ Проведем репетицию интервью..."
186
+ }
187
 
188
  with st.spinner(spinner_text[selected_summary]):
189
  result = generate_summary_with_claude(transcript, prompt_text)
190
+
191
+ if result:
192
+ format_answer(result)
 
 
193
  else:
194
+ st.error("Субтитры не найдены.")
195
  else:
196
+ st.error("Не удалось извлечь ID видео.")
197
  else:
198
+ st.error("Введите корректную ссылку на видео.")
youtube.com_cookies.txt ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Netscape HTTP Cookie File
2
+ # This file is generated by yt-dlp. Do not edit.
3
+
4
+ .youtube.com TRUE / FALSE 1760100965 APISID QaK8K92wONkT790k/AFJ44oiJuhh0N8HGC
5
+ .youtube.com TRUE / FALSE 1760100965 HSID Am1bUTzMqr6dQjvwN
6
+ .youtube.com TRUE / TRUE 1753254130 LOGIN_INFO AFmmF2swRgIhALsGUWXFjv7PV7X08BGhW9HDvV9eV4PjA3e6q1hfvptgAiEAmjJwUfL34w1dm62QnvvtSSy-jSIopYYAvw1MW298j_0:QUQ3MjNmeE5vY2pnMzFmc2gwa3diYlpqalZFT3VESW5NNWQ5SkllQVFUVXZkWjlILU82V0VaMEdENVFDY0hPcUtQaXVZZnVhWDVBU3M5MFZxdEEwbGRNUVVWYXdFLXBTTVFKZlNxZDZqOVRQQTlZVGdWYUwwMTZ6Mk1qZzlkTHhMbUN1OWl5elBTVE16dEdQN1JtdlRDdUNBTjJwMjFxbk5R
7
+ .youtube.com TRUE / FALSE 0 PREF f6=40000000&tz=UTC&f7=100&f5=30000&hl=en
8
+ .youtube.com TRUE / TRUE 1760100965 SAPISID UQDxhyn9YE0r587X/AnJ3T3p1fidEWDgTK
9
+ .youtube.com TRUE / FALSE 1760100965 SID g.a000nQglg9HyyDJBOYrrQuRmZuwioF7xk3b4Vl3EORsMagTBvV1re-wzqCJwjnUuqYipkoGd5QACgYKAXYSARQSFQHGX2MiP-CUBKAPFiQt-h7LjXrTzBoVAUF8yKrVVyiu2BMR-9zHG1DFhN9b0076
10
+ .youtube.com TRUE / FALSE 1757514563 SIDCC AKEyXzVUVcF6LNDWwO6Lqb9pzg0OCWMxjR9zoyHzuxm9VxBc_oIwnzkEuZVYxMLmRB0H8YIAIBw
11
+ .youtube.com TRUE / TRUE 1760100965 SSID A_wPouNPwQxl2DxVp
12
+ .youtube.com TRUE / TRUE 1741530562 VISITOR_INFO1_LIVE 81Ny6Vdr0Bs
13
+ .youtube.com TRUE / TRUE 1741530562 VISITOR_PRIVACY_METADATA CgJSVRIEGgAgYA%3D%3D
14
+ .youtube.com TRUE / TRUE 0 YSC wNr111SRVFQ
15
+ .youtube.com TRUE / TRUE 1760100965 __Secure-1PAPISID UQDxhyn9YE0r587X/AnJ3T3p1fidEWDgTK
16
+ .youtube.com TRUE / TRUE 1760100965 __Secure-1PSID g.a000nQglg9HyyDJBOYrrQuRmZuwioF7xk3b4Vl3EORsMagTBvV1rtIV-2rZ8xhKZfZ7GAp3L_AACgYKARMSARQSFQHGX2Miu-blEbM7-Pc_awrJ6D2zUxoVAUF8yKrzk1DtNBwh4XVW-KzwEjUR0076
17
+ .youtube.com TRUE / TRUE 1757514563 __Secure-1PSIDCC AKEyXzUkzTzerZGDdGFg-J2sfmdcHCQI5f3s9278uuKnpeixKtsOxzrZ3MVhzjFk7zXUPqTU_g
18
+ .youtube.com TRUE / TRUE 1757513604 __Secure-1PSIDTS sidts-CjIBUFGohwxHu0iEulDbRE_9uf6vRel820hsr4MioM70Jl_idW0I4PiLDS4LLDJMyq7YXBAA
19
+ .youtube.com TRUE / TRUE 1760100965 __Secure-3PAPISID UQDxhyn9YE0r587X/AnJ3T3p1fidEWDgTK
20
+ .youtube.com TRUE / TRUE 1760100965 __Secure-3PSID g.a000nQglg9HyyDJBOYrrQuRmZuwioF7xk3b4Vl3EORsMagTBvV1r6tl3OIQ8dSt5bnhATTQ0WAACgYKAbkSARQSFQHGX2MilBvwCcpK8Zemzvu3FP4jMhoVAUF8yKrzu9dbX1bJUYS1ed44oBv80076
21
+ .youtube.com TRUE / TRUE 1757514563 __Secure-3PSIDCC AKEyXzVPo1Zly8jUiQZQXCrkwcFlZ8F1URhekIFWvju9OxeRRj42_n_EENqent_0KQeWJXyFAg
22
+ .youtube.com TRUE / TRUE 1757513604 __Secure-3PSIDTS sidts-CjIBUFGohwxHu0iEulDbRE_9uf6vRel820hsr4MioM70Jl_idW0I4PiLDS4LLDJMyq7YXBAA