|
import streamlit as st |
|
import openai |
|
import json |
|
from datetime import datetime |
|
|
|
|
|
st.set_page_config( |
|
page_title="Agent Interview Context Generation Demo", |
|
layout="wide" |
|
) |
|
|
|
|
|
st.markdown(""" |
|
<style> |
|
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css'); |
|
.chat-bubble { |
|
padding: 15px; |
|
border-radius: 15px; |
|
margin: 5px 0; |
|
max-width: 80%; |
|
position: relative; |
|
} |
|
|
|
.bot-bubble { |
|
background-color: #F0F2F6; |
|
margin-right: auto; |
|
margin-left: 10px; |
|
border-bottom-left-radius: 5px; |
|
} |
|
|
|
.user-bubble { |
|
background-color: #4CAF50; |
|
color: white; |
|
margin-left: auto; |
|
margin-right: 10px; |
|
border-bottom-right-radius: 5px; |
|
} |
|
|
|
.chat-container { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 10px; |
|
padding: 10px; |
|
background-color: white; |
|
border-radius: 10px; |
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1); |
|
} |
|
|
|
.stTextArea textarea { |
|
border-radius: 20px; |
|
padding: 10px 15px; |
|
font-size: 16px; |
|
} |
|
|
|
.stButton button { |
|
border-radius: 20px; |
|
padding: 5px 20px; |
|
} |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
if 'messages' not in st.session_state: |
|
st.session_state.messages = [] |
|
if 'interview_complete' not in st.session_state: |
|
st.session_state.interview_complete = False |
|
if 'context_data' not in st.session_state: |
|
st.session_state.context_data = "" |
|
if 'interview_started' not in st.session_state: |
|
st.session_state.interview_started = False |
|
if 'context_focus' not in st.session_state: |
|
st.session_state.context_focus = None |
|
|
|
def get_random_question(api_key, focus_area=None): |
|
"""Get a random question from OpenAI based on optional focus area.""" |
|
try: |
|
client = openai.OpenAI(api_key=api_key) |
|
system_content = "You are an interviewer gathering context about the user. " |
|
if focus_area and focus_area != "general": |
|
system_content += f"Focus specifically on questions about their {focus_area}. " |
|
system_content += "Ask one random, open-ended question that reveals meaningful information about the user. Be creative and never repeat questions. Each response should be just one engaging question." |
|
|
|
response = client.chat.completions.create( |
|
model="gpt-3.5-turbo", |
|
messages=[ |
|
{ |
|
"role": "system", |
|
"content": system_content |
|
}, |
|
{ |
|
"role": "user", |
|
"content": "Please ask me a random question." |
|
} |
|
] |
|
) |
|
return response.choices[0].message.content if hasattr(response.choices[0].message, 'content') else str(response.choices[0].message) |
|
except Exception as e: |
|
return f"Error: {str(e)}" |
|
|
|
def extract_context(api_key, conversation): |
|
"""Extract context from the conversation using OpenAI.""" |
|
try: |
|
client = openai.OpenAI(api_key=api_key) |
|
conversation_text = "\n".join([f"{'Bot' if i%2==0 else 'User'}: {msg}" for i, msg in enumerate(conversation)]) |
|
|
|
response = client.chat.completions.create( |
|
model="gpt-3.5-turbo", |
|
messages=[ |
|
{ |
|
"role": "system", |
|
"content": "Analyze the following conversation and extract key information about the user. Create a well-organized summary in markdown format, grouping similar information under appropriate headings. Write in third person perspective." |
|
}, |
|
{ |
|
"role": "user", |
|
"content": f"Please analyze this conversation and create a context summary:\n\n{conversation_text}" |
|
} |
|
] |
|
) |
|
return response.choices[0].message.content if hasattr(response.choices[0].message, 'content') else str(response.choices[0].message) |
|
except Exception as e: |
|
return f"Error: {str(e)}" |
|
|
|
|
|
with st.sidebar: |
|
st.title("Settings") |
|
api_key = st.text_input("Enter OpenAI API Key", type="password") |
|
|
|
if st.button("Clear/Reset"): |
|
st.session_state.messages = [] |
|
st.session_state.interview_complete = False |
|
st.session_state.context_data = "" |
|
st.session_state.interview_started = False |
|
st.session_state.context_focus = None |
|
st.rerun() |
|
|
|
|
|
st.title("Agent Interview Context Generation Demo") |
|
st.markdown(""" |
|
This project demonstrates how AI agents can proactively gather and generate rich contextual data |
|
through intelligent interviewing. By focusing on specific areas of interest, the agent builds a comprehensive |
|
understanding that enhances AI-human interactions and enables more personalized experiences. |
|
""") |
|
|
|
|
|
tab1, tab2, tab3, tab4 = st.tabs(["Instructions", "Interview", "Gallery", "Generated Context"]) |
|
|
|
with tab1: |
|
st.header("How it Works") |
|
st.markdown(""" |
|
This application helps gather and extract contextual information about you through an interactive interview process. |
|
|
|
Created by [Daniel Rosehill](https://danielrosehill.com) and Claude (Anthropic). |
|
|
|
View the source code on [GitHub](https://github.com/danielrosehill/Context-Extraction-Demo). |
|
|
|
### Process: |
|
1. Enter your OpenAI API key in the sidebar |
|
2. Choose your preferred context focus area |
|
3. Click the "Start Interview" button in the Interview tab |
|
4. The AI interviewer will ask targeted questions based on your chosen focus |
|
5. Answer each question naturally - you can type or use voice input |
|
6. Click "Submit Answer" after each response |
|
7. Continue the conversation until you're ready to end |
|
8. Click "End Interview" to generate your context summary |
|
9. Review the extracted context and export it as needed |
|
|
|
### Features: |
|
- **Focus Areas**: Choose to focus on specific aspects like professional background, technical skills, or keep it general |
|
- **Voice Input**: Use Chrome's built-in speech-to-text by clicking the microphone icon |
|
- **Targeted Questions**: The AI asks questions relevant to your chosen focus area |
|
- **Context Extraction**: Automatically organizes your information into a structured summary |
|
- **Export Options**: Copy or download your context data in markdown format |
|
|
|
### Tips: |
|
- Provide detailed, honest answers for better context extraction |
|
- Use voice input to make the process faster and more natural |
|
- Take your time with each response |
|
- You can reset and start over at any time using the Clear/Reset button |
|
""") |
|
|
|
with tab2: |
|
|
|
col1, col2 = st.columns([2, 1]) |
|
|
|
with col1: |
|
st.subheader("Conversation") |
|
|
|
st.markdown('<div class="chat-container">', unsafe_allow_html=True) |
|
for msg in st.session_state.messages: |
|
is_bot = msg.startswith('Q:') |
|
bubble_class = "bot-bubble" if is_bot else "user-bubble" |
|
message_content = msg[3:] if is_bot else msg |
|
bot_icon = '<i class="fas fa-robot" style="margin-right: 8px;"></i>' if is_bot else '' |
|
st.markdown( |
|
f'<div class="chat-bubble {bubble_class}">{bot_icon}{message_content}</div>', |
|
unsafe_allow_html=True |
|
) |
|
st.markdown('</div>', unsafe_allow_html=True) |
|
|
|
with col2: |
|
st.subheader("Your Response") |
|
|
|
st.markdown(""" |
|
💡 **Voice Input Tip**: |
|
- Click the microphone icon in Chrome |
|
- Or use built-in speech-to-text |
|
""") |
|
|
|
|
|
if api_key: |
|
if not st.session_state.interview_started and not st.session_state.interview_complete: |
|
|
|
if st.session_state.context_focus is None: |
|
st.write("Before we begin, would you like to focus on a specific area or keep the questions general?") |
|
focus_options = ["general", "professional background", "personal interests", "technical skills", "life experiences"] |
|
selected_focus = st.selectbox("Choose focus area:", focus_options) |
|
if st.button("Set Focus"): |
|
st.session_state.context_focus = selected_focus |
|
st.rerun() |
|
else: |
|
if st.button("Start Interview", type="primary", use_container_width=True): |
|
st.session_state.interview_started = True |
|
question = get_random_question(api_key, st.session_state.context_focus) |
|
st.session_state.messages.append(f"Q: {question}") |
|
st.rerun() |
|
|
|
elif st.session_state.interview_started and not st.session_state.interview_complete: |
|
|
|
last_message = st.session_state.messages[-1] |
|
|
|
|
|
if not last_message.startswith('Q:'): |
|
question = get_random_question(api_key, st.session_state.context_focus) |
|
st.session_state.messages.append(f"Q: {question}") |
|
st.rerun() |
|
|
|
|
|
user_answer = st.text_area("Your answer:", height=100) |
|
|
|
|
|
if st.button("Submit Answer"): |
|
if user_answer: |
|
st.session_state.messages.append(user_answer) |
|
st.rerun() |
|
|
|
|
|
if st.button("End Interview"): |
|
if len(st.session_state.messages) > 1: |
|
st.session_state.interview_complete = True |
|
|
|
st.session_state.context_data = extract_context(api_key, st.session_state.messages) |
|
st.rerun() |
|
else: |
|
st.warning("Please enter your OpenAI API key in the sidebar to begin.") |
|
|
|
with tab3: |
|
st.header("Feature Gallery") |
|
st.markdown("### Interactive Interview Process") |
|
st.image("screenshots/1.png", use_container_width=True) |
|
st.markdown("### Context Focus Selection") |
|
st.image("screenshots/2.png", use_container_width=True) |
|
st.markdown("### Generated Context Summary") |
|
st.image("screenshots/3.png", use_container_width=True) |
|
|
|
with tab4: |
|
if st.session_state.interview_complete and st.session_state.context_data: |
|
st.header("Generated Context") |
|
st.markdown(""" |
|
Below is the AI-generated context summary based on your interview responses. |
|
This structured data can be used to enhance future AI interactions and create |
|
more personalized experiences. |
|
""") |
|
st.markdown(st.session_state.context_data) |
|
|
|
|
|
st.subheader("Export Options") |
|
col3, col4 = st.columns(2) |
|
with col3: |
|
if st.button("Copy to Clipboard", type="secondary", use_container_width=True): |
|
st.write("Context copied to clipboard!") |
|
st.code(st.session_state.context_data) |
|
|
|
with col4: |
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
|
filename = f"context_data_{timestamp}.md" |
|
with open(filename, "w") as f: |
|
f.write(st.session_state.context_data) |
|
st.download_button( |
|
label="Download as Markdown", |
|
data=st.session_state.context_data, |
|
file_name=filename, |
|
mime="text/markdown", |
|
use_container_width=True |
|
) |
|
else: |
|
st.info("Complete the interview to generate your context summary.") |
|
|