diff --git a/Homepage.py b/Homepage.py
index 425c855..8b38fbf 100644
--- a/Homepage.py
+++ b/Homepage.py
@@ -1,76 +1,19 @@
import streamlit as st
from streamlit_option_menu import option_menu
from app_utils import switch_page
-from initialization import initialize_session_state, embedding, resume_reader
-from prompts.prompts import templates
-from typing import Literal
-from dataclasses import dataclass
import streamlit as st
-from speech_recognition.openai_whisper import save_wav_file, transcribe
-from langchain.callbacks import get_openai_callback
-from aws.synthesize_speech import synthesize_speech
-from IPython.display import Audio
-from dataclasses import dataclass
-import base64
-from typing import Literal
-from audio_recorder_streamlit import audio_recorder
-from initialization import initialize_session_state
-@dataclass
-class Message:
- """Class for keeping track of interview history."""
- origin: Literal["human", "ai"]
- message: str
-def autoplay_audio(file_path: str):
- def update_audio():
- global global_audio_md
- with open(file_path, "rb") as f:
- data = f.read()
- b64 = base64.b64encode(data).decode()
- global_audio_md = f"""
-
- """
- def update_markdown(audio_md):
- st.markdown(audio_md, unsafe_allow_html=True)
- update_audio()
- update_markdown(global_audio_md)
-
-def answer_call_back():
- with get_openai_callback() as cb:
- # user input
- human_answer = st.session_state.answer
- # transcribe audio
- save_wav_file("temp/audio.wav", human_answer)
- try:
- input = transcribe("temp/audio.wav")
- # save human_answer to history
- st.session_state.history.append(
- Message("human", input)
- )
- # OpenAI answer and save to history
- llm_answer = st.session_state.screen.run(input)
- # speech synthesis and speak out
- audio_file_path = synthesize_speech(llm_answer)
- # create audio widget with autoplay
- audio_widget = Audio(audio_file_path, autoplay=True)
- # save audio data to history
- st.session_state.history.append(
- Message("ai", llm_answer)
- )
- st.session_state.token_count += cb.total_tokens
- return audio_widget
- except:
- st.session_state.history.append(Message("ai", "Sorry, I didn't get that. Please try again."))
+from PIL import Image
# ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
-st.set_page_config(page_title = "🤖 AI Interviewer", layout = "centered")
-home_title = "🤖 AI Interviewer"
+im = Image.open("icon.png")
+st.set_page_config(page_title = "AI Interviewer", layout = "centered",page_icon=im)
+
+home_title = "AI Interviewer"
home_introduction = "Welcome to AI Interviewer, empowering your interview preparation with generative AI."
with st.sidebar:
- st.markdown('🤖 AI Interviewer - V0.1.2')
+ st.markdown('AI Interviewer - V0.1.2')
st.markdown("""
#### Let's contact:
[Haoxiang Jia](https://www.linkedin.com/in/haoxiang-jia/)
@@ -94,8 +37,9 @@ def answer_call_back():
"",
unsafe_allow_html=True
)
-
+st.image(im, width=100)
st.markdown(f"""# {home_title} Beta""",unsafe_allow_html=True)
+
st.markdown("""\n""")
#st.markdown("#### Greetings")
st.markdown("Welcome to AI Interviewer! 👏AI Interviewer is a generative AI powered tool that provides you with realistic interview experience. "
@@ -116,7 +60,8 @@ def answer_call_back():
st.info("""
📚In this session, the AI Interviewer will assess your technical skills as they relate to the job description.
- Press the microphone to start answering.
- - Each Interview will take 10 to 15 mins.
+ - Each Interview will take 10 to 15 mins.
+ - To start a new session, just refresh the page.
- Start introduce yourself and enjoy! """)
if st.button("Start Interview!"):
switch_page("Professional Screen")
@@ -126,7 +71,8 @@ def answer_call_back():
st.info("""
📚In this session, the AI Interviewer will review your resume and discuss your past experiences.
- Press the microphone to start answering.
- - Each Interview will take 10 to 15 mins.
+ - Each Interview will take 10 to 15 mins.
+ - To start a new session, just refresh the page.
- Start introduce yourself and enjoy! """
)
if st.button("Start Interview!"):
@@ -137,7 +83,8 @@ def answer_call_back():
st.info("""
📚In this session, the AI Interviewer will assess your soft skills as they relate to the job description.
- Press the microphone to start answering.
- - Each Interview will take 10 to 15 mins.
+ - Each Interview will take 10 to 15 mins.
+ - To start a new session, just refresh the page.
- Start introduce yourself and enjoy!
""")
if st.button("Start Interview!"):
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..a3f7ead
Binary files /dev/null and b/icon.png differ
diff --git a/images/icon.png b/images/icon.png
deleted file mode 100644
index 36d4e01..0000000
Binary files a/images/icon.png and /dev/null differ
diff --git a/pages/Behavioral Screen.py b/pages/Behavioral Screen.py
index 0f6479a..7f35e84 100644
--- a/pages/Behavioral Screen.py
+++ b/pages/Behavioral Screen.py
@@ -65,7 +65,6 @@ def initialize_session_state():
st.session_state.bq_docserch = save_vector(jd)
if "bq_retriever" not in st.session_state:
st.session_state.bq_retriever = st.session_state.bq_docserch.as_retriever(search_type="similarity")
-
if "bq_chain_type_kwargs" not in st.session_state:
Behavioral_Prompt = PromptTemplate(input_variables=["context", "question"],
template=templates.behavioral_template)
@@ -73,6 +72,8 @@ def initialize_session_state():
# interview history
if "history" not in st.session_state:
st.session_state.history = []
+ st.session_state.history.append(Message("ai", "Hello there! I am your interviewer today. I will access your soft skills through a series of questions. Let's get started! Please start by saying hello or introducing yourself."))
+
# token count
if "token_count" not in st.session_state:
st.session_state.token_count = 0
@@ -95,7 +96,7 @@ def initialize_session_state():
PROMPT = PromptTemplate(
input_variables=["history", "input"],
template="""I want you to act as an interviewer strictly following the guideline in the current conversation.
-
+ Candidate has no idea what the guideline is.
Ask me questions and wait for my answers. Do not write explanations.
Ask question like a real person, only one question at a time.
Do not ask the same question.
@@ -128,18 +129,40 @@ def answer_call_back():
# user input
human_answer = st.session_state.answer
# transcribe audio
- save_wav_file("temp/audio.wav", human_answer)
- try:
- input = transcribe("temp/audio.wav")
- # save human_answer to history
+ if voice:
+ save_wav_file("temp/audio.wav", human_answer)
+ try:
+ input = transcribe("temp/audio.wav")
+ # save human_answer to history
+ st.session_state.history.append(
+ Message("human", input)
+ )
+ # OpenAI answer and save to history
+ llm_answer = st.session_state.conversation.run(input)
+ # speech synthesis and speak out
+ audio_file_path = synthesize_speech(llm_answer)
+ # create audio widget with autoplay
+ audio_widget = Audio(audio_file_path, autoplay=True)
+ # save audio data to history
+ st.session_state.history.append(
+ Message("ai", llm_answer)
+ )
+ st.session_state.token_count += cb.total_tokens
+ return audio_widget
+ except:
+ st.session_state.history.append(Message("ai", "Sorry, I didn't get that. Please try again."))
+ else:
+ input = human_answer
st.session_state.history.append(
Message("human", input)
)
# OpenAI answer and save to history
llm_answer = st.session_state.conversation.run(input)
+ # OpenAI answer and save to history
+ llm_answer = st.session_state.conversation.run(input)
# speech synthesis and speak out
audio_file_path = synthesize_speech(llm_answer)
- # 创建自动播放的音频部件
+ # create audio widget with autoplay
audio_widget = Audio(audio_file_path, autoplay=True)
# save audio data to history
st.session_state.history.append(
@@ -147,9 +170,6 @@ def answer_call_back():
)
st.session_state.token_count += cb.total_tokens
return audio_widget
- except:
- st.session_state.history.append(Message("ai", "Sorry, I didn't get that. Please try again."))
-
### ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
if jd:
@@ -168,23 +188,27 @@ def answer_call_back():
# keep interview
else:
with answer_placeholder:
- answer = audio_recorder(pause_threshold=2.5, sample_rate=44100)
+ voice: bool = st.checkbox("I would like to speak with AI Interviewer!")
+ if voice:
+ answer = audio_recorder(pause_threshold=2.5, sample_rate=44100)
+ else:
+ answer = st.chat_input("Your answer")
if answer:
st.session_state['answer'] = answer
audio = answer_call_back()
- else:
- st.write("Please speak into the microphone to answer the question.")
with chat_placeholder:
+ auto_play = st.checkbox("Let AI interviewer speak!")
+ if auto_play:
+ try:
+ st.write(audio)
+ except:
+ pass
for answer in st.session_state.history:
if answer:
if answer.origin == 'ai':
with st.chat_message("assistant"):
st.write(answer.message)
- try:
- st.write(audio)
- except:
- pass
else:
with st.chat_message("user"):
st.write(answer.message)
diff --git a/pages/Professional Screen.py b/pages/Professional Screen.py
index 9550699..359fff7 100644
--- a/pages/Professional Screen.py
+++ b/pages/Professional Screen.py
@@ -32,16 +32,12 @@ def load_lottiefile(filepath: str):
### ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
@dataclass
class Message:
-
"""class for keeping track of interview history."""
-
origin: Literal["human", "ai"]
message: str
def save_vector(text):
-
"""embeddings"""
-
text_splitter = NLTKTextSplitter()
texts = text_splitter.split_text(text)
# Create emebeddings
@@ -64,13 +60,16 @@ def initialize_session_state():
# interview history
if "jd_history" not in st.session_state:
st.session_state.jd_history = []
+ st.session_state.jd_history.append(Message("ai",
+ "Hello, Welcome to the interview. I am your interviewer today. I will ask you professional questions regarding the job description you submitted."
+ "Please start by introducting a little bit about yourself."))
# token count
if "token_count" not in st.session_state:
st.session_state.token_count = 0
if "jd_guideline" not in st.session_state:
llm = ChatOpenAI(
model_name = "gpt-3.5-turbo",
- temperature = 0.6,)
+ temperature = 0.8,)
st.session_state.jd_guideline = RetrievalQA.from_chain_type(
llm=llm,
chain_type_kwargs=st.session_state.jd_chain_type_kwargs, chain_type='stuff',
@@ -82,11 +81,11 @@ def initialize_session_state():
temperature=0.8, )
PROMPT = PromptTemplate(
input_variables=["history", "input"],
- template="""I want you to act as an interviewer strictly following the guideline in the current conversation.
+ template="""I want you to act as a human interviewer strictly following the guideline in the current conversation.
- Ask me questions and wait for my answers like a real person.
+ Ask me questions and wait for my answers.
Do not write explanations.
- Ask question like a real person, only one question at a time.
+ only one question at a time.
Do not ask the same question.
Do not repeat the question.
Do ask follow-up questions if necessary.
@@ -106,7 +105,7 @@ def initialize_session_state():
if 'jd_feedback' not in st.session_state:
llm = ChatOpenAI(
model_name="gpt-3.5-turbo",
- temperature=0.5, )
+ temperature=0.8, )
st.session_state.jd_feedback = ConversationChain(
prompt=PromptTemplate(input_variables=["history", "input"], template=templates.feedback_template),
llm=llm,
@@ -118,11 +117,32 @@ def answer_call_back():
with get_openai_callback() as cb:
# user input
human_answer = st.session_state.answer
- # transcribe audio
- save_wav_file("temp/audio.wav", human_answer)
- try:
- input = transcribe("temp/audio.wav")
- # save human_answer to history
+ if voice:
+ # transcribe audio
+ save_wav_file("temp/audio.wav", human_answer)
+ try:
+ input = transcribe("temp/audio.wav")
+ # save human_answer to history
+ st.session_state.jd_history.append(
+ Message("human", input)
+ )
+ # OpenAI answer and save to history
+ llm_answer = st.session_state.jd_screen.run(input)
+ # speech synthesis
+ audio_file_path = synthesize_speech(llm_answer)
+ st.session_state.audio_file_path = audio_file_path
+ # 创建自动播放的音频部件
+ audio_widget = Audio(audio_file_path, autoplay=True)
+ # save audio data to history
+ st.session_state.jd_history.append(
+ Message("ai", llm_answer)
+ )
+ st.session_state.token_count += cb.total_tokens
+ return audio_widget
+ except:
+ st.session_state.jd_history.append(Message("ai", "Sorry, I didn't get that. Please try again."))
+ else:
+ input = human_answer
st.session_state.jd_history.append(
Message("human", input)
)
@@ -139,8 +159,6 @@ def answer_call_back():
)
st.session_state.token_count += cb.total_tokens
return audio_widget
- except:
- st.session_state.jd_history.append(Message("ai", "Sorry, I didn't get that. Please try again."))
### ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# sumitted job description
@@ -158,25 +176,31 @@ def answer_call_back():
st.stop()
else:
with answer_placeholder:
- answer = audio_recorder(pause_threshold = 2.5, sample_rate = 44100)
+ voice: bool = st.checkbox("I would like to speak with AI Interviewer")
+ if voice:
+ answer = audio_recorder(pause_threshold = 2.5, sample_rate = 44100)
+ else:
+ answer = st.chat_input("Your answer")
if answer:
st.session_state['answer'] = answer
audio = answer_call_back()
- else:
- st.write("Please speak into the microphone to answer the question.")
+
with chat_placeholder:
+ auto_play = st.checkbox("Let AI interviewer speak!")
+ if auto_play:
+ try:
+ st.write(audio)
+ except:
+ pass
for answer in st.session_state.jd_history:
#if answer:
if answer.origin == 'ai':
with st.chat_message("assistant"):
st.write(answer.message)
- try:
- st.write(audio)
- except:
- pass
else:
with st.chat_message("user"):
st.write(answer.message)
+
credit_card_placeholder.caption(f"""
Used {st.session_state.token_count} tokens \n
Progress: {int(len(st.session_state.jd_history) / 30 * 100)}% completed.""")
diff --git a/pages/Resume Screen.py b/pages/Resume Screen.py
index 28be86c..52e4da9 100644
--- a/pages/Resume Screen.py
+++ b/pages/Resume Screen.py
@@ -1,5 +1,4 @@
# langchain: https://python.langchain.com/
-import time
from dataclasses import dataclass
import streamlit as st
from speech_recognition.openai_whisper import save_wav_file, transcribe
@@ -15,7 +14,6 @@
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.text_splitter import NLTKTextSplitter
-import nltk
from PyPDF2 import PdfReader
from prompts.prompt_selector import prompt_sector
from streamlit_lottie import st_lottie
@@ -23,19 +21,13 @@
from IPython.display import Audio
### ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
-
-try:
- nltk.data.find('tokenizers/punkt')
-except LookupError:
- nltk.download('punkt')
-
def load_lottiefile(filepath: str):
with open(filepath, "r") as f:
return json.load(f)
st_lottie(load_lottiefile("images/welcome.json"), speed=1, reverse=False, loop=True, quality="high", height=300)
-position = st.selectbox("#### Select the position you are applying for", ["Data Analyst", "Software Engineer", "Marketing"])
-resume = st.file_uploader("#### Upload your resume", type=["pdf"])
+position = st.selectbox("Select the position you are applying for", ["Data Analyst", "Software Engineer", "Marketing"])
+resume = st.file_uploader("Upload your resume", type=["pdf"])
### ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
@dataclass
@@ -45,25 +37,20 @@ class Message:
message: str
def save_vector(resume):
-
pdf_reader = PdfReader(resume)
-
text = ""
for page in pdf_reader.pages:
text += page.extract_text()
-
# Split the document into chunks
text_splitter = NLTKTextSplitter()
texts = text_splitter.split_text(text)
text_splitter = NLTKTextSplitter()
texts = text_splitter.split_text(text)
-
embeddings = OpenAIEmbeddings()
docsearch = FAISS.from_texts(texts, embeddings)
return docsearch
def initialize_session_state():
-
# convert resume to embeddings
if 'docsearch' not in st.session_state:
st.session_state.docserch = save_vector(resume)
@@ -76,6 +63,7 @@ def initialize_session_state():
# interview history
if "resume_history" not in st.session_state:
st.session_state.resume_history = []
+ st.session_state.resume_history.append(Message(origin="ai", message="Hello, I am your interivewer today. I will ask you some questions regarding your resume and your experience. Please start by saying hello or introducing yourself."))
# token count
if "token_count" not in st.session_state:
st.session_state.token_count = 0
@@ -122,11 +110,9 @@ def initialize_session_state():
st.session_state.resume_screen = ConversationChain(prompt=PROMPT, llm = llm, memory = st.session_state.resume_memory)
# llm chain for generating feedback
if "resume_feedback" not in st.session_state:
-
llm = ChatOpenAI(
model_name="gpt-3.5-turbo",
temperature=0.5,)
-
st.session_state.resume_feedback = ConversationChain(
prompt=PromptTemplate(input_variables=["history","input"], template=templates.feedback_template),
llm=llm,
@@ -134,37 +120,54 @@ def initialize_session_state():
)
def answer_call_back():
-
with get_openai_callback() as cb:
# user input
human_answer = st.session_state.answer
- # transcribe audio
- save_wav_file("temp/audio.wav", human_answer)
- try:
- input = transcribe("temp/audio.wav")
- # save human input to history
+ if voice:
+ # transcribe audio
+ save_wav_file("temp/audio.wav", human_answer)
+ try:
+ input = transcribe("temp/audio.wav")
+ # save human input to history
+ st.session_state.resume_history.append(
+ Message("human", input)
+ )
+ # GPT Interviewer output and save to history
+ llm_answer = st.session_state.resume_screen.run(input)
+ # speech synthesis and speak out
+ audio_file_path = synthesize_speech(llm_answer)
+
+ st.session_state.audio_file_path = audio_file_path
+ # create audio widget with autoplay
+ audio_widget = Audio(audio_file_path, autoplay=True)
+
+ # save audio data to history
+ st.session_state.resume_history.append(
+ Message("ai", llm_answer)
+ )
+ st.session_state.token_count += cb.total_tokens
+
+ return audio_widget
+ except:
+ st.session_state.resume_history.append(Message("ai", "Sorry, I didn't get that. Please try again."))
+ else:
+ input = human_answer
st.session_state.resume_history.append(
Message("human", input)
)
-
# GPT Interviewer output and save to history
llm_answer = st.session_state.resume_screen.run(input)
# speech synthesis and speak out
audio_file_path = synthesize_speech(llm_answer)
-
st.session_state.audio_file_path = audio_file_path
- # 创建自动播放的音频部件
+ # create audio widget with auto play
audio_widget = Audio(audio_file_path, autoplay=True)
-
# save audio data to history
st.session_state.resume_history.append(
Message("ai", llm_answer)
)
st.session_state.token_count += cb.total_tokens
-
return audio_widget
- except:
- st.session_state.resume_history.append(Message("ai", "Sorry, I didn't get that. Please try again."))
### ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
@@ -184,26 +187,31 @@ def answer_call_back():
st.stop()
else:
with answer_placeholder:
- answer = audio_recorder(pause_threshold=2, sample_rate=44100)
+ voice: bool = st.checkbox("I would like to speak with AI Interviewer!")
+ if voice:
+ answer = audio_recorder(pause_threshold=2, sample_rate=44100)
+ else:
+ answer = st.chat_input("Your answer")
if answer:
st.session_state['answer'] = answer
audio_widget = answer_call_back()
- else:
- st.write("Please speak into the microphone to answer the question.")
with chat_placeholder:
+ auto_play = st.checkbox("Let AI interviewer speak!")
+ if auto_play:
+ try:
+ st.write(audio_widget)
+ except:
+ pass
for answer in st.session_state.resume_history:
if answer:
if answer.origin == 'ai':
with st.chat_message("assistant"):
st.write(answer.message)
- try:
- st.write(audio_widget)
- except:
- pass
else:
with st.chat_message("user"):
st.write(answer.message)
+
credit_card_placeholder.caption(f"""
Used {st.session_state.token_count} tokens \n
Progress: {int(len(st.session_state.resume_history) / 30 * 100)}% completed.""")
diff --git a/requirements.txt b/requirements.txt
index c91c3b0..17defe0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@ langchain
PyPDF2
openai
wave
-streamlit
+streamlit==1.24.0
tiktoken
nltk
#azure-cognitiveservices-speech
diff --git a/temp/audio.wav b/temp/audio.wav
index 7d1599f..c98be16 100644
Binary files a/temp/audio.wav and b/temp/audio.wav differ