|
import streamlit as st |
|
from streamlit_js_eval import streamlit_js_eval |
|
import choosingdata as choice |
|
from dotenv import load_dotenv |
|
from langchain.text_splitter import CharacterTextSplitter |
|
from langchain_community.embeddings import HuggingFaceInstructEmbeddings |
|
from langchain_community.vectorstores import FAISS |
|
from langchain_openai import ChatOpenAI |
|
from langchain_openai import OpenAIEmbeddings |
|
from langchain.memory import ConversationBufferMemory |
|
from langchain.chains import ConversationalRetrievalChain |
|
from langchain_community.llms import HuggingFaceHub |
|
|
|
|
|
def get_text_chunks(text): |
|
""" |
|
Splits the given text into chunks based on specified character settings. |
|
|
|
Parameters: |
|
- text (str): The text to be split into chunks. |
|
|
|
Returns: |
|
- list: A list of text chunks. |
|
""" |
|
text_splitter = CharacterTextSplitter( |
|
separator="\n", chunk_size=1000, chunk_overlap=200, length_function=len |
|
) |
|
chunks = text_splitter.split_text(text) |
|
return chunks |
|
|
|
|
|
def get_vectorstore(text_chunks): |
|
""" |
|
Generates a vector store from a list of text chunks using specified embeddings. |
|
|
|
Parameters: |
|
- text_chunks (list of str): Text segments to convert into vector embeddings. |
|
|
|
Returns: |
|
- FAISS: A FAISS vector store containing the embeddings of the text chunks. |
|
""" |
|
embeddings = OpenAIEmbeddings() |
|
vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings) |
|
return vectorstore |
|
|
|
|
|
def get_conversation_chain(vectorstore): |
|
""" |
|
Initializes a conversational retrieval chain that uses a large language model |
|
for generating responses based on the provided vector store. |
|
|
|
Parameters: |
|
- vectorstore (FAISS): A vector store to be used for retrieving relevant content. |
|
|
|
Returns: |
|
- ConversationalRetrievalChain: An initialized conversational chain object. |
|
""" |
|
llm = ChatOpenAI( |
|
model_name="gpt-4-1106-preview", |
|
) |
|
|
|
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) |
|
conversation_chain = ConversationalRetrievalChain.from_llm( |
|
llm=llm, retriever=vectorstore.as_retriever(), memory=memory |
|
) |
|
return conversation_chain |
|
|
|
|
|
def set_prompt(text_block): |
|
""" |
|
Callback function that sets the chosen prompt in the session state. |
|
|
|
Parameters: |
|
- text_block (str): The prompt text selected by the user. |
|
""" |
|
st.session_state["messages"].append({"role": "user", "content": text_block}) |
|
st.session_state["prompts"] = text_block |
|
|
|
|
|
def prompts(): |
|
""" |
|
Renders clickable buttons for predefined prompts in the Streamlit application, |
|
allowing the user to select a prompt to send to the conversation chain. |
|
""" |
|
potential_prompts = [ |
|
f"What is the meaning of the song {st.session_state['title']} by {st.session_state['artist']}?", |
|
f"What is the most difficult English grammar point in the song {st.session_state['title']} by {st.session_state['artist']}? Can you explain it?", |
|
f"What is the most common English word in the song {st.session_state['title']} by {st.session_state['artist']} (excluding stopwords)? Can you give some example sentences using that word?", |
|
f"What is the most worth learning English phrase in the song {st.session_state['title']} by {st.session_state['artist']}? Can you explain it and provide practical example using the phrase?", |
|
] |
|
chosen_prompt = None |
|
for index, text_block in enumerate(potential_prompts): |
|
st.button( |
|
f"Prompt {index + 1}: {text_block}", on_click=set_prompt, args=(text_block,) |
|
) |
|
|
|
|
|
def get_lyrics(): |
|
""" |
|
Retrieves the lyrics stored in the session state. |
|
|
|
Returns: |
|
- str: The lyrics of the currently selected song. |
|
""" |
|
lyrics = st.session_state["lyrics"] |
|
return lyrics |
|
|
|
|
|
def page_title(): |
|
""" |
|
Sets the title of the Streamlit page based on the selected song and artist. |
|
""" |
|
if st.session_state["title"] and st.session_state["artist"]: |
|
st.title( |
|
f'π΅ English Music Recommender π¬ ({st.session_state["title"]} by {st.session_state["artist"]})' |
|
) |
|
else: |
|
st.title("π΅ English Music Recommender π¬") |
|
|
|
|
|
def chat_sidebar(): |
|
""" |
|
Renders the sidebar in the Streamlit application for selecting music preferences |
|
and handling song recommendations. |
|
""" |
|
with st.sidebar: |
|
st.title("π Music Preferences") |
|
|
|
user_difficulty = st.sidebar.radio( |
|
"Choose a difficulty level:", ("Easy", "Medium", "Hard") |
|
) |
|
|
|
user_danceability = st.sidebar.radio( |
|
"How much do you want to dance?", ("Low", "Medium", "High") |
|
) |
|
|
|
user_valence = st.sidebar.radio( |
|
"What energy are you feeling?", ("Negative", "Neutral", "Positive") |
|
) |
|
|
|
if not st.session_state["song_bool"]: |
|
|
|
if st.sidebar.button("Submit"): |
|
df = choice.process_data("data.json") |
|
recommendations = choice.recommendation( |
|
df, |
|
dance_choice=user_danceability, |
|
valence_choice=user_valence, |
|
difficulty_choice=user_difficulty, |
|
) |
|
|
|
st.session_state["title"] = recommendations["title"].values[0] |
|
st.session_state["artist"] = recommendations["artist"].values[0] |
|
st.session_state["lyrics"] = recommendations["lyrics"].values[0] |
|
st.session_state["id"] = ( |
|
f'https://open.spotify.com/track/{recommendations["id"].values[0]}' |
|
) |
|
st.session_state["song_bool"] = True |
|
|
|
st.rerun() |
|
|
|
else: |
|
if st.session_state["song_bool"]: |
|
|
|
st.write("### We would recommend you...") |
|
st.write(f"## {st.session_state['title']}") |
|
st.write(f" by {st.session_state['artist']}") |
|
st.markdown( |
|
f'<a href="{st.session_state["id"]}"><img src="{st.session_state["icon"]}" alt="Clickable image" style="height:60px;"></a>', |
|
unsafe_allow_html=True, |
|
) |
|
st.write("Please refresh the page for a new recommendation.") |
|
if st.button("Reload page"): |
|
streamlit_js_eval(js_expressions="parent.window.location.reload()") |
|
|
|
|
|
def chat(): |
|
""" |
|
Manages the chat interface in the Streamlit application, handling the conversation |
|
flow and displaying the chat history. |
|
""" |
|
if st.session_state["lyrics"]: |
|
|
|
text_chunks = get_text_chunks(get_lyrics()) |
|
vectorstore = get_vectorstore(text_chunks) |
|
st.session_state.conversation = get_conversation_chain(vectorstore) |
|
|
|
if len(st.session_state.messages) == 1: |
|
message = st.session_state.messages[0] |
|
with st.chat_message(message["role"]): |
|
st.write(message["content"]) |
|
prompts() |
|
|
|
else: |
|
for message in st.session_state.messages: |
|
with st.chat_message(message["role"]): |
|
st.write(message["content"]) |
|
|
|
|
|
if prompt := st.chat_input(): |
|
st.session_state.messages.append({"role": "user", "content": prompt}) |
|
st.session_state.prompts = prompt |
|
with st.chat_message("user"): |
|
st.write(prompt) |
|
|
|
if st.session_state.messages[-1]["role"] != "system": |
|
|
|
with st.chat_message("system"): |
|
with st.spinner("Generating response..."): |
|
response = st.session_state.conversation.invoke( |
|
{"question": st.session_state.prompts} |
|
) |
|
st.session_state.chat_history = response["chat_history"] |
|
message = st.session_state.chat_history[-1] |
|
st.write(message.content) |
|
message = {"role": "system", "content": message.content} |
|
st.session_state.messages.append(message) |
|
|
|
else: |
|
st.write("You can chat with GPT once a song has been recommended to you!") |
|
|
|
|
|
def init(): |
|
""" |
|
Initializes the session state variables used in the Streamlit application and |
|
loads environment variables. |
|
""" |
|
load_dotenv() |
|
|
|
if "title" not in st.session_state: |
|
st.session_state["title"] = "" |
|
if "artist" not in st.session_state: |
|
st.session_state["artist"] = "" |
|
if "icon" not in st.session_state: |
|
st.session_state["icon"] = ( |
|
"https://thereceptionist.com/wp-content/uploads/2021/02/Podcast-Listen-On-Spotify-1.png" |
|
) |
|
if "id" not in st.session_state: |
|
st.session_state["id"] = "" |
|
if "song_bool" not in st.session_state: |
|
st.session_state["song_bool"] = False |
|
if "messages" not in st.session_state.keys(): |
|
st.session_state.messages = [ |
|
{ |
|
"role": "system", |
|
"content": "What do you want to learn about? Here are some suggested prompts: ", |
|
} |
|
] |
|
if "conversation" not in st.session_state: |
|
st.session_state.conversation = None |
|
if "chat_history" not in st.session_state: |
|
st.session_state.chat_history = None |
|
if "lyrics" not in st.session_state: |
|
st.session_state["lyrics"] = "" |
|
if "prompts" not in st.session_state: |
|
st.session_state["prompts"] = "" |
|
|