Spaces:
Sleeping
Sleeping
Upload 6 files
Browse files- app.py +105 -0
- config.yaml +13 -0
- constants.py +4 -0
- prompts.py +29 -0
- requirements.txt +6 -0
- utils.py +32 -0
app.py
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import re
|
3 |
+
import streamlit_authenticator as stauth
|
4 |
+
import yaml
|
5 |
+
from yaml.loader import SafeLoader
|
6 |
+
from streamlit_player import st_player
|
7 |
+
from utils import create_transcript_from_youtube_api, create_open_ai_query
|
8 |
+
from prompts import DETECT_INTENT_OF_CONVERSATION, TOPIC_BASED_QUESTION, FOLLOW_UP_QUESTION, GENERAL_QUESTION, GENERAL_GREETING, \
|
9 |
+
VAGUE_QUERY_PROMPT
|
10 |
+
|
11 |
+
st.set_page_config(page_title="Youtube AI")
|
12 |
+
with open('config.yaml') as file:
|
13 |
+
config = yaml.load(file, Loader=SafeLoader)
|
14 |
+
|
15 |
+
authenticator = stauth.Authenticate(
|
16 |
+
config['credentials'],
|
17 |
+
config['cookie']['name'],
|
18 |
+
config['cookie']['key'],
|
19 |
+
config['cookie']['expiry_days'],
|
20 |
+
config['preauthorized']
|
21 |
+
)
|
22 |
+
name, authentication_status, username = authenticator.login()
|
23 |
+
|
24 |
+
if st.session_state["authentication_status"]:
|
25 |
+
authenticator.logout('Logout', 'main')
|
26 |
+
st.write(f'Welcome to Mentor Mode')
|
27 |
+
elif st.session_state["authentication_status"] is False:
|
28 |
+
st.error('Wrong password or username')
|
29 |
+
elif st.session_state["authentication_status"] is None:
|
30 |
+
st.warning('Please enter your username and password')
|
31 |
+
st.session_state["chat_history"] = []
|
32 |
+
|
33 |
+
if st.session_state["authentication_status"]:
|
34 |
+
if "chat_history" not in st.session_state:
|
35 |
+
st.session_state["chat_history"] = []
|
36 |
+
|
37 |
+
if "messages" not in st.session_state:
|
38 |
+
st.session_state.messages = []
|
39 |
+
|
40 |
+
for message in st.session_state.messages:
|
41 |
+
with st.chat_message(message["role"]):
|
42 |
+
st.markdown(message["content"])
|
43 |
+
|
44 |
+
with st.sidebar:
|
45 |
+
st.title("Your Video")
|
46 |
+
youtube_video_link = st.text_area("Please enter your video link")
|
47 |
+
st.button("Play Video", type="primary")
|
48 |
+
if youtube_video_link:
|
49 |
+
st_player(youtube_video_link)
|
50 |
+
else:
|
51 |
+
st.write("Please enter a valid link")
|
52 |
+
|
53 |
+
if prompt := st.chat_input("Hey AI!"):
|
54 |
+
st.session_state.messages.append({"role": "user", "content": prompt})
|
55 |
+
st.session_state.chat_history.append({"role": "user", "content": prompt})
|
56 |
+
with st.chat_message("user"):
|
57 |
+
st.markdown(prompt)
|
58 |
+
|
59 |
+
if youtube_video_link and prompt:
|
60 |
+
with st.spinner("Processing..."):
|
61 |
+
video_id = re.search(r'(?<=v=)[\w-]+', youtube_video_link).group(0)
|
62 |
+
yt_transcript = create_transcript_from_youtube_api(video_id)
|
63 |
+
if yt_transcript["success"]:
|
64 |
+
ADDITIONAL_PROMPT = f"""QUERY : ```{prompt}```, TRANSCRIPT:```{yt_transcript}```,
|
65 |
+
CHAT_HISTORY:```{st.session_state["chat_history"]}````"""
|
66 |
+
FINAL_PROMPT = ADDITIONAL_PROMPT + DETECT_INTENT_OF_CONVERSATION
|
67 |
+
intent = create_open_ai_query(FINAL_PROMPT)
|
68 |
+
print(intent["data"])
|
69 |
+
if intent["success"]:
|
70 |
+
if intent["data"] == "VAGUE_QUERY":
|
71 |
+
FINAL_PROMPT = ADDITIONAL_PROMPT + VAGUE_QUERY_PROMPT
|
72 |
+
response = create_open_ai_query(FINAL_PROMPT)
|
73 |
+
elif intent["data"] == "GENERAL_QUESTION":
|
74 |
+
FINAL_PROMPT = ADDITIONAL_PROMPT + GENERAL_QUESTION
|
75 |
+
response = create_open_ai_query(FINAL_PROMPT)
|
76 |
+
elif intent["data"] == "TOPIC_BASED_QUESTION":
|
77 |
+
FINAL_PROMPT = ADDITIONAL_PROMPT + TOPIC_BASED_QUESTION
|
78 |
+
response = create_open_ai_query(FINAL_PROMPT)
|
79 |
+
elif intent["data"] == "FOLLOW_UP_QUESTION":
|
80 |
+
FINAL_PROMPT = ADDITIONAL_PROMPT + FOLLOW_UP_QUESTION
|
81 |
+
response = create_open_ai_query(FINAL_PROMPT)
|
82 |
+
elif intent["data"] == "GENERAL_GREETING":
|
83 |
+
FINAL_PROMPT = ADDITIONAL_PROMPT + GENERAL_GREETING
|
84 |
+
response = create_open_ai_query(FINAL_PROMPT)
|
85 |
+
|
86 |
+
with st.chat_message("assistant"):
|
87 |
+
if response["success"]:
|
88 |
+
st.write(response["data"])
|
89 |
+
else:
|
90 |
+
st.write(response["error"])
|
91 |
+
st.session_state.messages.append({"role": "assistant", "content": response["data"]})
|
92 |
+
st.session_state.chat_history.append({"role": "assistant", "content": response["data"]})
|
93 |
+
|
94 |
+
if st.button("Download Chat History"):
|
95 |
+
# Combine role and content for each message
|
96 |
+
chat_history = "\n".join(
|
97 |
+
[f"{message['role']} : {message['content']}" for message in
|
98 |
+
st.session_state.messages if message["content"] is not None]
|
99 |
+
)
|
100 |
+
st.download_button(
|
101 |
+
label="Download",
|
102 |
+
data=chat_history,
|
103 |
+
file_name="chat_history.txt",
|
104 |
+
mime="text/plain"
|
105 |
+
)
|
config.yaml
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
credentials:
|
2 |
+
usernames:
|
3 |
+
IssacNewton:
|
4 |
+
email: [email protected]
|
5 |
+
name: Issac Newton
|
6 |
+
password: "$2b$12$CnkWEiaUjJTkRvUy4R5R6.UXjHkAxMbwB13AMklpnPcHfdadD9tBK" # To be replaced with hashed password
|
7 |
+
cookie:
|
8 |
+
expiry_days: 30
|
9 |
+
key: "issac" # Must be string
|
10 |
+
name: "newton"
|
11 |
+
preauthorized:
|
12 |
+
emails:
|
13 |
constants.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
3 |
+
OPENAI_API_BASE_URL = "https://api.openai.com/v1"
|
4 |
+
OPEN_AI_MODEL = "gpt-4-1106-preview"
|
prompts.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
DETECT_INTENT_OF_CONVERSATION = """User is watching a youtube video, whose transcript is : TRANSCRIPT. Your task is to classify the type of the given
|
2 |
+
query : QUERY which is asked by the user. Always take inference from chat history: CHAT_HISTORY, while detecting type.
|
3 |
+
Here are the possible types along with the definition of the type:
|
4 |
+
1.) VAGUE_QUERY: User is asking absolutely irrelevant question which is not present in transcript
|
5 |
+
2.) GENERAL_QUESTION: User is asking in general about the video for eg what is the video about, give me a gist etc
|
6 |
+
3.) TOPIC_BASED_QUESTION: User is asking questions based on specific parts of the video
|
7 |
+
4.) FOLLOW_UP_QUESTION: User is asking follow up questions based on their previous chat history
|
8 |
+
5.) GENERAL_GREETING: User is greeting by saying hi hello thank you.
|
9 |
+
OUTPUT FORMAT -> Just final type, no extra text"""
|
10 |
+
|
11 |
+
VAGUE_QUERY_PROMPT = """User is watching a youtube video, whose transcript is : TRANSCRIPT. The previous chat history of the
|
12 |
+
user: CHAT_HISTORY. The user had asked a vague query : QUERY. So please tell the user to please stick to a conversation regarding the video
|
13 |
+
only"""
|
14 |
+
GENERAL_QUESTION = """User is watching a youtube video, whose transcript is : TRANSCRIPT. The previous chat history of the
|
15 |
+
user: CHAT_HISTORY. The user had asked a general question: QUERY regarding the video. Reply the user by taking reference from transcript
|
16 |
+
as well from the chat history(if needed). Also be short and crunch , reply with in 100 to 80 words. Give short pointers and be to the point
|
17 |
+
"""
|
18 |
+
TOPIC_BASED_QUESTION = """User is watching a youtube video, whose transcript is : TRANSCRIPT. The previous chat history of the
|
19 |
+
user: CHAT_HISTORY. The user had asked question from a specific part from the video:QUERY. You have to reply to the user by performing
|
20 |
+
the following steps internally :
|
21 |
+
1.) First understand the question and figure out from which part of the transcript this topic will be.
|
22 |
+
2.) Take time to think
|
23 |
+
3.) Reply the user accordingly in 100 to 80 words and also be to the point always."""
|
24 |
+
|
25 |
+
FOLLOW_UP_QUESTION = """User is watching a youtube video, whose transcript is : TRANSCRIPT. The previous chat history of the
|
26 |
+
user: CHAT_HISTORY. The user is asking a follow up question: QUERY based on the chat history. Your task is to analyse the chat history
|
27 |
+
and reply the user accordingly. Always be short and to the point while replying , with in 100 to 80 words"""
|
28 |
+
|
29 |
+
GENERAL_GREETING = """User is greeting you : query, please ask the user if they have any question for you!"""
|
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit~=1.31.1
|
2 |
+
streamlit-player
|
3 |
+
streamlit_authenticator
|
4 |
+
pyyaml~=6.0.1
|
5 |
+
requests~=2.31.0
|
6 |
+
youtube-transcript-api
|
utils.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from youtube_transcript_api import YouTubeTranscriptApi
|
2 |
+
from constants import OPENAI_API_KEY, OPENAI_API_BASE_URL, OPEN_AI_MODEL
|
3 |
+
import json
|
4 |
+
import requests
|
5 |
+
|
6 |
+
def create_transcript_from_youtube_api(youtube_video_id):
|
7 |
+
if not youtube_video_id:
|
8 |
+
return {"success": False, "error": "Please pass your youtube video-id"}
|
9 |
+
try:
|
10 |
+
list_transcript = YouTubeTranscriptApi.get_transcript(youtube_video_id)
|
11 |
+
transcript = ' '.join(entry['text'] for entry in list_transcript)
|
12 |
+
return {"success": True, "data": transcript}
|
13 |
+
except Exception as e:
|
14 |
+
return {"success": False, "error": f"Transcription failed due to : {e}"}
|
15 |
+
|
16 |
+
|
17 |
+
def create_open_ai_query(input_query, system_message=None, model_engine=OPEN_AI_MODEL):
|
18 |
+
openai_url = f"{OPENAI_API_BASE_URL}/chat/completions"
|
19 |
+
headers = {'Authorization': f'Bearer {OPENAI_API_KEY}', 'Content-Type': 'application/json'}
|
20 |
+
messages = []
|
21 |
+
if system_message:
|
22 |
+
messages.append({"role": "system", "content": system_message})
|
23 |
+
messages.append({"role": "user", "content": input_query})
|
24 |
+
payload = {
|
25 |
+
'model': model_engine,
|
26 |
+
'messages': messages,
|
27 |
+
}
|
28 |
+
response = requests.post(openai_url, headers=headers, data=json.dumps(payload))
|
29 |
+
if response.status_code == 200 and 'choices' in response.json():
|
30 |
+
content_text = response.json()['choices'][0]['message']['content'].strip()
|
31 |
+
return {"success": True, "data": content_text, "response_json": response.json()}
|
32 |
+
return {"success": False, "error": response.text}
|