Spaces:
Runtime error
Runtime error
Add application file
Browse files
app.py
ADDED
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import numpy as np
|
3 |
+
import streamlit as st
|
4 |
+
import whisper
|
5 |
+
import pytube
|
6 |
+
from pytube import YouTube
|
7 |
+
from streamlit_chat import message
|
8 |
+
import openai
|
9 |
+
from openai.embeddings_utils import get_embedding, distances_from_embeddings
|
10 |
+
import os
|
11 |
+
import pinecone
|
12 |
+
from dotenv import load_dotenv
|
13 |
+
|
14 |
+
# whisper
|
15 |
+
model = whisper.load_model('base')
|
16 |
+
output = ''
|
17 |
+
data = []
|
18 |
+
data_transcription = []
|
19 |
+
embeddings = []
|
20 |
+
mp4_video = ''
|
21 |
+
audio_file = ''
|
22 |
+
|
23 |
+
# Pinacone
|
24 |
+
|
25 |
+
# Uncomment this section if you want to save the embedding in pinecone
|
26 |
+
#load_dotenv()
|
27 |
+
# initialize connection to pinecone (get API key at app.pinecone.io)
|
28 |
+
# pinecone.init(
|
29 |
+
# api_key=os.getenv("PINACONE_API_KEY"),
|
30 |
+
# environment=os.getenv("PINACONE_ENVIRONMENT")
|
31 |
+
# )
|
32 |
+
array = []
|
33 |
+
|
34 |
+
# Uncomment this section if you want to upload your own video
|
35 |
+
# Sidebar
|
36 |
+
with st.sidebar:
|
37 |
+
user_secret = st.text_input(label = ":blue[OpenAI API key]",
|
38 |
+
value="",
|
39 |
+
placeholder = "Paste your openAI API key, sk-",
|
40 |
+
type = "password")
|
41 |
+
youtube_link = st.text_input(label = ":red[Youtube link]",
|
42 |
+
value="https://youtu.be/bsFXgfbj8Bc",
|
43 |
+
placeholder = "")
|
44 |
+
if youtube_link and user_secret:
|
45 |
+
youtube_video = YouTube(youtube_link)
|
46 |
+
video_id = pytube.extract.video_id(youtube_link)
|
47 |
+
streams = youtube_video.streams.filter(only_audio=True)
|
48 |
+
stream = streams.first()
|
49 |
+
if st.button("Start Analysis"):
|
50 |
+
if os.path.exists("word_embeddings.csv"):
|
51 |
+
os.remove("word_embeddings.csv")
|
52 |
+
|
53 |
+
with st.spinner('Running process...'):
|
54 |
+
# Get the video mp4
|
55 |
+
mp4_video = stream.download(filename='youtube_video.mp4')
|
56 |
+
audio_file = open(mp4_video, 'rb')
|
57 |
+
st.write(youtube_video.title)
|
58 |
+
st.video(youtube_link)
|
59 |
+
|
60 |
+
# Whisper
|
61 |
+
output = model.transcribe("youtube_video.mp4")
|
62 |
+
|
63 |
+
# Transcription
|
64 |
+
transcription = {
|
65 |
+
"title": youtube_video.title.strip(),
|
66 |
+
"transcription": output['text']
|
67 |
+
}
|
68 |
+
data_transcription.append(transcription)
|
69 |
+
pd.DataFrame(data_transcription).to_csv('transcription.csv')
|
70 |
+
segments = output['segments']
|
71 |
+
|
72 |
+
# Pinacone index
|
73 |
+
# check if index_name index already exists (only create index if not)
|
74 |
+
# index_name = str(video_id)
|
75 |
+
# # check if 'index_name' index already exists (only create index if not)
|
76 |
+
# if 'index1' not in pinecone.list_indexes():
|
77 |
+
# pinecone.create_index('index1', dimension=len(segments))
|
78 |
+
# # connect to index
|
79 |
+
# index = pinecone.Index('index1')
|
80 |
+
|
81 |
+
#st.write(segments)
|
82 |
+
#Embeddings
|
83 |
+
for segment in segments:
|
84 |
+
openai.api_key = user_secret
|
85 |
+
response = openai.Embedding.create(
|
86 |
+
input= segment["text"].strip(),
|
87 |
+
model="text-embedding-ada-002"
|
88 |
+
)
|
89 |
+
embeddings = response['data'][0]['embedding']
|
90 |
+
meta = {
|
91 |
+
"text": segment["text"].strip(),
|
92 |
+
"start": segment['start'],
|
93 |
+
"end": segment['end'],
|
94 |
+
"embedding": embeddings
|
95 |
+
}
|
96 |
+
data.append(meta)
|
97 |
+
# upsert_response = index.upsert(
|
98 |
+
# vectors=data,
|
99 |
+
# namespace=video_id
|
100 |
+
# )
|
101 |
+
pd.DataFrame(data).to_csv('word_embeddings.csv')
|
102 |
+
os.remove("youtube_video.mp4")
|
103 |
+
st.success('Analysis completed')
|
104 |
+
|
105 |
+
st.markdown('<h1>Youtube GPT 🤖<small> by <a href="https://codegpt.co">Code GPT</a></small></h1>', unsafe_allow_html=True)
|
106 |
+
#st.write("Start a chat with this video of Microsoft CEO Satya Nadella's interview. You just need to add your OpenAI API Key and paste it in the 'Chat with the video' tab.")
|
107 |
+
st.write('Demo con Midudev')
|
108 |
+
|
109 |
+
DEFAULT_WIDTH = 80
|
110 |
+
VIDEO_DATA = "https://youtu.be/bsFXgfbj8Bc"
|
111 |
+
|
112 |
+
# width = 40
|
113 |
+
|
114 |
+
# width = max(width, 0.01)
|
115 |
+
# side = max((100 - width) / 2, 0.01)
|
116 |
+
|
117 |
+
# _, container, _ = st.columns([side, 47, side])
|
118 |
+
# container.video(data=VIDEO_DATA)
|
119 |
+
tab1, tab2, tab3, tab4 = st.tabs(["Intro", "Transcription", "Embedding", "Chat with the Video"])
|
120 |
+
with tab1:
|
121 |
+
st.markdown("### How does it work?")
|
122 |
+
st.markdown('Read the article to know how it works: https://medium.com/@dan.avila7/youtube-gpt-start-a-chat-with-a-video-efe92a499e60')
|
123 |
+
st.write("Youtube GPT was written with the following tools:")
|
124 |
+
st.markdown("#### Code GPT")
|
125 |
+
st.write("All code was written with the help of Code GPT. Visit https://codegpt.co to get the extension.")
|
126 |
+
st.markdown("#### Streamlit")
|
127 |
+
st.write("The design was written with Streamlit https://streamlit.io.")
|
128 |
+
st.markdown("#### Whisper")
|
129 |
+
st.write("Video transcription is done by OpenAI Whisper: https://openai.com/blog/whisper.")
|
130 |
+
st.markdown("#### Embedding")
|
131 |
+
st.write('Embedding is done via the OpenAI API with "text-embedding-ada-002": https://platform.openai.com/docs/guides/embeddings')
|
132 |
+
st.markdown("#### GPT-3")
|
133 |
+
st.write('The chat uses the OpenAI API with the GPT-3: https://platform.openai.com/docs/models/gpt-3 model "text-davinci-003""')
|
134 |
+
st.markdown("""---""")
|
135 |
+
st.write('Author: Daniel Ávila https://www.linkedin.com/in/daniel-avila-arias/')
|
136 |
+
st.write('Repo: Github https://github.com/davila7/youtube-gpt')
|
137 |
+
st.write("This software was developed with Code GPT, for more information visit: https://codegpt.co")
|
138 |
+
with tab2:
|
139 |
+
st.header("Transcription:")
|
140 |
+
if(os.path.exists("youtube_video.mp4")):
|
141 |
+
audio_file = open('youtube_video.mp4', 'rb')
|
142 |
+
audio_bytes = audio_file.read()
|
143 |
+
st.audio(audio_bytes, format='audio/ogg')
|
144 |
+
if os.path.exists("transcription.csv"):
|
145 |
+
df = pd.read_csv('transcription.csv')
|
146 |
+
st.write(df)
|
147 |
+
with tab3:
|
148 |
+
st.header("Embedding:")
|
149 |
+
if os.path.exists("word_embeddings.csv"):
|
150 |
+
df = pd.read_csv('word_embeddings.csv')
|
151 |
+
st.write(df)
|
152 |
+
with tab4:
|
153 |
+
# user_secret = st.text_input(label = ":blue[OpenAI API key]",
|
154 |
+
# placeholder = "Paste your openAI API key, sk-",
|
155 |
+
# type = "password")
|
156 |
+
st.write('To obtain an API Key you must create an OpenAI account at the following link: https://openai.com/api/')
|
157 |
+
if 'generated' not in st.session_state:
|
158 |
+
st.session_state['generated'] = []
|
159 |
+
|
160 |
+
if 'past' not in st.session_state:
|
161 |
+
st.session_state['past'] = []
|
162 |
+
|
163 |
+
def get_text():
|
164 |
+
if user_secret:
|
165 |
+
st.header("Ask me something about the video:")
|
166 |
+
input_text = st.text_input("You: ","", key="input")
|
167 |
+
return input_text
|
168 |
+
user_input = get_text()
|
169 |
+
|
170 |
+
def get_embedding_text(api_key, prompt):
|
171 |
+
openai.api_key = user_secret
|
172 |
+
response = openai.Embedding.create(
|
173 |
+
input= prompt.strip(),
|
174 |
+
model="text-embedding-ada-002"
|
175 |
+
)
|
176 |
+
q_embedding = response['data'][0]['embedding']
|
177 |
+
df=pd.read_csv('word_embeddings.csv', index_col=0)
|
178 |
+
df['embedding'] = df['embedding'].apply(eval).apply(np.array)
|
179 |
+
|
180 |
+
df['distances'] = distances_from_embeddings(q_embedding, df['embedding'].values, distance_metric='cosine')
|
181 |
+
returns = []
|
182 |
+
|
183 |
+
# Sort by distance with 4 hints
|
184 |
+
for i, row in df.sort_values('distances', ascending=True).head(4).iterrows():
|
185 |
+
# Else add it to the text that is being returned
|
186 |
+
returns.append(row["text"])
|
187 |
+
|
188 |
+
# Return the context
|
189 |
+
return "\n\n###\n\n".join(returns)
|
190 |
+
|
191 |
+
def generate_response(api_key, prompt):
|
192 |
+
one_shot_prompt = '''I am YoutubeGPT, a highly intelligent question answering bot. If you ask me a question that is rooted in truth, I will give you the answer.
|
193 |
+
Q: What is human life expectancy in the United States?
|
194 |
+
A: Human life expectancy in the United States is 78 years.
|
195 |
+
Q: '''+prompt+'''
|
196 |
+
A: '''
|
197 |
+
completions = openai.Completion.create(
|
198 |
+
engine = "text-davinci-003",
|
199 |
+
prompt = one_shot_prompt,
|
200 |
+
max_tokens = 1024,
|
201 |
+
n = 1,
|
202 |
+
stop=["Q:"],
|
203 |
+
temperature=0.2,
|
204 |
+
)
|
205 |
+
message = completions.choices[0].text
|
206 |
+
return message
|
207 |
+
|
208 |
+
if user_input:
|
209 |
+
text_embedding = get_embedding_text(user_secret, user_input)
|
210 |
+
title = pd.read_csv('transcription.csv')['title']
|
211 |
+
string_title = "\n\n###\n\n".join(title)
|
212 |
+
user_input_embedding = 'Using this context: " Video about: '+string_title+'. '+text_embedding+'", answer the following question. \n'+user_input
|
213 |
+
# uncomment to see the embedding
|
214 |
+
#st.write(user_input_embedding)
|
215 |
+
output = generate_response(user_secret, user_input_embedding)
|
216 |
+
st.session_state.past.append(user_input)
|
217 |
+
st.session_state.generated.append(output)
|
218 |
+
if st.session_state['generated']:
|
219 |
+
for i in range(len(st.session_state['generated'])-1, -1, -1):
|
220 |
+
message(st.session_state["generated"][i], key=str(i))
|
221 |
+
message(st.session_state['past'][i], is_user=True, key=str(i) + '_user')
|