import time import pandas as pd import streamlit as st import os import json from openai import AzureOpenAI from model import create_models, configure_settings, load_documents_and_create_index, \ create_chat_prompt_template, execute_query from datasets import Dataset, DatasetDict, load_dataset, concatenate_datasets client = AzureOpenAI(azure_endpoint="https://personality-service.openai.azure.com/", api_key=os.getenv("AZURE_OPENAI_KEY"), api_version="2024-02-15-preview") TOKEN = os.getenv('hf_token') def store_feedback(user_input, response, feedback, rating,repo): dataset = load_dataset(repo, token=TOKEN, download_mode="force_redownload", ignore_verifications=True) new_entry = pd.DataFrame({"user_input": [user_input], "response": [response], "feedback": [feedback], "rate": [rating]}) new_dataset = Dataset.from_pandas(new_entry) updated_dataset = concatenate_datasets([dataset["train"], new_dataset]) updated_dataset.push_to_hub(repo, private=False, token=TOKEN) # Function to generate a completion using OpenAI API def generate_one_completion(message, temperature): response = client.chat.completions.create( model="personality_gpt4o", temperature=temperature, max_tokens=1000, # Adjust based on desired response length frequency_penalty=0.2, # To avoid repetition presence_penalty=0.2, # To introduce new topics messages=message, stream=False ) return response import json def get_profile_str(profile): bio_info = profile['bio_information'] main_profile = profile['main_profile'] red_flag = profile['red_flag'] motivation = profile['motivation'] profile_str = f"Bio Information:\n" for key, value in bio_info.items(): profile_str += f"- {key.replace('_', ' ').title()}: {value}\n" profile_str += f"\nMain Profile:\n" for key, value in main_profile.items(): profile_str += f"- {key.title()}: {value['score']} - {value['summary']}\n" profile_str += f"\nRed Flags:\n" for key, value in red_flag.items(): profile_str += f"- {key.title()}: {value['score']} - {value['summary']}\n" profile_str += f"\nMotivation:\n" for key, value in motivation.items(): profile_str += f"- {key.title()}: {value['score']} - {value['summary']}\n" return profile_str def generate_prompt_from_profile(profile, version="TestTakersSummary"): with open('prompts.json') as f: prompt_sets = json.load(f)['Prompts'] prompt_templates = prompt_sets[version] try: # Fetching profile data individual_name = profile['bio_information'].get('Name', 'the individual') # Generating bio, profile, and red flags sections bio_section = "\n".join( [f"- {k.replace('_', ' ').title()}: {v}" for k, v in profile['bio_information'].items()]) main_profile_section = "\n".join( [f"- {trait.title()}: {details['score']} - {details['summary']}" for trait, details in profile['main_profile'].items()]) red_flags_section = "\n".join( [f"- {trait.title()}: {details['score']} - {details['summary']}" for trait, details in profile['red_flag'].items()]) motivation_section = "\n".join( [f"- {trait.title()}: {details['score']} - {details['summary']}" for trait, details in profile['motivation'].items()]) # Replacing placeholders in the prompts prompts = [ x.replace('{{INDIVIDUAL_NAME}}', individual_name).replace('{{BIO}}', bio_section).replace('{{PROFILE}}',main_profile_section).replace( '{{REDFLAGS_PROFILE}}', red_flags_section).replace('{{MOTIVATION_PROFILE}}', motivation_section) for x in prompt_templates] # Compiling final prompt prompt = "\n".join(prompts) except KeyError as e: return [{"role": "system", "content": f"Error processing profile data: missing {str(e)}"}] message = [ {"role": "system", "content": prompt_sets[version][0]}, {"role": "user", "content": prompt} ] return message def display_profile_info(profile): main_profile = profile["main_profile"] red_flag = profile["red_flag"] bio_info = profile["bio_information"] st.sidebar.markdown("### Bio Information: ") st.sidebar.markdown("\n".join([f"- **{key.replace('_', ' ')}**: {value}" for key, value in bio_info.items()])) st.sidebar.markdown("### Main Profile: ") st.sidebar.markdown("\n".join( [f"- **{attribute}**: {details['score']} - {details['summary']}" for attribute, details in main_profile.items()])) st.sidebar.markdown("### Red Flags: ") st.sidebar.markdown("\n".join( [f"- **{attribute}**: {details['score']} - {details['summary']}" for attribute, details in red_flag.items()])) st.sidebar.markdown("### Motivation: ") st.sidebar.markdown("\n".join( [f"- **{attribute}**: {details['score']} - {details['summary']}" for attribute, details in profile['motivation'].items()])) def validate_json(profile): required_keys = ['bio_information', 'main_profile', 'red_flag', 'motivation'] for key in required_keys: if key not in profile: return False, f"Key '{key}' is missing." if not isinstance(profile[key], dict): return False, f"'{key}' should be a dictionary." return True, "JSON structure is valid." def logout(): st.session_state['authenticated'] = False st.session_state['profile'] = None st.session_state['show_chat'] = None st.session_state['analysis'] = None st.rerun() def main_app(): sidebar_components() if st.button('Logout'): logout() # Streamlit app st.title('Metaprofiling\'s Career Insight Analyzer Demo') # Check if a profile is selected if st.session_state['profile']: profile = st.session_state['profile'] display_profile_info(profile) # Display the profile information st.markdown(""" ### Generation Temperature Adjust the 'Generation Temperature' to control the creativity of the AI responses. - A *lower temperature* (closer to 0.0) generates more predictable, conservative responses. - A *higher temperature* (closer to 1.0) generates more creative, diverse responses. """) # Temperature slider st.session_state['temperature'] = st.slider("", min_value=0.0, max_value=1.0, value=0.5, step=0.01) # Allow user to choose from different versions of the prompt st.session_state['version'] = st.selectbox("Select Prompt Version", ["TestTakersSummary", "ManagersSummary"]) # Generate and display prompt if st.button(f'Analyze Profile ({st.session_state["version"]})'): # with st.spinner('Generating completion...'): prompt = generate_prompt_from_profile(profile, version=st.session_state['version']) with st.chat_message("assistant"): stream = client.chat.completions.create( model="personality_gpt4o", temperature=st.session_state['temperature'], max_tokens=4096, # Adjust based on desired response length frequency_penalty=0.2, # To avoid repetition presence_penalty=0.2, # To introduce new topics messages=prompt, stream=True) response = st.write_stream(stream) # st.markdown(response_test_taker) st.session_state['analysis'] = response st.session_state['show_chat'] = True st.rerun() # display the response if st.session_state['analysis']: # Ask for feedback st.markdown(st.session_state['analysis']) # Ask the user to choose the type of feedback feedback_type = st.selectbox( "Select the type of feedback:", ["Report", "Coach"] ) # Set the dataset identifier based on feedback type if feedback_type == "Report": dataset_id = "wu981526092/feedback_report" else: dataset_id = "wu981526092/feedback_coach" st.markdown(f"Provide feedback on the {feedback_type.lower()}:") criteria = { "Faithfulness": "Are all claims made in the answer inferred from the given context, i.e., not hallucinated?", "Answer Relevancy": "Is the answer relevant to the question?", "Context Relevancy": "Is the context relevant to the question?", "Correctness": "Is the answer factually correct, based on the context?", "Clarity": "Is the answer explained clearly without the extensive jargon of the original document?", "Completeness": "Is the question answered fully, with all parts and subquestions being addressed?", } ratings = {} for criterion, description in criteria.items(): ratings[criterion] = st.slider(f"{criterion}: {description}", 0, 10, 5,key=f"{feedback_type} {criterion}") feedback = st.text_input("Provide additional feedback on the response:",key=f"{feedback_type} feedback") if st.button('Submit Report Feedback'): if feedback_type == "Report": store_feedback(str(generate_prompt_from_profile(profile, version=st.session_state['version'])), st.session_state['analysis'], feedback, str(ratings), dataset_id) else: store_feedback(str(st.session_state['coach_query']), str(st.session_state['coach_response']), feedback, str(ratings), dataset_id) st.success("Feedback submitted successfully!") else: st.write("Please upload a profile JSON file or use the example profile.") # Function to verify credentials and set the session state def verify_credentials(): if st.session_state['username'] == os.getenv("username_app") and st.session_state['password'] == os.getenv( "password_app"): st.session_state['authenticated'] = True else: st.error("Invalid username or password") # Login page def login_page(): st.title("Welcome to Metaprofiling's Career Insight Analyzer Demo") st.write( "This application provides in-depth analysis and insights into professional profiles. Please log in to continue.") # Description and Instructions st.markdown(""" ## How to Use This Application - Enter your username and password in the sidebar. - Click on 'Login' to access the application. - Once logged in, you will be able to upload and analyze professional profiles. """) st.sidebar.write("Login:") username = st.sidebar.text_input("Username") # , key='username') password = st.sidebar.text_input("Password", type="password") # , key='password') st.session_state['username'] = username st.session_state['password'] = password st.sidebar.button("Login", on_click=verify_credentials) def sidebar_components(): with st.sidebar: if st.button('Reset'): st.session_state['profile'] = None st.session_state['show_chat'] = None st.session_state['analysis'] = None st.rerun() if not st.session_state['show_chat']: # Instructions for JSON format st.markdown("### JSON File Requirements:") st.markdown("1. Must contain 'bio_information', 'main_profile', and 'red_flag' as top-level keys.") st.markdown("2. Both keys should have dictionary values.") st.markdown("### Choose the Definition:") st.session_state['definition'] = st.selectbox("Select Definition", [1, 2, 3]) st.session_state['chat_context'] = st.selectbox("Select Chat Context", ["analysis", "profile"]) # File uploader st.markdown("### Upload a profile JSON file") uploaded_file = st.file_uploader("", type=['json']) if uploaded_file is not None: try: profile_data = json.load(uploaded_file) valid, message = validate_json(profile_data) if valid: st.session_state['profile'] = profile_data else: st.error(message) except json.JSONDecodeError: st.error("Invalid JSON file. Please upload a valid JSON file.") # Button to load example profile if st.button('Use Example Profile'): if st.session_state['definition'] == 1: file_name = "example_data_definition_1.json" elif st.session_state['definition'] == 2: file_name = "example_data_definition_2.json" else: file_name = "example_data_definition_3.json" with open(file_name, 'r') as file: st.session_state['profile'] = json.load(file) else: st.sidebar.title("Chat with Our Career Advisor") #st.sidebar.markdown( #"Hello, we hope you learned something about yourself in this report. This chat is here so you can ask any questions you have about your report! It’s also a great tool to get ideas about how you can use the information in your report for your personal development and achieving your current goals.") # Name to be included in the questions # name = st.session_state['profile']['bio_information'].get('Name', 'the individual') # List of question templates where {} will be replaced with the name question_templates = [ "What are the main risks associated with {}’s profile?", "What are the implications of {}’s profile for working with others?", # "What conclusions might we draw from his profile about {}’s style of leadership?", # "Looking specifically at {}'s Red Flags, are there any particular areas of concern?", # "Based on this profile, is {} better suited as a COO or a CEO?", # "If speed of execution is important, based on his profile, how likely is {} to be able to achieve this?", # "How is {} likely to react to business uncertainty and disruption?", # "Based on his profile, what should a coaching plan designed for {} focus on?" ] # Formatting each question template with the name questions_list = [question.format("Test Taker") for question in question_templates] # Prepare the questions for Markdown display questions_markdown = "\n\n".join( [f"Q{index + 1}: {question}" for index, question in enumerate(questions_list)]) # Code to display in the app st.sidebar.markdown("### Suggest Questions") st.sidebar.markdown(questions_markdown) # st.sidebar.text_area("Suggested Questions", value=questions.choices[0].message.content, height=200, disabled=True) user_input = st.sidebar.text_input("Ask a question about the profile analysis:") llm, embed_model = create_models() configure_settings(llm, embed_model) index = load_documents_and_create_index() if st.sidebar.button('Submit'): if user_input: st.session_state['coach_query'] = str(user_input) if st.session_state['chat_context'] == "profile": chat_prompt_template = create_chat_prompt_template(get_profile_str(st.session_state['profile']),st.session_state['definition']) else: chat_prompt_template = create_chat_prompt_template(st.session_state['analysis'],st.session_state['definition']) st.session_state['coach_response'] = execute_query(index, chat_prompt_template, user_input) st.sidebar.markdown(st.session_state['coach_response']) # Initialize session state variables with default values if not already set session_defaults = { 'show_chat': None, 'definition': 1, 'chat_context': "analysis", 'profile': None, 'analysis': None, 'temperature': 0, 'version': "", 'username': '', 'password': '', 'authenticated': False, 'coach_response':"", 'coach_query':"" } for key, default in session_defaults.items(): if key not in st.session_state: st.session_state[key] = default # Show login or main app based on authentication status if st.session_state['authenticated']: main_app() else: login_page()