File size: 16,932 Bytes
07aabce
 
228f205
62e10d6
 
 
 
 
 
228f205
62e10d6
 
 
 
228f205
 
4911494
54ff1eb
228f205
 
4911494
62e10d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a60d2b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62e10d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8513c92
62e10d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228f205
54a765f
 
 
 
228f205
5f639dd
 
727d404
 
 
 
 
 
 
 
 
 
 
 
 
f290ec9
 
 
 
 
 
 
 
 
 
63782e9
f290ec9
727d404
63782e9
727d404
228f205
333848e
727d404
 
 
d4e272e
727d404
 
5642940
5f639dd
62e10d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d12a771
a60d2b1
62e10d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb1b6a0
62e10d6
fb1b6a0
 
62e10d6
 
 
 
 
 
228f205
 
62e10d6
 
a60d2b1
62e10d6
 
 
 
 
b6e7533
 
 
 
 
 
62e10d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bcb54f4
a60d2b1
 
 
 
d4e272e
727d404
228f205
 
 
b6e7533
 
 
 
 
 
 
 
 
 
 
727d404
 
 
b6e7533
 
 
 
 
 
 
62e10d6
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
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()