Spaces:
Runtime error
Runtime error
TTsamurai
commited on
Commit
•
31c7f82
1
Parent(s):
4d73160
update
Browse files- _static/html/evaluation_instruction.html +21 -0
- _static/html/final_evaluation.html +36 -0
- _static/html/general_instruction.html +27 -0
- _static/html/instruction_page.html +55 -0
- _static/html/system_instruction_preference_elicitation.html +21 -0
- _static/html/user_narrative.html +8 -0
- _static/txt/general_instruction_button.txt +1 -0
- _static/txt/general_instruction_task.txt +1 -0
- _static/txt/personality_ext.txt +1 -0
- _static/txt/personality_int.txt +1 -0
- _static/txt/system_instruction_non_personalization.txt +1 -0
- _static/txt/system_instruction_personality.txt +1 -0
- _static/txt/system_instruction_personalization.txt +1 -0
- _static/txt/system_instruction_preference_elicitation.txt +5 -0
- _static/txt/system_instruction_preference_elicitation_personality.txt +5 -0
- _static/txt/system_summarization_user_preference_elicitation.txt +1 -0
- app.py +1493 -0
- components/.ipynb_checkpoints/constant-checkpoint.py +12 -0
- components/__pycache__/chat_conversation.cpython-310.pyc +0 -0
- components/__pycache__/chat_conversation.cpython-38.pyc +0 -0
- components/__pycache__/chat_conversation.cpython-39.pyc +0 -0
- components/__pycache__/constant.cpython-310.pyc +0 -0
- components/__pycache__/constant.cpython-38.pyc +0 -0
- components/__pycache__/constant.cpython-39.pyc +0 -0
- components/__pycache__/induce_personality.cpython-310.pyc +0 -0
- components/__pycache__/induce_personality.cpython-38.pyc +0 -0
- components/__pycache__/induce_personality.cpython-39.pyc +0 -0
- components/__pycache__/prompt.cpython-310.pyc +0 -0
- components/__pycache__/prompt.cpython-38.pyc +0 -0
- components/__pycache__/prompt.cpython-39.pyc +0 -0
- components/__pycache__/query_rewriting.cpython-310.pyc +0 -0
- components/__pycache__/query_rewriting.cpython-38.pyc +0 -0
- components/__pycache__/rag_components.cpython-310.pyc +0 -0
- components/__pycache__/rag_components.cpython-38.pyc +0 -0
- components/__pycache__/rewrite_passages.cpython-310.pyc +0 -0
- components/__pycache__/rewrite_passages.cpython-38.pyc +0 -0
- components/chat_conversation.py +173 -0
- components/constant.py +19 -0
- components/induce_personality.py +34 -0
- components/prompt.py +10 -0
- components/query_rewriting.py +60 -0
- components/rag_components.py +190 -0
- components/rewrite_passages.py +94 -0
- data/single_stock_data/experiment_processed_data.jsonl +3 -0
- data/single_stock_data/single_stock_demo.jsonl +0 -0
- requirements.txt +3 -0
_static/html/evaluation_instruction.html
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin-bottom: 20px; max-height: 780px; overflow-y: auto; overflow-x: hidden;">
|
2 |
+
<h2 style="color: #2c3e50; text-align: center;">Evaluation Instructions</h2>
|
3 |
+
<p style="font-size: 16px; color: #34495e; line-height: 1.6;">
|
4 |
+
Welcome to the evaluation process! Please follow the steps below to complete your evaluation:
|
5 |
+
</p>
|
6 |
+
<ol style="font-size: 16px; color: #34495e; line-height: 1.8;">
|
7 |
+
<!-- <li><strong>Decision Making:</strong>Please respond with either <strong>Yes</strong> or <strong>No</strong> to the question: "Would you like to purchase the stock?"</li> -->
|
8 |
+
<!-- <li><strong>Reason:</strong> Write down the reason for your choice in the free text box labeled "The reason of your choice".</li> -->
|
9 |
+
<!-- <li><strong>A simple recall question:</strong>Which company were you discussing?</li> -->
|
10 |
+
<li><strong>Evaluation Criteria:</strong> Please evaluate the system in the following aspects:
|
11 |
+
<ul>
|
12 |
+
<li><strong>Likelihood of Purchase:</strong> Rate the likelihood of purchase.</li>
|
13 |
+
<li><strong>Reason:</strong> Write down the reason for your choice in the free text box labeled "The reason of your choice".</li>
|
14 |
+
<li><strong>Confidence in Your Decision:</strong> Rate the confidence in your decision.</li>
|
15 |
+
<li><strong>Familiarity Level</strong>:</strong> Rate your familiarity with the stock before the interaction.</li>
|
16 |
+
|
17 |
+
</ul>
|
18 |
+
</li>
|
19 |
+
<li>After completing all the evaluation criteria, <strong>click the "Send: Evaluation" button</strong> to submit your responses. <strong>Once you submit, you cannot resubmit, so please review your answers carefully before submitting.</strong></li>
|
20 |
+
</ol>
|
21 |
+
</div>
|
_static/html/final_evaluation.html
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin-bottom: 20px; max-height: 780px; overflow-y: auto; overflow-x: hidden;">
|
2 |
+
<!-- Heading -->
|
3 |
+
<h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
|
4 |
+
Instruction: Final Evaluation
|
5 |
+
</h2>
|
6 |
+
|
7 |
+
<!-- User Instruction -->
|
8 |
+
<p style="text-align: left; font-size: 16px; color: #34495e; margin-bottom: 20px;">
|
9 |
+
In the final evaluation, you will first rank the individual stocks below based on your discussion with your financial advisor, according to your desire to invest in each one. Use the following guidelines to assign a unique rank to each stock:
|
10 |
+
</p>
|
11 |
+
|
12 |
+
<!-- Ranking Instructions List -->
|
13 |
+
<ul style="font-size: 16px; color: #34495e; margin-left: 20px; margin-bottom: 20px;">
|
14 |
+
<li><strong>Rank 1:</strong> The stock you are most eager to invest in.</li>
|
15 |
+
<li><strong>Rank 2:</strong> The second most preferred stock for investment.</li>
|
16 |
+
<!-- <li><strong>Rank 3:</strong> A stock you are moderately interested in investing in.</li> -->
|
17 |
+
<li><strong>Rank 3:</strong> The second least preferred stock for investment.</li>
|
18 |
+
<li><strong>Rank 4:</strong> The stock you are least likely to invest in.</li>
|
19 |
+
<!-- <li><strong>Rank 5:</strong> The stock you are least likely to invest in.</li> -->
|
20 |
+
</ul>
|
21 |
+
|
22 |
+
<!-- Important Note -->
|
23 |
+
<p style="text-align: left; font-size: 16px; color: #e74c3c; margin-bottom: 20px;">
|
24 |
+
<strong>Important:</strong> Each stock must receive a different rank (from 1 to 4), and no two stocks can share the same rank.
|
25 |
+
</p>
|
26 |
+
|
27 |
+
<p style="text-align: left; font-size: 16px; color: #34495e; margin-bottom: 20px;">
|
28 |
+
Then, evaluate the advisor by choosing a number between <strong style="color:red;">1 (Strongly Disagree)</strong> and <strong style="color:green;">7 (Strongly Agree)</strong> for each statement.
|
29 |
+
</p>
|
30 |
+
|
31 |
+
|
32 |
+
<!-- Final Instruction -->
|
33 |
+
<p style="text-align: left; font-size: 16px; color: #34495e;">
|
34 |
+
After assigning a rank to each stock and evaluating the advisor, click the <strong>"Submit Ranking"</strong> button to submit your evaluation.
|
35 |
+
</p>
|
36 |
+
</div>
|
_static/html/general_instruction.html
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!-- Grouped Container for Task Instruction and Stock Information -->
|
2 |
+
<!-- Grouped Container for Task Instruction and Stock Information -->
|
3 |
+
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin-bottom: 20px; max-height: 780px; overflow-y: auto; overflow-x: hidden;">
|
4 |
+
<!-- Heading -->
|
5 |
+
<h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
|
6 |
+
Instruction: Financial Decision Stage
|
7 |
+
</h2>
|
8 |
+
|
9 |
+
<!-- User Instruction -->
|
10 |
+
<p style="text-align: left; font-size: 16px; color: #34495e; margin-bottom: 20px;">
|
11 |
+
<div>
|
12 |
+
<p>It is December 31, 2023. You are an investor interested in purchasing individual stocks. You understand and accept the risks involved, and you’ve come to consult a financial advisor for guidance on which individual stocks might suit your needs.</p>
|
13 |
+
|
14 |
+
<p>In this experiment, you will be presented with one stock per round over four rounds (a total of four stocks). For each stock, engage with the financial advisor to determine whether the stock is suitable for your needs or not. If you come across unfamiliar financial concepts or don’t fully understand what the financial advisor says, <strong>feel free to ask questions for clarification</strong>.</p>
|
15 |
+
|
16 |
+
Once <strong>you feel that you have gathered enough information to make a financial decision, you can move on to the evaluation phase</strong>.
|
17 |
+
|
18 |
+
Remember, the candidate stock has been <strong>randomly</strong> selected for this exploration and is <strong>not a recommendation</strong> from the financial advisor.
|
19 |
+
|
20 |
+
<!-- <p>If you don’t have a strong preference about certain characteristics of the stock, <span style="background-color: yellow;">you may simply state, “I don’t have a preference on this dimension.”</span></p> -->
|
21 |
+
<p>To interact with the financial advisor, first push the <strong>Start Conversation</strong> button. Then, type your message in the <strong>User Input</strong> textbox and press the <strong>Send This Message to Advisor</strong> button. If the response from the financial advisor is cut off due to word limitations, press the <strong>Show More of the Advisor’s Answer</strong> button to have the advisor continue the conversation. If you already have enough information to make a decision, you don’t need to press the <strong>Show More of the Advisor’s Answer</strong> button.</p>
|
22 |
+
|
23 |
+
<p>You will go through four rounds of financial decisions. Each round consists of a “Discussion (Discuss)” and an “Evaluation (Eval)” phase. Please move through the following sequence: 1-1: Discuss → 1-2: Eval → 2-1: Discuss → 2-2: Eval → … → 4-2: Eval.</p>
|
24 |
+
|
25 |
+
</div>
|
26 |
+
</p>
|
27 |
+
</div>
|
_static/html/instruction_page.html
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div style="font-family: Arial, sans-serif; line-height: 1.6; max-width: 800px; margin: auto; padding: 20px; background-color: #f9f9f9; border-radius: 10px;"></div>
|
2 |
+
<h2 style="color: #2c3e50; text-align: center;">Welcome to the Financial Advisory Experiment</h2>
|
3 |
+
<p style=" color: #34495e; text-align: center;">Please read the instructions carefully before beginning.</p>
|
4 |
+
|
5 |
+
<p style=" color: #34495e;">
|
6 |
+
In this experiment, you will role-play as a user profile and decide whether to purchase a stock by interacting with a financial advisor over four candidate stocks.
|
7 |
+
</p>
|
8 |
+
|
9 |
+
<div style="background-color: #eaf7f7; padding: 15px; border-left: 5px solid #17a2b8; margin-bottom: 20px;">
|
10 |
+
<strong>Step 1: Preference Elicitation Stage</strong>
|
11 |
+
<p>
|
12 |
+
During this stage, financial advisors will ask you a series of questions to gather insights into your investment preferences and needs. The information you provide will be used to guide the discussions and decisions in the subsequent stages. You will be assigned a user narrative that describes an investor interested in buying individual stocks but unsure of which to choose. <strong>Review the narrative thoroughly and role-play as the investor described.</strong>
|
13 |
+
</p>
|
14 |
+
</div>
|
15 |
+
|
16 |
+
<div style="background-color: #f2f5ff; padding: 15px; border-left: 5px solid #6c63ff; margin-bottom: 20px;">
|
17 |
+
<strong>Step 2: Financial Decision Stage</strong>
|
18 |
+
<p>
|
19 |
+
You will go through four rounds of financial decisions. Each round consists of a “Discussion (Discuss)” and an “Evaluation (Eval)” phase. Please move through the following sequence: 1-1: Discuss → 1-2: Eval → 2-1: Discuss → 2-2: Eval → … → 4-2: Eval.
|
20 |
+
</p>
|
21 |
+
<div style="margin-left: 20px;">
|
22 |
+
<h4 style="color: #6c63ff;">Discussion Phase (e.g., 1-1: Discuss)</h4>
|
23 |
+
<p style="color: #34495e;">
|
24 |
+
You will receive general instructions and information about the candidate stock, which has been <strong>randomly selected for this exploration</strong>. After understanding the instructions, engage with the financial advisor to make financial decisions. <strong>Once you feel that you have gathered enough information to make a financial decision, you can move on to the evaluation phase.</strong>
|
25 |
+
Please note, the candidate stock is <strong>not a recommendation</strong> from the financial advisor.
|
26 |
+
</p>
|
27 |
+
|
28 |
+
<h4 style="color: #6c63ff;">Evaluation Phase (e.g., 1-2: Eval)</h4>
|
29 |
+
<p style=" color: #34495e;">
|
30 |
+
Once you feel informed, switch to the Evaluation tab and complete your evaluation for the stock.
|
31 |
+
</p>
|
32 |
+
|
33 |
+
<h4 style="color: #6c63ff;">Next Round (e.g., 2-1: Discuss)</h4>
|
34 |
+
<p style=" color: #34495e;">
|
35 |
+
After completing the evaluation for one stock, move to the next stock tab and repeat the process. Continue until all four stocks have been evaluated.
|
36 |
+
</p>
|
37 |
+
</div>
|
38 |
+
</div>
|
39 |
+
|
40 |
+
<div style="background-color: #fff8e1; padding: 15px; border-left: 5px solid #ffc107; margin-bottom: 20px;">
|
41 |
+
<strong>Step 3: Final Evaluation</strong>
|
42 |
+
<p style="color: #34495e;">
|
43 |
+
Based on your conversations with your financial advisor, you will first rank the individual stocks according to your desire to invest in each one, then evaluate the advisor by answering the questions.
|
44 |
+
<strong>Assign a unique rank to each stock</strong> (1 being the most preferred, 4 being the least preferred), and <strong>answer all the questions</strong> (1 being strongly disagree, 7 being strongly agree).
|
45 |
+
</p>
|
46 |
+
</div>
|
47 |
+
<!-- Cautionary Guidelines -->
|
48 |
+
<div style="background-color: #fdecea; padding: 15px; border-left: 5px solid #e74c3c; margin-top: 20px;">
|
49 |
+
<h4 style="color: #e74c3c;">Cautionary Guidelines</h4>
|
50 |
+
<ul style="color: #34495e;">
|
51 |
+
<li>Do not <strong>refresh</strong> or <strong>reload</strong> the page. Doing so will result in <strong>loss of data</strong>, and you will have to <strong>restart the experiment</strong> from the beginning.</li>
|
52 |
+
<li>Please move through the following sequence: <strong>Experiment Instruction</strong> → <strong>Preference Elicitation Stage</strong> → <strong>Financial Decision Stage</strong> → <strong>Final Evaluation</strong>.</li>
|
53 |
+
</ul>
|
54 |
+
</div>
|
55 |
+
|
_static/html/system_instruction_preference_elicitation.html
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin-bottom: 20px; max-height: 780px; overflow-y: auto; overflow-x: hidden;">
|
2 |
+
<!-- Heading -->
|
3 |
+
<h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
|
4 |
+
Instruction: Preference Elicitation Stage
|
5 |
+
</h2>
|
6 |
+
|
7 |
+
<!-- User Instruction -->
|
8 |
+
<!-- <p style="text-align: left; font-size: 16px; color: #34495e; margin-bottom: 20px;">
|
9 |
+
It is December 31, 2023. You are an investor interested in purchasing individual stocks. You understand and accept the associated risks, and you’ve come to consult a financial advisor for guidance on which stocks may suit your needs.
|
10 |
+
In this stage, the financial advisor will ask you several questions to better understand your investment goals and preferences. When answering, it is not necessary to have a preference for every aspect of investing. If you do not have a preference regarding a particular dimension, you may simply state, “I don’t have a preference on this dimension.” Additionally, if there is anything you do not understand in what the advisor says, feel free to ask questions for clarification. This will help you gain a deeper understanding of the advice provided.
|
11 |
+
To interact with the financial advisor, first push the start conversation button. Then, type your message in the User Input textbox and press the Send This Message to Advisor button. If the response from the financial advisor is cut off due to word limitations, press the Show More of the Advisor’s Answer button to have the advisor continue the conversation. If you already have enough information to make a decision, you don’t need to press the Show More of the Advisor’s Answer button.
|
12 |
+
</p> -->
|
13 |
+
<p style="text-align: left; font-size: 16px; color: #34495e; margin-bottom: 20px; line-height: 1.6;">
|
14 |
+
It is December 31, 2023. You are an investor interested in purchasing individual stocks. You understand and accept the associated risks, and you’ve come to consult a financial advisor for guidance on which stocks may suit your needs.
|
15 |
+
<br><br>
|
16 |
+
This stage aims to explore and deepen the understanding of your investment preferences. Your financial advisor will ask several questions to better understand your investment goals and preferences. You don’t need to have a preference for every aspect of investing. <strong>If you’re asked about a topic where you have no preference, simply say, “I don’t have a preference on this topic.”</strong> Note that this stage focuses on your investment preferences. Specific details about individual stocks should be discussed during the financial decision stage.
|
17 |
+
<strong> Feel free to ask questions for clarification</strong> if there is anything you do not understand in what the advisor says. This will help you gain a deeper understanding of the advice provided.
|
18 |
+
<br><br>
|
19 |
+
To interact with the financial advisor, first push the <strong>Start Conversation</strong> button. Then, type your message in the <strong>User Input</strong> textbox and press the <strong>Send This Message to Advisor</strong> button. If the response from the financial advisor is cut off due to word limitations, press the <strong>Show More of the Advisor’s Answer</strong> button to have the advisor continue the conversation. If you already have enough information to make a decision, you don’t need to press the <strong>Show More of the Advisor’s Answer</strong> button.
|
20 |
+
</p>
|
21 |
+
</div>
|
_static/html/user_narrative.html
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!-- User Narrative (Bold label, Normal narrative) -->
|
2 |
+
<div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
|
3 |
+
User Narrative
|
4 |
+
</div>
|
5 |
+
<div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
|
6 |
+
{user_narrative}
|
7 |
+
</div>
|
8 |
+
</div>
|
_static/txt/general_instruction_button.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
To interact with the financial advisor, first push the start conversation button. Then, type your message in the Input: User Input textbox and press the Send: User Input button. If the response from the financial advisor is cut off due to word limitations, press the Continue button to have the advisor continue the conversation. If the response from the financial advisor is cut off due to word limitations, press the “Continue” button to have the advisor continue the conversation. If you already have enough information to make a decision, you don’t need to press the “Continue” button.
|
_static/txt/general_instruction_task.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
It is December 31, 2023. You are an investor interested in purchasing individual stocks. You understand and accept the risks involved, and you’ve come to consult a financial advisor for guidance on which individual stocks might suit your needs. In this experiment, you will be presented with one stock per round over five rounds (a total of five stocks). For each stock, engage with the financial advisor to determine whether the stock is suitable for your needs or not. If you come across unfamiliar financial concepts or don’t fully understand what the financial advisor says, be sure to ask for definitions or explanations.
|
_static/txt/personality_ext.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are extroverted (affectionate, friendly, fun-loving, confident), agreeable (cheerful, trusting, amiable, humble, polite, helpful), low in conscientious (reliable, consistent, perceptive), open to experience (insightful, original, clever, daring), and emotionally stable.
|
_static/txt/personality_int.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are introverted (reserved, quiet, insecure), antagonistic (skeptical, blunt, independent), conscientious (organized, disciplined, responsible), closed to experience (practical, thoughtful, cautious), and neurotic (anxious, nervous)
|
_static/txt/system_instruction_non_personalization.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a professional financial advisor speaking with a customer who is interested in purchasing individual stocks. In this session, you are faced with a candidate stock and work together to understand if it aligns with the customer. Remember, the stock was selected randomly, and you are not recommending this specific stock, nor do you know whether the customer has any particular interest in it. Your task is to interact with the customer, using the stock’s details to help them determine whether the stock is a good fit for them. Do not attempt to collect any users’ information, such as risk tolerance or preferred industries. Instead, assist the user in a non-personalized way. First, start the conversation by providing a brief description of the company, and then ask the customer what they would like to know more about. When asking questions to the customer, incorporate both open-ended and closed-ended questions when relevant, rather than sticking to only closed-ended questions. In this session, keep the conversation centered on the current candidate stock. Avoid discussing other stocks unless you are making a direct comparison to the candidate stock. If users attempt to shift the focus to other stocks, remind them to stay on topic or suggest moving to the next round. The main focus should always be the candidate stock. If the customer is unfamiliar with any financial concepts, explain them to help the customer make an informed decision. If you do not have the information the client has requested, please be honest and inform them that the data is not available. Keep responses concise, AT MOST ONE HUNDRED WORDS. If additional information is necessary, a longer response is acceptable, but aim to be brief and to the point.
|
_static/txt/system_instruction_personality.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a professional financial advisor speaking with a customer who is interested in purchasing individual stocks. {personality} Emphasize the personality in the conversation. Do not include any expressions in parentheses such as pauses, hesitations, or physical actions. The dialogue should focus purely on the verbal content of the conversation. In this session, you are faced with a candidate stock and work together to understand if it aligns with the customer. It’s important to tailor the information based on the user’s profile to ensure the conversation is personalized. Remember, the stock was selected randomly, and you are not recommending this specific stock, nor do you know whether the customer has any particular interest in it. User profile is provided below under “Previous Conversations with the Customer about the User Profile.” Your task is to interact with the customer, using the stock’s details and the user profile to help them determine whether the stock is a good fit for them in a personalized manner. First, start the conversation by providing a brief description of the company in a personalized manner, highlighting both the ways in which the company fits the user’s profile and any potential misalignments, and then ask the customer what they would like to know more about. When asking questions to the customer, incorporate both open-ended and closed-ended questions when relevant, rather than sticking to only closed-ended questions. In this session, keep the conversation centered on the current candidate stock. Avoid discussing other stocks unless you are making a direct comparison to the candidate stock. If users attempt to shift the focus to other stocks, remind them to stay on topic or suggest moving to the next round. The main focus should always be the candidate stock. If the customer is unfamiliar with any financial concepts, explain them to help the customer make an informed decision. If you do not have the information the client has requested, please be honest and inform them that the data is not available. Keep responses concise, AT MOST ONE HUNDRED WORDS. If additional information is necessary, a longer response is acceptable, but aim to be brief and to the point.
|
_static/txt/system_instruction_personalization.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a professional financial advisor speaking with a customer who is interested in purchasing individual stocks. In this session, you are faced with a candidate stock and work together to understand if it aligns with the customer. It’s important to tailor the information based on the user’s profile to ensure the conversation is personalized. Remember, the stock was selected randomly, and you are not recommending this specific stock, nor do you know whether the customer has any particular interest in it. User profile is provided below under “Previous Conversations with the Customer about the User Profile.” Your task is to interact with the customer, using the stock’s details and the user profile to help them determine whether the stock is a good fit for them in a personalized manner. First, start the conversation by providing a brief description of the company in a personalized manner, highlighting both the ways in which the company fits the user’s profile and any potential misalignments, and then ask the customer what they would like to know more about. When asking questions to the customer, incorporate both open-ended and closed-ended questions when relevant, rather than sticking to only closed-ended questions. In this session, keep the conversation centered on the current candidate stock. Avoid discussing other stocks unless you are making a direct comparison to the candidate stock. If users attempt to shift the focus to other stocks, remind them to stay on topic or suggest moving to the next round. The main focus should always be the candidate stock. If the customer is unfamiliar with any financial concepts, explain them to help the customer make an informed decision. If you do not have the information the client has requested, please be honest and inform them that the data is not available. Keep responses concise, AT MOST ONE HUNDRED WORDS. If additional information is necessary, a longer response is acceptable, but aim to be brief and to the point.
|
_static/txt/system_instruction_preference_elicitation.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are a financial advisor discussing individual stocks with a customer. Your goal is to understand their investment preferences in the following areas: preferred industries, value or growth stocks, dividend or non-dividend stocks, and cyclical or non-cyclical stocks. Engage the client in conversation, addressing each topic one by one. Start conversation by asking the preferred industry first.
|
2 |
+
|
3 |
+
Keep responses concise (AT MOST EIGHTY WORDS). If needed, longer responses are acceptable, but aim to be brief. Avoid discussing topics outside of these preferences. The purpose of this stage is to understand the customers’ investment preferences. Please avoid discussing specific stocks during this process. If the client tries to shift the focus, remind them that specific stock details will be covered in the next round, and this session is solely about preferences. If they are unfamiliar with any financial concepts, provide clear explanations to assist them.
|
4 |
+
|
5 |
+
Once you’ve gathered all the information, say: *“Thank you for the conversation, please move on to the next section.”*
|
_static/txt/system_instruction_preference_elicitation_personality.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are a professional financial advisor discussing individual stocks with a customer. {personality} Emphasize the personality in the conversation. Do not include any expressions in parentheses such as pauses, hesitations, or physical actions. The dialogue should focus purely on the verbal content of the conversation. Your goal is to understand their investment preferences in the following areas: preferred industries, value or growth stocks, dividend or non-dividend stocks, and cyclical or non-cyclical stocks. Engage the client in conversation, addressing each topic one by one. Start conversation by asking the preferred industry first.
|
2 |
+
|
3 |
+
Keep responses concise (AT MOST EIGHTY WORDS). If needed, longer responses are acceptable, but aim to be brief. Avoid discussing topics outside of these preferences. The purpose of this stage is to understand the customers’ investment preferences. Please avoid discussing specific stocks during this process. If the client tries to shift the focus, remind them that specific stock details will be covered in the next round, and this session is solely about preferences. If they are unfamiliar with any financial concepts, provide clear explanations to assist them.
|
4 |
+
|
5 |
+
Once you’ve gathered all the information, say: *“Thank you for the conversation, please move on to the next section.”*
|
_static/txt/system_summarization_user_preference_elicitation.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a financial advisor. Summarize a previous conversation with a customer about their investment preferences in four areas: preferred industries, value vs. growth stocks, dividend vs. non-dividend stocks, and cyclical vs. non-cyclical stocks. If the customer has not expressed a preference in any of these areas, clearly indicate that the preference for that specific aspect has not been discussed. Keep the summary very simple, omitting any unnecessary details.
|
app.py
ADDED
@@ -0,0 +1,1493 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
import os
|
3 |
+
from datetime import datetime
|
4 |
+
import json
|
5 |
+
import uuid
|
6 |
+
from pathlib import Path
|
7 |
+
from huggingface_hub import CommitScheduler, login
|
8 |
+
from datasets import load_dataset
|
9 |
+
import gradio as gr
|
10 |
+
import markdown
|
11 |
+
from together import Together
|
12 |
+
|
13 |
+
ROOT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "./")
|
14 |
+
sys.path.append(ROOT_FILE)
|
15 |
+
from components.induce_personality import construct_big_five_words
|
16 |
+
from components.chat_conversation import (
|
17 |
+
# format_message_history,
|
18 |
+
format_user_message,
|
19 |
+
format_context,
|
20 |
+
gradio_to_huggingface_message,
|
21 |
+
huggingface_to_gradio_message,
|
22 |
+
# get_system_instruction,
|
23 |
+
prepare_tokenizer,
|
24 |
+
# format_rag_context,
|
25 |
+
conversation_window,
|
26 |
+
generate_response_local_api,
|
27 |
+
generate_response_together_api,
|
28 |
+
generate_response_debugging,
|
29 |
+
)
|
30 |
+
from components.constant import (
|
31 |
+
CONV_WINDOW,
|
32 |
+
API_URL,
|
33 |
+
)
|
34 |
+
from components.induce_personality import (
|
35 |
+
build_personality_prompt,
|
36 |
+
)
|
37 |
+
|
38 |
+
LOG_DIR = os.path.join(ROOT_FILE, "log/api/")
|
39 |
+
if os.path.exists(LOG_DIR) is False:
|
40 |
+
os.makedirs(LOG_DIR)
|
41 |
+
|
42 |
+
# Load Static Files
|
43 |
+
STATIC_FILE = os.path.join(ROOT_FILE, "_static")
|
44 |
+
LOG_DIR = os.path.join(ROOT_FILE, "log/test_session/")
|
45 |
+
INSTRUCTION_PAGE_FILE = os.path.join(STATIC_FILE, "html/instruction_page.html")
|
46 |
+
USER_NARRATIVE_FILE = os.path.join(STATIC_FILE, "html/user_narrative.html")
|
47 |
+
PREFERENCE_ELICITATION_TASK_FILE = os.path.join(STATIC_FILE, "html/system_instruction_preference_elicitation.html")
|
48 |
+
EVALUATION_INSTRUCTION_FILE = os.path.join(STATIC_FILE, "html/evaluation_instruction.html")
|
49 |
+
GENERAL_INSTRUCTION_FILE = os.path.join(STATIC_FILE, "html/general_instruction.html")
|
50 |
+
FINAL_EVALUATION_FILE = os.path.join(STATIC_FILE, "html/final_evaluation.html")
|
51 |
+
SYSTEM_INSTRUCTION_PERSONALIZATION_FILE = os.path.join(STATIC_FILE, "txt/system_instruction_personalization.txt")
|
52 |
+
SYSTEM_INSTRUCTION_NON_PERSONALIZATION_FILE = os.path.join(
|
53 |
+
STATIC_FILE, "txt/system_instruction_non_personalization.txt"
|
54 |
+
)
|
55 |
+
SYSTEM_INSTRUCTION_PERSONALITY_FILE = os.path.join(STATIC_FILE, "txt/system_instruction_personality.txt")
|
56 |
+
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_FILE = os.path.join(
|
57 |
+
STATIC_FILE, "txt/system_instruction_preference_elicitation.txt"
|
58 |
+
)
|
59 |
+
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY_FILE = os.path.join(
|
60 |
+
STATIC_FILE, "txt/system_instruction_preference_elicitation_personality.txt"
|
61 |
+
)
|
62 |
+
SUMMARIZATION_PROMPT_FILE = os.path.join(STATIC_FILE, "txt/system_summarization_user_preference_elicitation.txt")
|
63 |
+
PERSONALITY_EXT_FILE = os.path.join(STATIC_FILE, "txt/personality_ext.txt")
|
64 |
+
PERSONALITY_INT_FILE = os.path.join(STATIC_FILE, "txt/personality_int.txt")
|
65 |
+
|
66 |
+
uuid_this_session = str(uuid.uuid4())
|
67 |
+
system_order = "demo"
|
68 |
+
feedback_file_interaction = Path("demo_user_feedback/") / f"interaction_{uuid_this_session}_{system_order}.json"
|
69 |
+
feedback_file_summarization = Path("demo_user_feedback/") / f"summarization_{uuid_this_session}_{system_order}.json"
|
70 |
+
feedback_file_round_evaluation = (
|
71 |
+
Path("demo_user_feedback/") / f"round_evaluation_{uuid_this_session}_{system_order}.json"
|
72 |
+
)
|
73 |
+
feedback_file_final_ranking = Path("demo_user_feedback/") / f"final_ranking_{uuid_this_session}_{system_order}.json"
|
74 |
+
feedback_file_final_survey = Path("demo_user_feedback/") / f"final_survey_{uuid_this_session}_{system_order}.json"
|
75 |
+
feedback_folder = feedback_file_interaction.parent
|
76 |
+
feedback_folder.mkdir(parents=True, exist_ok=True) # Ensure the directory exists
|
77 |
+
|
78 |
+
# scheduler = CommitScheduler(
|
79 |
+
# repo_id=os.getenv("LOGGING_FILE"),
|
80 |
+
# repo_type="dataset",
|
81 |
+
# folder_path=feedback_folder,
|
82 |
+
# path_in_repo="data",
|
83 |
+
# token=os.getenv("HUGGINGFACE_HUB_TOKEN"),
|
84 |
+
# every=1,
|
85 |
+
# )
|
86 |
+
scheduler = None
|
87 |
+
|
88 |
+
|
89 |
+
# Function to save user feedback
|
90 |
+
def save_feedback(user_id: str, uuid: str, type: str, value, feedback_file) -> None:
|
91 |
+
"""
|
92 |
+
Append input/outputs and user feedback to a JSON Lines file using a thread lock to avoid concurrent writes from different users.
|
93 |
+
"""
|
94 |
+
# timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
95 |
+
# with scheduler.lock:
|
96 |
+
# with feedback_file.open("a") as f:
|
97 |
+
# f.write(
|
98 |
+
# json.dumps({"user_id": user_id, "uuid": uuid, "timestamp": timestamp, "type": type, "value": value})
|
99 |
+
# )
|
100 |
+
# f.write("\n")
|
101 |
+
pass
|
102 |
+
|
103 |
+
|
104 |
+
# Load the required static content from files
|
105 |
+
def load_static_content(file_path):
|
106 |
+
|
107 |
+
with open(file_path, "r") as f:
|
108 |
+
return f.read()
|
109 |
+
|
110 |
+
|
111 |
+
def ensure_directory_exists(directory_path):
|
112 |
+
"""Ensures the given directory exists; creates it if it does not."""
|
113 |
+
if not os.path.exists(directory_path):
|
114 |
+
os.makedirs(directory_path)
|
115 |
+
|
116 |
+
|
117 |
+
INSTRUCTION_PAGE = load_static_content(INSTRUCTION_PAGE_FILE)
|
118 |
+
EVALUATION_INSTRUCTION = load_static_content(EVALUATION_INSTRUCTION_FILE)
|
119 |
+
GENERAL_INSTRUCTION = load_static_content(GENERAL_INSTRUCTION_FILE)
|
120 |
+
USER_NARRATIVE = load_static_content(USER_NARRATIVE_FILE)
|
121 |
+
PREFERENCE_ELICITATION_TASK = load_static_content(PREFERENCE_ELICITATION_TASK_FILE)
|
122 |
+
FINAL_EVALUATION = load_static_content(FINAL_EVALUATION_FILE)
|
123 |
+
SYSTEM_INSTRUCTION_PERSONALIZATION = load_static_content(SYSTEM_INSTRUCTION_PERSONALIZATION_FILE)
|
124 |
+
SYSTEM_INSTRUCTION_NON_PERSONALIZATION = load_static_content(SYSTEM_INSTRUCTION_NON_PERSONALIZATION_FILE)
|
125 |
+
SYSTEM_INSTRUCTION_PERSONALITY = load_static_content(SYSTEM_INSTRUCTION_PERSONALITY_FILE)
|
126 |
+
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION = load_static_content(SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_FILE)
|
127 |
+
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY = load_static_content(
|
128 |
+
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY_FILE
|
129 |
+
)
|
130 |
+
SUMMARIZATION_PROMPT = load_static_content(SUMMARIZATION_PROMPT_FILE)
|
131 |
+
PERSONALITY_EXT = load_static_content(PERSONALITY_EXT_FILE)
|
132 |
+
PERSONALITY_INT = load_static_content(PERSONALITY_INT_FILE)
|
133 |
+
|
134 |
+
# Other constants
|
135 |
+
FIRST_MESSAGE = "Hey"
|
136 |
+
USER_PREFERENCE_SUMMARY = True
|
137 |
+
DEBUG = False
|
138 |
+
API_TYPE = "together"
|
139 |
+
assert API_TYPE in ["together", "local", "debug"], "The API should be either 'together' or 'local'"
|
140 |
+
if API_TYPE == "together":
|
141 |
+
TOGETHER_CLIENT = Together(api_key=os.getenv("TOGETHER_API_KEY"))
|
142 |
+
|
143 |
+
|
144 |
+
def generate_username_pwd_list(data):
|
145 |
+
user_list = []
|
146 |
+
demo_list = []
|
147 |
+
for index, row in data.iterrows():
|
148 |
+
user_list.append((row["user"], str(row["pwd"])))
|
149 |
+
demo_list.append((row["demo"], str(row["pwd"])))
|
150 |
+
return user_list, demo_list
|
151 |
+
|
152 |
+
|
153 |
+
def load_username_and_pwd():
|
154 |
+
login(token=os.environ["HUGGINGFACE_HUB_TOKEN"])
|
155 |
+
dataset = load_dataset(os.getenv("USER_PWD_FILE"))
|
156 |
+
df = dataset["train"].to_pandas()
|
157 |
+
user_list, demo_list = generate_username_pwd_list(df)
|
158 |
+
return user_list, demo_list
|
159 |
+
|
160 |
+
|
161 |
+
def get_context_list(synthetic_data_path):
|
162 |
+
# Load data from the synthetic data file
|
163 |
+
with open(synthetic_data_path, "r") as f:
|
164 |
+
data = [json.loads(line) for line in f]
|
165 |
+
|
166 |
+
return data
|
167 |
+
|
168 |
+
|
169 |
+
def add_ticker_prefix(ticker_list, context_list):
|
170 |
+
res = []
|
171 |
+
for ticker, context in zip(ticker_list, context_list):
|
172 |
+
res.append(f"{ticker}: {context}")
|
173 |
+
return res
|
174 |
+
|
175 |
+
|
176 |
+
def build_raw_context_list(context_dict):
|
177 |
+
return context_dict["data"]
|
178 |
+
|
179 |
+
|
180 |
+
def build_context(context_dict):
|
181 |
+
return [build_context_element(context) for context in context_dict["data"]]
|
182 |
+
|
183 |
+
|
184 |
+
def build_context_element(context):
|
185 |
+
# [{topic: ex, data: {}}, {..}, ..]
|
186 |
+
# Extract information from the context
|
187 |
+
ticker = context["ticker"]
|
188 |
+
sector = context["sector"]
|
189 |
+
business_summary = context["business_summary"]
|
190 |
+
name = context["short_name"]
|
191 |
+
stock_price = context["price_data"]
|
192 |
+
earning = context["earning_summary"]
|
193 |
+
beta = context["beta"]
|
194 |
+
|
195 |
+
# Build the context string
|
196 |
+
stock_candidate = f"Stock Candidate: {name}"
|
197 |
+
stock_info = f"Stock Information: \nIndustry - {sector}, \nBeta (risk indicator) - {beta}, \nEarning Summary - {earning}\n, 2023 Monthly Stock Price - {stock_price}\n, Business Summary - {business_summary}"
|
198 |
+
|
199 |
+
context_list = [stock_candidate, stock_info]
|
200 |
+
|
201 |
+
# Combine all parts into a single string
|
202 |
+
return "\n".join(context_list)
|
203 |
+
|
204 |
+
|
205 |
+
def get_user_narrative_html(user_narrative):
|
206 |
+
return USER_NARRATIVE.replace("{user_narrative}", user_narrative).replace("\n", "<br>")
|
207 |
+
|
208 |
+
|
209 |
+
def get_user_narrative_from_raw(raw_narrative):
|
210 |
+
return get_user_narrative_html(markdown.markdown(raw_narrative.replace("\n", "<br>")))
|
211 |
+
|
212 |
+
|
213 |
+
def get_task_instruction_for_user(context):
|
214 |
+
ticker_name = context["short_name"]
|
215 |
+
user_narrative = context["user_narrative"]
|
216 |
+
user_narrative = user_narrative.replace("\n", "<br>")
|
217 |
+
html_user_narrative = markdown.markdown(user_narrative)
|
218 |
+
general_instruction = GENERAL_INSTRUCTION
|
219 |
+
round_instruction = f"""
|
220 |
+
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin-bottom: 20px; max-height: 780px; overflow-y: auto; overflow-x: hidden;">
|
221 |
+
<!-- Stock Information (Bold label, Normal ticker name) -->
|
222 |
+
<h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
|
223 |
+
Round Info
|
224 |
+
</h2>
|
225 |
+
<div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
|
226 |
+
Stock
|
227 |
+
</div>
|
228 |
+
<div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
|
229 |
+
<span style="font-weight: bold;">
|
230 |
+
This Round's Stock:
|
231 |
+
</span>
|
232 |
+
{ticker_name}
|
233 |
+
</div>
|
234 |
+
|
235 |
+
<!-- User Narrative (Bold label, Normal narrative) -->
|
236 |
+
<div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
|
237 |
+
User Narrative
|
238 |
+
</div>
|
239 |
+
<div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
|
240 |
+
{html_user_narrative}
|
241 |
+
</div>
|
242 |
+
</div>"""
|
243 |
+
|
244 |
+
return general_instruction, round_instruction
|
245 |
+
|
246 |
+
|
247 |
+
def display_system_instruction_with_html(
|
248 |
+
system_instruction,
|
249 |
+
):
|
250 |
+
html_system_instruction = f"""
|
251 |
+
<p style="text-align: left; margin-bottom: 10px;">
|
252 |
+
{system_instruction}
|
253 |
+
</p>
|
254 |
+
"""
|
255 |
+
return html_system_instruction
|
256 |
+
|
257 |
+
|
258 |
+
def log_action(user_id, tab_name, action, details):
|
259 |
+
"""
|
260 |
+
Log actions for each tab (stock).
|
261 |
+
"""
|
262 |
+
log_file_dir = os.path.join(LOG_DIR, f"{user_id}")
|
263 |
+
if os.path.exists(log_file_dir) is False:
|
264 |
+
os.makedirs(log_file_dir)
|
265 |
+
log_file = os.path.join(log_file_dir, f"{tab_name}.txt")
|
266 |
+
with open(log_file, "a") as f:
|
267 |
+
f.write(f"Action: {action} | Details: {details}\n")
|
268 |
+
|
269 |
+
|
270 |
+
def add_user_profile_to_system_instruction(
|
271 |
+
user_id, system_instruction, user_preference_elicitation_data, summary, terminator
|
272 |
+
):
|
273 |
+
exp_id = int(user_id.split("_")[-3])
|
274 |
+
# exp_id = 1 => No personalization
|
275 |
+
if exp_id == 1:
|
276 |
+
return system_instruction
|
277 |
+
if summary:
|
278 |
+
if user_preference_elicitation_data["summary_history"] == "":
|
279 |
+
# Format prompt
|
280 |
+
summarization_prompt = SUMMARIZATION_PROMPT + "\nPrevious Conversations: {}".format(
|
281 |
+
user_preference_elicitation_data["history"]
|
282 |
+
)
|
283 |
+
summarization_instruction = [{"role": "system", "content": summarization_prompt}]
|
284 |
+
if API_TYPE == "local":
|
285 |
+
summ, _ = generate_response_local_api(summarization_instruction, terminator, 512, API_URL)
|
286 |
+
elif API_TYPE == "together":
|
287 |
+
summ, _ = generate_response_together_api(summarization_instruction, 512, TOGETHER_CLIENT)
|
288 |
+
else:
|
289 |
+
summ, _ = generate_response_debugging(summarization_instruction)
|
290 |
+
user_preference_elicitation_data["summary_history"] = summ
|
291 |
+
# log_action(user_id, "Prompt", "Preference Elicitation Summarization", summ)
|
292 |
+
save_feedback(
|
293 |
+
user_id,
|
294 |
+
uuid_this_session,
|
295 |
+
"preference_elicitation_summarization",
|
296 |
+
{"summarization": summ},
|
297 |
+
feedback_file_summarization,
|
298 |
+
)
|
299 |
+
system_instruction += f"\nUser Profile collected in the previous conversations: {user_preference_elicitation_data['summary_history']}\n"
|
300 |
+
else:
|
301 |
+
system_instruction += (
|
302 |
+
f"\nUser Profile collected in the previous conversations: {user_preference_elicitation_data['history']}\n"
|
303 |
+
)
|
304 |
+
return system_instruction
|
305 |
+
|
306 |
+
|
307 |
+
def likert_evaluation(content):
|
308 |
+
return gr.Radio(
|
309 |
+
[1, 2, 3, 4, 5, 6, 7],
|
310 |
+
label=f"{content}",
|
311 |
+
show_label=True,
|
312 |
+
)
|
313 |
+
|
314 |
+
|
315 |
+
def reorder_list_based_on_user_in_narrative_id(user_in_narrative_id, target_list):
|
316 |
+
# user_in_narrative
|
317 |
+
random_order = {"0": [3, 2, 1, 0], "1": [1, 0, 3, 2], "2": [2, 1, 0, 3], "3": [1, 3, 2, 0], "4": [0, 3, 1, 2]}
|
318 |
+
user_in_narrative_random = random_order[user_in_narrative_id]
|
319 |
+
return [target_list[i] for i in user_in_narrative_random]
|
320 |
+
|
321 |
+
|
322 |
+
def create_demo():
|
323 |
+
global context_info_list, terminator
|
324 |
+
|
325 |
+
def tab_creation_personality_injection(system_description_without_context, system_description_user_elicitation):
|
326 |
+
def personality_results(openness, conscientiousness, extraversion, agreeableness, neuroticism):
|
327 |
+
result = f"""
|
328 |
+
<div style="background-color: #f7f9fc; padding: 30px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); max-width: 600px; margin: auto; font-family: Arial, sans-serif; color: #333;">
|
329 |
+
<h3 style="font-size: 24px; color: #4a90e2; text-align: center; margin-bottom: 20px;">The Advisor Big Five Personality Traits</h3>
|
330 |
+
<ul style="list-style-type: none; padding: 0;">
|
331 |
+
<li style="font-size: 18px; padding: 12px 0; border-bottom: 1px solid #ddd;"><strong>Openness to Experience:</strong> {openness}</li>
|
332 |
+
<li style="font-size: 18px; padding: 12px 0; border-bottom: 1px solid #ddd;"><strong>Conscientiousness:</strong> {conscientiousness}</li>
|
333 |
+
<li style="font-size: 18px; padding: 12px 0; border-bottom: 1px solid #ddd;"><strong>Extraversion:</strong> {extraversion}</li>
|
334 |
+
<li style="font-size: 18px; padding: 12px 0; border-bottom: 1px solid #ddd;"><strong>Agreeableness:</strong> {agreeableness}</li>
|
335 |
+
<li style="font-size: 18px; padding: 12px 0;"><strong>Neuroticism:</strong> {neuroticism}</li>
|
336 |
+
</ul>
|
337 |
+
</div>
|
338 |
+
"""
|
339 |
+
return result
|
340 |
+
|
341 |
+
def respond_personality(
|
342 |
+
openness,
|
343 |
+
conscientiousness,
|
344 |
+
extraversion,
|
345 |
+
agreeableness,
|
346 |
+
neuroticism,
|
347 |
+
system_description_without_context,
|
348 |
+
system_description_user_elicitation,
|
349 |
+
):
|
350 |
+
prompt_personality = (
|
351 |
+
build_personality_prompt(
|
352 |
+
[extraversion, agreeableness, conscientiousness, neuroticism, openness],
|
353 |
+
)
|
354 |
+
+ " Emphasize your personality in the conversation."
|
355 |
+
)
|
356 |
+
print(prompt_personality)
|
357 |
+
return (
|
358 |
+
personality_results(openness, conscientiousness, extraversion, agreeableness, neuroticism),
|
359 |
+
system_description_without_context.format(personality=prompt_personality),
|
360 |
+
system_description_user_elicitation.format(personality=prompt_personality),
|
361 |
+
)
|
362 |
+
|
363 |
+
gr.Markdown("# Personality Injection Module")
|
364 |
+
gr.Markdown("Select one option for each trait that best describes you.")
|
365 |
+
# openness_options = ["🌟 Open to experience", "🚪 Closed to experience"]
|
366 |
+
# conscientiousness_options = ["✅ Conscientious", "🎲 Unconscientious"]
|
367 |
+
# extraversion_options = ["😃 Extroverted", "🤫 Introverted"]
|
368 |
+
# agreeableness_options = ["😊 Agreeable", "😠 Antagonistic"]
|
369 |
+
# neuroticism_options = ["😰 Neurotic", "😌 Emotionally stable"]
|
370 |
+
openness_options = ["open to experience", "closed to experience"]
|
371 |
+
conscientiousness_options = ["conscientious", "unconscientious"]
|
372 |
+
extraversion_options = ["extroverted", "introverted"]
|
373 |
+
agreeableness_options = ["agreeable", "antagonistic"]
|
374 |
+
neuroticism_options = ["neurotic", "emotionally stable"]
|
375 |
+
|
376 |
+
with gr.Row():
|
377 |
+
with gr.Column():
|
378 |
+
openness = gr.Radio(openness_options, label="Openness to Experience")
|
379 |
+
conscientiousness = gr.Radio(conscientiousness_options, label="Conscientiousness")
|
380 |
+
extraversion = gr.Radio(extraversion_options, label="Extraversion")
|
381 |
+
agreeableness = gr.Radio(agreeableness_options, label="Agreeableness")
|
382 |
+
neuroticism = gr.Radio(neuroticism_options, label="Neuroticism")
|
383 |
+
with gr.Row():
|
384 |
+
personality_submit_button = gr.Button(value="Submit")
|
385 |
+
with gr.Column():
|
386 |
+
with gr.Row():
|
387 |
+
output = gr.HTML()
|
388 |
+
personality_submit_button.click(
|
389 |
+
lambda openness, conscientiousness, extraversion, agreeableness, neuroticism, system_description_without_context, system_description_user_elicitation,: respond_personality(
|
390 |
+
openness,
|
391 |
+
conscientiousness,
|
392 |
+
extraversion,
|
393 |
+
agreeableness,
|
394 |
+
neuroticism,
|
395 |
+
system_description_without_context,
|
396 |
+
system_description_user_elicitation,
|
397 |
+
),
|
398 |
+
[
|
399 |
+
openness,
|
400 |
+
conscientiousness,
|
401 |
+
extraversion,
|
402 |
+
agreeableness,
|
403 |
+
neuroticism,
|
404 |
+
system_description_without_context,
|
405 |
+
system_description_user_elicitation,
|
406 |
+
],
|
407 |
+
[output, system_description_without_context, system_description_user_elicitation],
|
408 |
+
)
|
409 |
+
return {
|
410 |
+
"personality_button": personality_submit_button,
|
411 |
+
"traits": [openness, conscientiousness, extraversion, agreeableness, neuroticism],
|
412 |
+
}
|
413 |
+
|
414 |
+
def tab_creation_exploration_stage(order, comp, context):
|
415 |
+
english_order = ["1", "2", "3", "4", "5"]
|
416 |
+
with gr.Tab(f"{english_order[order]}-1:Discuss"):
|
417 |
+
general_instruction = gr.HTML(label="General Instruction")
|
418 |
+
with gr.Row():
|
419 |
+
with gr.Column():
|
420 |
+
with gr.Row():
|
421 |
+
round_instruction = gr.HTML(label="Round Instruction")
|
422 |
+
with gr.Column():
|
423 |
+
with gr.Row():
|
424 |
+
chatbot = gr.Chatbot(height=600)
|
425 |
+
with gr.Row():
|
426 |
+
start_conversation = gr.Button(value="Start Conversation")
|
427 |
+
with gr.Row():
|
428 |
+
msg = gr.Textbox(scale=1, label="User Input")
|
429 |
+
with gr.Row():
|
430 |
+
msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
|
431 |
+
continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
|
432 |
+
with gr.Row():
|
433 |
+
clear = gr.ClearButton([msg, chatbot])
|
434 |
+
with gr.Tab(f"{english_order[order]}-2:Eval"):
|
435 |
+
with gr.Row():
|
436 |
+
gr.HTML(value=EVALUATION_INSTRUCTION)
|
437 |
+
with gr.Row():
|
438 |
+
likelihood = gr.Radio(
|
439 |
+
[1, 2, 3, 4, 5, 6, 7],
|
440 |
+
label="I am likely to purchase the stock (1 = Strongly Disagree, 7 = Strongly Agree)",
|
441 |
+
show_label=True,
|
442 |
+
)
|
443 |
+
reason = gr.Textbox(
|
444 |
+
scale=1,
|
445 |
+
label="Reason for Your Choice (Explain Your Reasoning & Highlight Useful Parts of Conversation)",
|
446 |
+
lines=5,
|
447 |
+
)
|
448 |
+
with gr.Row():
|
449 |
+
confidence = gr.Radio(
|
450 |
+
[1, 2, 3, 4, 5, 6, 7],
|
451 |
+
label="I am confident in my decision (1 = Strongly Disagree, 7 = Strongly Agree)",
|
452 |
+
show_label=True,
|
453 |
+
)
|
454 |
+
familiarity = gr.Radio(
|
455 |
+
[1, 2, 3, 4, 5, 6, 7],
|
456 |
+
label="What was your level of familiarity with the candidate stock before the interaction? (1 = Not Familiar, 7 = Very Familiar)",
|
457 |
+
)
|
458 |
+
with gr.Row():
|
459 |
+
textbox = gr.HTML()
|
460 |
+
evaluation_send_button = gr.Button(value="Send: Evaluation")
|
461 |
+
return {
|
462 |
+
"comp": comp,
|
463 |
+
"system_instruction_context": context,
|
464 |
+
"start_conversation": start_conversation,
|
465 |
+
"msg_button": msg_button,
|
466 |
+
"continue_button": continue_button,
|
467 |
+
"chatbot": chatbot,
|
468 |
+
"msg": msg,
|
469 |
+
"reason": reason,
|
470 |
+
"likelihood": likelihood,
|
471 |
+
"confidence": confidence,
|
472 |
+
"familiarity": familiarity,
|
473 |
+
"evaluation_send_button": evaluation_send_button,
|
474 |
+
"general_instruction": general_instruction,
|
475 |
+
"round_instruction": round_instruction,
|
476 |
+
"textbox": textbox,
|
477 |
+
}
|
478 |
+
|
479 |
+
def tab_creation_preference_stage():
|
480 |
+
with gr.Row():
|
481 |
+
gr.HTML(value=PREFERENCE_ELICITATION_TASK, label="Preference Elicitation Task")
|
482 |
+
with gr.Row():
|
483 |
+
with gr.Column():
|
484 |
+
user_narrative = gr.HTML(label="User Narrative")
|
485 |
+
with gr.Column():
|
486 |
+
with gr.Row():
|
487 |
+
elicitation_chatbot = gr.Chatbot(height=600)
|
488 |
+
with gr.Row():
|
489 |
+
start_conversation = gr.Button(value="Start Conversation")
|
490 |
+
with gr.Row():
|
491 |
+
msg = gr.Textbox(scale=1, label="User Input")
|
492 |
+
with gr.Row():
|
493 |
+
msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
|
494 |
+
continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
|
495 |
+
|
496 |
+
return {
|
497 |
+
"start_conversation": start_conversation,
|
498 |
+
"msg_button": msg_button,
|
499 |
+
"continue_button": continue_button,
|
500 |
+
"msg": msg,
|
501 |
+
"elicitation_chatbot": elicitation_chatbot,
|
502 |
+
"user_narrative": user_narrative,
|
503 |
+
}
|
504 |
+
|
505 |
+
def tab_final_evaluation():
|
506 |
+
with gr.Row():
|
507 |
+
gr.HTML(value=FINAL_EVALUATION)
|
508 |
+
with gr.Row():
|
509 |
+
gr.HTML(value="<h3>Rank the individual stocks below according to your desire to invest in each one.</h3>")
|
510 |
+
with gr.Row():
|
511 |
+
ranking_first_comp = gr.Dropdown(choices=[1, 2, 3, 4])
|
512 |
+
ranking_second_comp = gr.Dropdown(choices=[1, 2, 3, 4])
|
513 |
+
ranking_third_comp = gr.Dropdown(choices=[1, 2, 3, 4])
|
514 |
+
ranking_fourth_comp = gr.Dropdown(choices=[1, 2, 3, 4])
|
515 |
+
with gr.Row():
|
516 |
+
gr.HTML(
|
517 |
+
value='<h3>Choose how strongly you agree with each statement about the advisor (<strong style="color:red;">1 for Strongly Disagree</strong>, <strong style="color:green;">7 for Strongly Agree</strong>).</h3>'
|
518 |
+
)
|
519 |
+
with gr.Row():
|
520 |
+
perceived_personalization = likert_evaluation("The advisor understands my needs")
|
521 |
+
emotional_trust = likert_evaluation("I feel content about relying on this advisor for my decisions")
|
522 |
+
with gr.Row():
|
523 |
+
trust_in_competence = likert_evaluation("The advisor has good knowledge of the stock")
|
524 |
+
intention_to_use = likert_evaluation(
|
525 |
+
"I am willing to use this advisor as an aid to help with my decision about which stock to purchase"
|
526 |
+
)
|
527 |
+
|
528 |
+
with gr.Row():
|
529 |
+
usefulness = likert_evaluation("The advisor gave me good suggestions")
|
530 |
+
overall_satisfaction = likert_evaluation("Overall, I am satisfied with the advisor")
|
531 |
+
with gr.Row():
|
532 |
+
providing_information = likert_evaluation("The advisor provides the financial knowledge needed")
|
533 |
+
with gr.Row():
|
534 |
+
textbox = gr.HTML()
|
535 |
+
submit_ranking = gr.Button(value="Submit Final Evaluation")
|
536 |
+
return {
|
537 |
+
"first": ranking_first_comp,
|
538 |
+
"second": ranking_second_comp,
|
539 |
+
"third": ranking_third_comp,
|
540 |
+
"fourth": ranking_fourth_comp,
|
541 |
+
"evaluators": {
|
542 |
+
"perceived_personalization": perceived_personalization,
|
543 |
+
"emotional_trust": emotional_trust,
|
544 |
+
"trust_in_competence": trust_in_competence,
|
545 |
+
"intention_to_use": intention_to_use,
|
546 |
+
"usefulness": usefulness,
|
547 |
+
"overall_satisfaction": overall_satisfaction,
|
548 |
+
"providing_information": providing_information,
|
549 |
+
},
|
550 |
+
"submit_ranking": submit_ranking,
|
551 |
+
"text_box": textbox,
|
552 |
+
}
|
553 |
+
|
554 |
+
def click_control_exploration_stage(
|
555 |
+
tabs, user_id, tab_session, user_preference_elicitation_session, system_description_without_context
|
556 |
+
):
|
557 |
+
(
|
558 |
+
comp,
|
559 |
+
system_instruction_context,
|
560 |
+
start_conversation,
|
561 |
+
msg_button,
|
562 |
+
continue_button,
|
563 |
+
chatbot,
|
564 |
+
msg,
|
565 |
+
reason,
|
566 |
+
likelihood,
|
567 |
+
confidence,
|
568 |
+
familiarity,
|
569 |
+
evaluation_send_button,
|
570 |
+
textbox,
|
571 |
+
) = (
|
572 |
+
tabs["comp"],
|
573 |
+
tabs["system_instruction_context"],
|
574 |
+
tabs["start_conversation"],
|
575 |
+
tabs["msg_button"],
|
576 |
+
tabs["continue_button"],
|
577 |
+
tabs["chatbot"],
|
578 |
+
tabs["msg"],
|
579 |
+
tabs["reason"],
|
580 |
+
tabs["likelihood"],
|
581 |
+
tabs["confidence"],
|
582 |
+
tabs["familiarity"],
|
583 |
+
tabs["evaluation_send_button"],
|
584 |
+
tabs["textbox"],
|
585 |
+
)
|
586 |
+
system_instruction = ""
|
587 |
+
start_conversation.click(
|
588 |
+
lambda user_id, tab_session, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond_start_conversation(
|
589 |
+
user_id,
|
590 |
+
tab_session,
|
591 |
+
history,
|
592 |
+
system_instruction,
|
593 |
+
comp,
|
594 |
+
user_preference_elicitation_data=user_preference_elicitation_session,
|
595 |
+
system_description_without_context=system_description_without_context,
|
596 |
+
system_instruction_context=system_instruction_context,
|
597 |
+
),
|
598 |
+
[
|
599 |
+
user_id,
|
600 |
+
tab_session,
|
601 |
+
chatbot,
|
602 |
+
comp,
|
603 |
+
user_preference_elicitation_session,
|
604 |
+
system_description_without_context,
|
605 |
+
system_instruction_context,
|
606 |
+
],
|
607 |
+
[tab_session, chatbot, start_conversation, msg_button, continue_button],
|
608 |
+
)
|
609 |
+
msg_button.click(
|
610 |
+
lambda user_id, tab_session, message, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond(
|
611 |
+
user_id,
|
612 |
+
tab_session,
|
613 |
+
message,
|
614 |
+
tab_session["history"],
|
615 |
+
system_instruction,
|
616 |
+
comp,
|
617 |
+
user_preference_elicitation_data=user_preference_elicitation_session,
|
618 |
+
system_description_without_context=system_description_without_context,
|
619 |
+
system_instruction_context=system_instruction_context,
|
620 |
+
),
|
621 |
+
[
|
622 |
+
user_id,
|
623 |
+
tab_session,
|
624 |
+
msg,
|
625 |
+
chatbot,
|
626 |
+
comp,
|
627 |
+
user_preference_elicitation_session,
|
628 |
+
system_description_without_context,
|
629 |
+
system_instruction_context,
|
630 |
+
],
|
631 |
+
[tab_session, msg, chatbot],
|
632 |
+
)
|
633 |
+
continue_button.click(
|
634 |
+
lambda user_id, tab_session, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond_continue(
|
635 |
+
user_id,
|
636 |
+
tab_session,
|
637 |
+
tab_session["history"],
|
638 |
+
system_instruction,
|
639 |
+
comp,
|
640 |
+
user_preference_elicitation_data=user_preference_elicitation_session,
|
641 |
+
system_description_without_context=system_description_without_context,
|
642 |
+
system_instruction_context=system_instruction_context,
|
643 |
+
),
|
644 |
+
[
|
645 |
+
user_id,
|
646 |
+
tab_session,
|
647 |
+
chatbot,
|
648 |
+
comp,
|
649 |
+
user_preference_elicitation_session,
|
650 |
+
system_description_without_context,
|
651 |
+
system_instruction_context,
|
652 |
+
],
|
653 |
+
[tab_session, chatbot],
|
654 |
+
)
|
655 |
+
evaluation_send_button.click(
|
656 |
+
lambda user_id, comp, tab_session, reason, likelihood, confidence, familiarity, evaluation_send_button, textbox: respond_evaluation(
|
657 |
+
user_id,
|
658 |
+
tab_session,
|
659 |
+
{
|
660 |
+
"reason": reason,
|
661 |
+
"likelihood": likelihood,
|
662 |
+
"confidence": confidence,
|
663 |
+
"familiarity": familiarity,
|
664 |
+
},
|
665 |
+
comp,
|
666 |
+
evaluation_send_button,
|
667 |
+
textbox,
|
668 |
+
),
|
669 |
+
[
|
670 |
+
user_id,
|
671 |
+
comp,
|
672 |
+
tab_session,
|
673 |
+
reason,
|
674 |
+
likelihood,
|
675 |
+
confidence,
|
676 |
+
familiarity,
|
677 |
+
evaluation_send_button,
|
678 |
+
textbox,
|
679 |
+
],
|
680 |
+
[tab_session, reason, likelihood, confidence, familiarity, evaluation_send_button, textbox],
|
681 |
+
)
|
682 |
+
|
683 |
+
def click_control_preference_stage(
|
684 |
+
tabs, user_id, user_preference_elicitation_session, system_description_user_elicitation
|
685 |
+
):
|
686 |
+
(
|
687 |
+
start_conversation,
|
688 |
+
msg_button,
|
689 |
+
continue_button,
|
690 |
+
elicitation_chatbot,
|
691 |
+
msg,
|
692 |
+
) = (
|
693 |
+
tabs["start_conversation"],
|
694 |
+
tabs["msg_button"],
|
695 |
+
tabs["continue_button"],
|
696 |
+
tabs["elicitation_chatbot"],
|
697 |
+
tabs["msg"],
|
698 |
+
)
|
699 |
+
# nonlocal user_id
|
700 |
+
start_conversation.click(
|
701 |
+
lambda user_id, user_preference_elicitation_data, history, system_description_user_elicitation: respond_start_conversation(
|
702 |
+
user_id,
|
703 |
+
user_preference_elicitation_data,
|
704 |
+
history,
|
705 |
+
system_description_user_elicitation,
|
706 |
+
user_elicitation=True,
|
707 |
+
),
|
708 |
+
[user_id, user_preference_elicitation_session, elicitation_chatbot, system_description_user_elicitation],
|
709 |
+
[user_preference_elicitation_session, elicitation_chatbot, start_conversation, msg_button, continue_button],
|
710 |
+
)
|
711 |
+
msg_button.click(
|
712 |
+
lambda user_id, tab_data, message, history, system_description_user_elicitation: respond(
|
713 |
+
user_id,
|
714 |
+
tab_data,
|
715 |
+
message,
|
716 |
+
tab_data["history"],
|
717 |
+
system_description_user_elicitation,
|
718 |
+
user_elicitation=True,
|
719 |
+
),
|
720 |
+
[
|
721 |
+
user_id,
|
722 |
+
user_preference_elicitation_session,
|
723 |
+
msg,
|
724 |
+
elicitation_chatbot,
|
725 |
+
system_description_user_elicitation,
|
726 |
+
],
|
727 |
+
[user_preference_elicitation_session, msg, elicitation_chatbot],
|
728 |
+
)
|
729 |
+
continue_button.click(
|
730 |
+
lambda user_id, tab_data, history, system_description_user_elicitation: respond_continue(
|
731 |
+
user_id,
|
732 |
+
tab_data,
|
733 |
+
tab_data["history"],
|
734 |
+
system_description_user_elicitation,
|
735 |
+
user_elicitation=True,
|
736 |
+
),
|
737 |
+
[user_id, user_preference_elicitation_session, elicitation_chatbot, system_description_user_elicitation],
|
738 |
+
[user_preference_elicitation_session, elicitation_chatbot],
|
739 |
+
)
|
740 |
+
|
741 |
+
def click_control_final_evaluation(tabs, user_id, first_comp, second_comp, third_comp, fourth_comp, evaluators):
|
742 |
+
(
|
743 |
+
ranking_first_comp,
|
744 |
+
ranking_second_comp,
|
745 |
+
ranking_third_comp,
|
746 |
+
ranking_fourth_comp,
|
747 |
+
) = (
|
748 |
+
tabs["first"],
|
749 |
+
tabs["second"],
|
750 |
+
tabs["third"],
|
751 |
+
tabs["fourth"],
|
752 |
+
)
|
753 |
+
(
|
754 |
+
perceived_personalization,
|
755 |
+
emotional_trust,
|
756 |
+
trust_in_competence,
|
757 |
+
intention_to_use,
|
758 |
+
usefulness,
|
759 |
+
overall_satisfaction,
|
760 |
+
providing_information,
|
761 |
+
) = (
|
762 |
+
evaluators["perceived_personalization"],
|
763 |
+
evaluators["emotional_trust"],
|
764 |
+
evaluators["trust_in_competence"],
|
765 |
+
evaluators["intention_to_use"],
|
766 |
+
evaluators["usefulness"],
|
767 |
+
evaluators["overall_satisfaction"],
|
768 |
+
evaluators["providing_information"],
|
769 |
+
)
|
770 |
+
result_textbox = tabs["text_box"]
|
771 |
+
submit_ranking = tabs["submit_ranking"]
|
772 |
+
submit_ranking.click(
|
773 |
+
lambda user_id, first_comp, ranking_first_comp, second_comp, ranking_second_comp, third_comp, ranking_third_comp, fourth_comp, ranking_fourth_comp, perceived_personalization, emotional_trust, trust_in_competence, intention_to_use, usefulness, overall_satisfaction, providing_information, submit_ranking: respond_final_ranking(
|
774 |
+
user_id,
|
775 |
+
first_comp,
|
776 |
+
ranking_first_comp,
|
777 |
+
second_comp,
|
778 |
+
ranking_second_comp,
|
779 |
+
third_comp,
|
780 |
+
ranking_third_comp,
|
781 |
+
fourth_comp,
|
782 |
+
ranking_fourth_comp,
|
783 |
+
perceived_personalization,
|
784 |
+
emotional_trust,
|
785 |
+
trust_in_competence,
|
786 |
+
intention_to_use,
|
787 |
+
usefulness,
|
788 |
+
overall_satisfaction,
|
789 |
+
providing_information,
|
790 |
+
submit_ranking,
|
791 |
+
),
|
792 |
+
# Input components (names and rankings)
|
793 |
+
[
|
794 |
+
user_id,
|
795 |
+
first_comp,
|
796 |
+
ranking_first_comp,
|
797 |
+
second_comp,
|
798 |
+
ranking_second_comp,
|
799 |
+
third_comp,
|
800 |
+
ranking_third_comp,
|
801 |
+
fourth_comp,
|
802 |
+
ranking_fourth_comp,
|
803 |
+
perceived_personalization,
|
804 |
+
emotional_trust,
|
805 |
+
trust_in_competence,
|
806 |
+
intention_to_use,
|
807 |
+
usefulness,
|
808 |
+
overall_satisfaction,
|
809 |
+
providing_information,
|
810 |
+
submit_ranking,
|
811 |
+
],
|
812 |
+
# Output component(s) where you want the result to appear, e.g., result_textbox
|
813 |
+
[result_textbox, submit_ranking],
|
814 |
+
)
|
815 |
+
|
816 |
+
def respond(
|
817 |
+
user_id,
|
818 |
+
tab_data,
|
819 |
+
message,
|
820 |
+
history,
|
821 |
+
system_instruction,
|
822 |
+
tab_name=None,
|
823 |
+
user_elicitation=False,
|
824 |
+
user_preference_elicitation_data=None,
|
825 |
+
system_description_without_context=None,
|
826 |
+
system_instruction_context=None,
|
827 |
+
):
|
828 |
+
"""
|
829 |
+
Return:
|
830 |
+
msg
|
831 |
+
chat_history
|
832 |
+
retrieved_passage
|
833 |
+
rewritten_query
|
834 |
+
|
835 |
+
"""
|
836 |
+
assert (
|
837 |
+
tab_name is not None or user_elicitation is True
|
838 |
+
), "Tab name is required for the start of the conversation unless it is not preference elicitation."
|
839 |
+
# Add user profile to system instruction
|
840 |
+
if system_description_without_context is not None and system_instruction_context is not None:
|
841 |
+
system_instruction = system_description_without_context + "\n" + system_instruction_context
|
842 |
+
if not user_elicitation:
|
843 |
+
system_instruction = add_user_profile_to_system_instruction(
|
844 |
+
user_id,
|
845 |
+
system_instruction,
|
846 |
+
user_preference_elicitation_data,
|
847 |
+
summary=USER_PREFERENCE_SUMMARY,
|
848 |
+
terminator=terminator,
|
849 |
+
)
|
850 |
+
# From string to list [{"role":"user", "content": message}, ...]
|
851 |
+
history = gradio_to_huggingface_message(history)
|
852 |
+
# We can implement context window here as we need all the system interaction. We can cut some of the early interactions if needed.
|
853 |
+
history = conversation_window(history, CONV_WINDOW)
|
854 |
+
# Add system instruction to the history
|
855 |
+
history = format_context(system_instruction, history)
|
856 |
+
# Add user message to the history
|
857 |
+
history_with_user_utterance = format_user_message(message, history)
|
858 |
+
# Call API instead of locally handle it
|
859 |
+
if API_TYPE == "local":
|
860 |
+
outputs_text, history = generate_response_local_api(history_with_user_utterance, terminator, 128, API_URL)
|
861 |
+
elif API_TYPE == "together":
|
862 |
+
outputs_text, history = generate_response_together_api(history_with_user_utterance, 128, TOGETHER_CLIENT)
|
863 |
+
else:
|
864 |
+
outputs_text, history = generate_response_debugging(history_with_user_utterance)
|
865 |
+
# exclude system interaction and store the others in the history
|
866 |
+
history = huggingface_to_gradio_message(history)
|
867 |
+
if tab_name is not None:
|
868 |
+
# Log the user message and response
|
869 |
+
save_feedback(
|
870 |
+
user_id,
|
871 |
+
uuid_this_session,
|
872 |
+
"interaction",
|
873 |
+
{"type": tab_name, "role": "user", "content": message},
|
874 |
+
feedback_file_interaction,
|
875 |
+
)
|
876 |
+
save_feedback(
|
877 |
+
user_id,
|
878 |
+
uuid_this_session,
|
879 |
+
"interaction",
|
880 |
+
{"type": tab_name, "role": "assistant", "content": outputs_text},
|
881 |
+
feedback_file_interaction,
|
882 |
+
)
|
883 |
+
# log_action(user_id, tab_name, "User Message", message)
|
884 |
+
# log_action(user_id, tab_name, "Response", outputs_text)
|
885 |
+
# Store the updated history for this tab
|
886 |
+
tab_data["history"] = history
|
887 |
+
if user_elicitation:
|
888 |
+
save_feedback(
|
889 |
+
user_id,
|
890 |
+
uuid_this_session,
|
891 |
+
"Interaction",
|
892 |
+
{"type": "user_elicitation", "role": "user", "content": message},
|
893 |
+
feedback_file_interaction,
|
894 |
+
)
|
895 |
+
save_feedback(
|
896 |
+
user_id,
|
897 |
+
uuid_this_session,
|
898 |
+
"Interaction",
|
899 |
+
{"type": "user_elicitation", "role": "assistant", "content": outputs_text},
|
900 |
+
feedback_file_interaction,
|
901 |
+
)
|
902 |
+
# log_action(user_id, "User_Elicitation", "User Message", message)
|
903 |
+
# log_action(user_id, "User_Elicitation", "Response", outputs_text)
|
904 |
+
tab_data["history"] = history
|
905 |
+
|
906 |
+
return tab_data, "", history
|
907 |
+
|
908 |
+
def respond_start_conversation(
|
909 |
+
user_id,
|
910 |
+
tab_data,
|
911 |
+
history,
|
912 |
+
system_instruction,
|
913 |
+
tab_name=None,
|
914 |
+
user_elicitation=False,
|
915 |
+
user_preference_elicitation_data=None,
|
916 |
+
system_description_without_context=None,
|
917 |
+
system_instruction_context=None,
|
918 |
+
):
|
919 |
+
assert (
|
920 |
+
tab_name is not None or user_elicitation is True
|
921 |
+
), "Tab name is required for the start of the conversation unless it is not preference elicitation."
|
922 |
+
if system_description_without_context is not None and system_instruction_context is not None:
|
923 |
+
system_instruction = system_description_without_context + "\n" + system_instruction_context
|
924 |
+
if not user_elicitation:
|
925 |
+
system_instruction = add_user_profile_to_system_instruction(
|
926 |
+
user_id,
|
927 |
+
system_instruction,
|
928 |
+
user_preference_elicitation_data,
|
929 |
+
summary=USER_PREFERENCE_SUMMARY,
|
930 |
+
terminator=terminator,
|
931 |
+
)
|
932 |
+
history = gradio_to_huggingface_message(history)
|
933 |
+
history = format_context(system_instruction, history)
|
934 |
+
first_message = FIRST_MESSAGE
|
935 |
+
history_with_user_utterance = format_user_message(first_message, history)
|
936 |
+
max_length = 128 if user_elicitation else 256
|
937 |
+
if API_TYPE == "local":
|
938 |
+
outputs_text, history = generate_response_local_api(
|
939 |
+
history_with_user_utterance, terminator, max_length, API_URL
|
940 |
+
)
|
941 |
+
elif API_TYPE == "together":
|
942 |
+
outputs_text, history = generate_response_together_api(
|
943 |
+
history_with_user_utterance, max_length, TOGETHER_CLIENT
|
944 |
+
)
|
945 |
+
else:
|
946 |
+
outputs_text, history = generate_response_debugging(history_with_user_utterance)
|
947 |
+
# Format
|
948 |
+
history = huggingface_to_gradio_message(history)
|
949 |
+
if tab_name is not None:
|
950 |
+
# Log the user message and response
|
951 |
+
save_feedback(
|
952 |
+
user_id,
|
953 |
+
uuid_this_session,
|
954 |
+
"interaction",
|
955 |
+
{"type": tab_name, "role": "user", "content": first_message},
|
956 |
+
feedback_file_interaction,
|
957 |
+
)
|
958 |
+
save_feedback(
|
959 |
+
user_id,
|
960 |
+
uuid_this_session,
|
961 |
+
"interaction",
|
962 |
+
{"type": tab_name, "role": "assistant", "content": outputs_text},
|
963 |
+
feedback_file_interaction,
|
964 |
+
)
|
965 |
+
# log_action(user_id, tab_name, "User Message", first_message)
|
966 |
+
# log_action(user_id, tab_name, "Response", outputs_text)
|
967 |
+
# Store the updated history for this tab
|
968 |
+
tab_data["history"] = history
|
969 |
+
if user_elicitation:
|
970 |
+
save_feedback(
|
971 |
+
user_id,
|
972 |
+
uuid_this_session,
|
973 |
+
"interaction",
|
974 |
+
{"type": "user_elicitation", "role": "user", "content": first_message},
|
975 |
+
feedback_file_interaction,
|
976 |
+
)
|
977 |
+
save_feedback(
|
978 |
+
user_id,
|
979 |
+
uuid_this_session,
|
980 |
+
"Interaction",
|
981 |
+
{"type": "user_elicitation", "role": "assistant", "content": outputs_text},
|
982 |
+
feedback_file_interaction,
|
983 |
+
)
|
984 |
+
tab_data["history"] = history
|
985 |
+
return (
|
986 |
+
tab_data,
|
987 |
+
history,
|
988 |
+
gr.Button(value="Start Conversation", interactive=False),
|
989 |
+
gr.Button(value="Send This Message to Advisor", interactive=True),
|
990 |
+
gr.Button(value="Show More of the Advisor’s Answer", interactive=True),
|
991 |
+
)
|
992 |
+
|
993 |
+
def respond_continue(
|
994 |
+
user_id,
|
995 |
+
tab_data,
|
996 |
+
history,
|
997 |
+
system_instruction,
|
998 |
+
tab_name=None,
|
999 |
+
user_elicitation=False,
|
1000 |
+
user_preference_elicitation_data=None,
|
1001 |
+
system_description_without_context=None,
|
1002 |
+
system_instruction_context=None,
|
1003 |
+
):
|
1004 |
+
assert (
|
1005 |
+
tab_name is not None or user_elicitation is True
|
1006 |
+
), "Tab name is required for the start of the conversation."
|
1007 |
+
# Add user profile to system instruction
|
1008 |
+
if system_description_without_context is not None and system_instruction_context is not None:
|
1009 |
+
system_instruction = system_description_without_context + "\n" + system_instruction_context
|
1010 |
+
if not user_elicitation:
|
1011 |
+
system_instruction = add_user_profile_to_system_instruction(
|
1012 |
+
user_id,
|
1013 |
+
system_instruction,
|
1014 |
+
user_preference_elicitation_data,
|
1015 |
+
summary=USER_PREFERENCE_SUMMARY,
|
1016 |
+
terminator=terminator,
|
1017 |
+
)
|
1018 |
+
message = "continue"
|
1019 |
+
history = gradio_to_huggingface_message(history)
|
1020 |
+
history = conversation_window(history, CONV_WINDOW)
|
1021 |
+
history = format_context(system_instruction, history)
|
1022 |
+
history_with_user_utterance = format_user_message(message, history)
|
1023 |
+
if API_TYPE == "local":
|
1024 |
+
outputs_text, history = generate_response_local_api(history_with_user_utterance, terminator, 128, API_URL)
|
1025 |
+
elif API_TYPE == "together":
|
1026 |
+
outputs_text, history = generate_response_together_api(history_with_user_utterance, 128, TOGETHER_CLIENT)
|
1027 |
+
else:
|
1028 |
+
outputs_text, history = generate_response_debugging(history_with_user_utterance)
|
1029 |
+
history = huggingface_to_gradio_message(history)
|
1030 |
+
if tab_name is not None:
|
1031 |
+
save_feedback(
|
1032 |
+
user_id,
|
1033 |
+
uuid_this_session,
|
1034 |
+
"interaction",
|
1035 |
+
{
|
1036 |
+
"type": tab_name,
|
1037 |
+
"role": "user",
|
1038 |
+
"content": message,
|
1039 |
+
},
|
1040 |
+
feedback_file_interaction,
|
1041 |
+
)
|
1042 |
+
save_feedback(
|
1043 |
+
user_id,
|
1044 |
+
uuid_this_session,
|
1045 |
+
"interaction",
|
1046 |
+
{"type": tab_name, "role": "assistant", "content": outputs_text},
|
1047 |
+
feedback_file_interaction,
|
1048 |
+
)
|
1049 |
+
|
1050 |
+
# Update history for this tab
|
1051 |
+
tab_data["history"] = history
|
1052 |
+
if user_elicitation:
|
1053 |
+
save_feedback(
|
1054 |
+
user_id,
|
1055 |
+
uuid_this_session,
|
1056 |
+
"interaction",
|
1057 |
+
{"type": "user_elicitation", "role": "user", "content": message},
|
1058 |
+
feedback_file_interaction,
|
1059 |
+
)
|
1060 |
+
save_feedback(
|
1061 |
+
user_id,
|
1062 |
+
uuid_this_session,
|
1063 |
+
"interaction",
|
1064 |
+
{"type": "user_elicitation", "role": "assistant", "content": outputs_text},
|
1065 |
+
feedback_file_interaction,
|
1066 |
+
)
|
1067 |
+
tab_data["history"] = history
|
1068 |
+
return tab_data, history
|
1069 |
+
|
1070 |
+
def respond_evaluation(user_id, tab_data, evals, tab_name, evaluation_send_button, textbox):
|
1071 |
+
|
1072 |
+
# dropdown, readon_button, multi-evaluator
|
1073 |
+
if evals["likelihood"] is None or evals["confidence"] is None or evals["familiarity"] is None:
|
1074 |
+
return (
|
1075 |
+
tab_data,
|
1076 |
+
evals["reason"],
|
1077 |
+
evals["likelihood"],
|
1078 |
+
evals["confidence"],
|
1079 |
+
evals["familiarity"],
|
1080 |
+
evaluation_send_button,
|
1081 |
+
"""<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
|
1082 |
+
<strong>Please make sure that you answer all the questions.</strong>
|
1083 |
+
</div>""",
|
1084 |
+
)
|
1085 |
+
else:
|
1086 |
+
save_feedback(
|
1087 |
+
user_id,
|
1088 |
+
uuid_this_session,
|
1089 |
+
"round_evaluation",
|
1090 |
+
{**evals, "company": tab_name},
|
1091 |
+
feedback_file_round_evaluation,
|
1092 |
+
)
|
1093 |
+
# log_action(user_id, tab_name, "Round Evaluation", "Following")
|
1094 |
+
# for key, value in evals.items():
|
1095 |
+
# log_action(user_id, tab_name, key, value)
|
1096 |
+
# Store the reason for this tab
|
1097 |
+
tab_data["multi_evaluator"] = evals
|
1098 |
+
evaluation_send_button = gr.Button(value="Evaluation receirved", interactive=False)
|
1099 |
+
return (
|
1100 |
+
tab_data,
|
1101 |
+
evals["reason"],
|
1102 |
+
evals["likelihood"],
|
1103 |
+
evals["confidence"],
|
1104 |
+
evals["familiarity"],
|
1105 |
+
evaluation_send_button,
|
1106 |
+
"""<div style="background-color: #d4edda; color: #155724; padding: 15px; border: 1px solid #c3e6cb; border-radius: 5px; margin-bottom: 20px;">
|
1107 |
+
<strong>Thank you for submitting your evaluation. You may proceed to the next tab.</strong>
|
1108 |
+
</div>""",
|
1109 |
+
)
|
1110 |
+
|
1111 |
+
def respond_final_ranking(
|
1112 |
+
user_id,
|
1113 |
+
first_comp,
|
1114 |
+
ranking_first_comp,
|
1115 |
+
second_comp,
|
1116 |
+
ranking_second_comp,
|
1117 |
+
third_comp,
|
1118 |
+
ranking_third_comp,
|
1119 |
+
fourth_comp,
|
1120 |
+
ranking_fourth_comp,
|
1121 |
+
perceived_personalization,
|
1122 |
+
emotional_trust,
|
1123 |
+
trust_in_competence,
|
1124 |
+
intention_to_use,
|
1125 |
+
usefulness,
|
1126 |
+
overall_satisfaction,
|
1127 |
+
providing_information,
|
1128 |
+
submit_ranking,
|
1129 |
+
):
|
1130 |
+
# make sure that they are not the same
|
1131 |
+
ranking_list = [
|
1132 |
+
ranking_first_comp,
|
1133 |
+
ranking_second_comp,
|
1134 |
+
ranking_third_comp,
|
1135 |
+
ranking_fourth_comp,
|
1136 |
+
]
|
1137 |
+
if len(set(ranking_list)) != len(ranking_list):
|
1138 |
+
return (
|
1139 |
+
"""<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
|
1140 |
+
<strong>Please make sure that you are not ranking the same stock multiple times.</strong>
|
1141 |
+
</div>""",
|
1142 |
+
submit_ranking,
|
1143 |
+
)
|
1144 |
+
if any(
|
1145 |
+
var is None
|
1146 |
+
for var in [
|
1147 |
+
perceived_personalization,
|
1148 |
+
emotional_trust,
|
1149 |
+
trust_in_competence,
|
1150 |
+
intention_to_use,
|
1151 |
+
usefulness,
|
1152 |
+
overall_satisfaction,
|
1153 |
+
providing_information,
|
1154 |
+
]
|
1155 |
+
):
|
1156 |
+
return (
|
1157 |
+
"""<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
|
1158 |
+
<strong>Please make sure that you answer all the statements.</strong>
|
1159 |
+
</div>""",
|
1160 |
+
submit_ranking,
|
1161 |
+
)
|
1162 |
+
else:
|
1163 |
+
save_feedback(
|
1164 |
+
user_id,
|
1165 |
+
uuid_this_session,
|
1166 |
+
"final_ranking",
|
1167 |
+
{
|
1168 |
+
"comp_order": [first_comp, second_comp, third_comp, fourth_comp],
|
1169 |
+
"ranking": ranking_list,
|
1170 |
+
},
|
1171 |
+
feedback_file_final_ranking,
|
1172 |
+
)
|
1173 |
+
|
1174 |
+
save_feedback(
|
1175 |
+
user_id,
|
1176 |
+
uuid_this_session,
|
1177 |
+
"final_ranking_survey",
|
1178 |
+
{
|
1179 |
+
"perceived_personalization": perceived_personalization,
|
1180 |
+
"emotional_trust": emotional_trust,
|
1181 |
+
"trust_in_competence": trust_in_competence,
|
1182 |
+
"intention_to_use": intention_to_use,
|
1183 |
+
"usefulness": usefulness,
|
1184 |
+
"overall_satisfaction": overall_satisfaction,
|
1185 |
+
"providing_information": providing_information,
|
1186 |
+
},
|
1187 |
+
feedback_file_final_survey,
|
1188 |
+
)
|
1189 |
+
submit_ranking = gr.Button(value="Final evaluaiotn received", interactive=False)
|
1190 |
+
return (
|
1191 |
+
"""<div style="background-color: #d4edda; color: #155724; padding: 15px; border: 1px solid #c3e6cb; border-radius: 5px; margin-bottom: 20px;">
|
1192 |
+
<strong>Thank you for participating in the experiment. This concludes the session. You may now close the tab.</strong>
|
1193 |
+
</div>""",
|
1194 |
+
submit_ranking,
|
1195 |
+
)
|
1196 |
+
|
1197 |
+
def get_context(index, raw_context_list, stock_context_list):
|
1198 |
+
comp = raw_context_list[index]["short_name"]
|
1199 |
+
context = stock_context_list[index]
|
1200 |
+
general_instruction, round_instruction = get_task_instruction_for_user(raw_context_list[index])
|
1201 |
+
return comp, context, general_instruction, round_instruction
|
1202 |
+
|
1203 |
+
def set_user_id(request: gr.Request):
|
1204 |
+
user_id = request.username
|
1205 |
+
user_in_narrative_id = user_id.split("_")[-1]
|
1206 |
+
narrative_id = user_id.split("_")[-2]
|
1207 |
+
experiment_id = user_id.split("_")[-3]
|
1208 |
+
return user_id, user_in_narrative_id, narrative_id, experiment_id
|
1209 |
+
|
1210 |
+
def get_inst_without_context(experiment_id):
|
1211 |
+
# experiment_id = 1 => personalization
|
1212 |
+
# experiment_id = 2 => no personalization
|
1213 |
+
# experiment_id == 3 => ext personality
|
1214 |
+
# experiment_id == 4 => int personality
|
1215 |
+
if experiment_id == "0":
|
1216 |
+
return SYSTEM_INSTRUCTION_PERSONALIZATION
|
1217 |
+
elif experiment_id == "1":
|
1218 |
+
return SYSTEM_INSTRUCTION_NON_PERSONALIZATION
|
1219 |
+
else:
|
1220 |
+
return SYSTEM_INSTRUCTION_PERSONALIZATION
|
1221 |
+
# elif experiment_id == "2":
|
1222 |
+
# return SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_EXT)
|
1223 |
+
# elif experiment_id == "3":
|
1224 |
+
# return SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_INT)
|
1225 |
+
|
1226 |
+
def get_user_preference_elicitation(experiment_id):
|
1227 |
+
if experiment_id == "0" or experiment_id == "1":
|
1228 |
+
return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION
|
1229 |
+
else:
|
1230 |
+
return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION
|
1231 |
+
# elif experiment_id == "2":
|
1232 |
+
# return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(personality=PERSONALITY_EXT)
|
1233 |
+
# elif experiment_id == "3":
|
1234 |
+
# return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(personality=PERSONALITY_INT)
|
1235 |
+
|
1236 |
+
def get_stock_related_context(narrative_id, user_in_narrative_id):
|
1237 |
+
raw_context_list = build_raw_context_list(context_info_list[int(narrative_id)])
|
1238 |
+
stock_context_list = build_context(context_info_list[int(narrative_id)])
|
1239 |
+
raw_context_list = reorder_list_based_on_user_in_narrative_id(user_in_narrative_id, raw_context_list)
|
1240 |
+
stock_context_list = reorder_list_based_on_user_in_narrative_id(user_in_narrative_id, stock_context_list)
|
1241 |
+
return raw_context_list, stock_context_list
|
1242 |
+
|
1243 |
+
def set_initial_values(request: gr.Request):
|
1244 |
+
# Set user specific information (Session State)
|
1245 |
+
# user_id, user_in_narrative_id, narrative_id, experiment_id = set_user_id(request)
|
1246 |
+
user_id = "ecir_demo_0_0_2"
|
1247 |
+
user_in_narrative_id = "0"
|
1248 |
+
narrative_id = "0"
|
1249 |
+
experiment_id = "2"
|
1250 |
+
# System instruction without prompt
|
1251 |
+
system_description_without_context = get_inst_without_context(experiment_id)
|
1252 |
+
# user_preference_elicitation
|
1253 |
+
system_description_user_elicitation = get_user_preference_elicitation(experiment_id)
|
1254 |
+
# Stock related context
|
1255 |
+
raw_context_list, stock_context_list = get_stock_related_context(narrative_id, user_in_narrative_id)
|
1256 |
+
# User Narrative
|
1257 |
+
user_narrative = get_user_narrative_from_raw(raw_context_list[0]["user_narrative"])
|
1258 |
+
# Tab Context
|
1259 |
+
first_comp, first_context, first_general_instruction, first_round_instruction = get_context(
|
1260 |
+
0, raw_context_list, stock_context_list
|
1261 |
+
)
|
1262 |
+
second_comp, second_context, second_general_instruction, second_round_instruction = get_context(
|
1263 |
+
1, raw_context_list, stock_context_list
|
1264 |
+
)
|
1265 |
+
third_comp, third_context, third_general_instruction, third_round_instruction = get_context(
|
1266 |
+
2, raw_context_list, stock_context_list
|
1267 |
+
)
|
1268 |
+
fourth_comp, fourth_context, fourth_general_instruction, fourth_round_instruction = get_context(
|
1269 |
+
3, raw_context_list, stock_context_list
|
1270 |
+
)
|
1271 |
+
# Final Evaluation
|
1272 |
+
ranking_first_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=first_comp)
|
1273 |
+
ranking_second_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=second_comp)
|
1274 |
+
ranking_third_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=third_comp)
|
1275 |
+
ranking_fourth_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=fourth_comp)
|
1276 |
+
|
1277 |
+
return (
|
1278 |
+
user_id,
|
1279 |
+
user_in_narrative_id,
|
1280 |
+
narrative_id,
|
1281 |
+
experiment_id,
|
1282 |
+
system_description_without_context,
|
1283 |
+
system_description_user_elicitation,
|
1284 |
+
raw_context_list,
|
1285 |
+
stock_context_list,
|
1286 |
+
user_narrative,
|
1287 |
+
first_comp,
|
1288 |
+
first_context,
|
1289 |
+
first_general_instruction,
|
1290 |
+
first_round_instruction,
|
1291 |
+
second_comp,
|
1292 |
+
second_context,
|
1293 |
+
second_general_instruction,
|
1294 |
+
second_round_instruction,
|
1295 |
+
third_comp,
|
1296 |
+
third_context,
|
1297 |
+
third_general_instruction,
|
1298 |
+
third_round_instruction,
|
1299 |
+
fourth_comp,
|
1300 |
+
fourth_context,
|
1301 |
+
fourth_general_instruction,
|
1302 |
+
fourth_round_instruction,
|
1303 |
+
# ranking_first_comp,
|
1304 |
+
# ranking_second_comp,
|
1305 |
+
# ranking_third_comp,
|
1306 |
+
# ranking_fourth_comp,
|
1307 |
+
)
|
1308 |
+
|
1309 |
+
with gr.Blocks(title="RAG Chatbot Q&A", theme="Soft") as demo:
|
1310 |
+
# Set user specific information (Session State)
|
1311 |
+
user_id = gr.State()
|
1312 |
+
user_in_narrative_id = gr.State()
|
1313 |
+
narrative_id = gr.State()
|
1314 |
+
experiment_id = gr.State()
|
1315 |
+
system_description_without_context = gr.State()
|
1316 |
+
system_description_user_elicitation = gr.State()
|
1317 |
+
# Context data
|
1318 |
+
raw_context_list = gr.State()
|
1319 |
+
stock_context_list = gr.State()
|
1320 |
+
first_comp = gr.State()
|
1321 |
+
first_context = gr.State()
|
1322 |
+
second_comp = gr.State()
|
1323 |
+
second_context = gr.State()
|
1324 |
+
third_comp = gr.State()
|
1325 |
+
third_context = gr.State()
|
1326 |
+
fourth_comp = gr.State()
|
1327 |
+
fourth_context = gr.State()
|
1328 |
+
# Tab data
|
1329 |
+
if DEBUG:
|
1330 |
+
user_preference_elicitation_session = gr.State(
|
1331 |
+
value={
|
1332 |
+
"history": "",
|
1333 |
+
"summary_history": """User Profile collected in the previous conversations: Based on our previous conversation, here's a summary of your investment preferences:
|
1334 |
+
|
1335 |
+
# 1. **Preferred Industries:** You're interested in investing in the healthcare sector, without a specific preference for sub-industries such as pharmaceuticals, medical devices, biotechnology, or healthcare services.
|
1336 |
+
# 2. **Value vs. Growth Stocks:** You prefer growth stocks, which have the potential for high returns but may be riskier.
|
1337 |
+
# 3. **Dividend vs. Non-Dividend Stocks:** You're open to both dividend and non-dividend growth stocks, focusing on reinvesting profits for future growth.
|
1338 |
+
# 4. **Cyclical vs. Non-Cyclical Stocks:** You're interested in cyclical stocks, which are sensitive to economic fluctuations and tend to perform well during economic expansions.""",
|
1339 |
+
}
|
1340 |
+
)
|
1341 |
+
else:
|
1342 |
+
user_preference_elicitation_session = gr.State(value={"history": "", "summary_history": ""})
|
1343 |
+
first_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
|
1344 |
+
second_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
|
1345 |
+
third_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
|
1346 |
+
fourth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
|
1347 |
+
# # EXperiment Instruction
|
1348 |
+
# with gr.Tab("Experiment Instruction") as instruction_tab:
|
1349 |
+
# gr.HTML(value=INSTRUCTION_PAGE, label="Experiment Instruction")
|
1350 |
+
# Personality injection
|
1351 |
+
with gr.Tab("Personality Injection") as personality_button:
|
1352 |
+
personality_button, perosnality_traits = tab_creation_personality_injection(
|
1353 |
+
system_description_without_context, system_description_user_elicitation
|
1354 |
+
)
|
1355 |
+
|
1356 |
+
# click_control_personality_injection(personality_button, perosnality_traits)
|
1357 |
+
# User Preference Elicitation Tab
|
1358 |
+
with gr.Tab("Preference Elicitation Module") as preference_elicitation_tab:
|
1359 |
+
user_preference_elicitation_tab = tab_creation_preference_stage()
|
1360 |
+
user_narrative = user_preference_elicitation_tab["user_narrative"]
|
1361 |
+
click_control_preference_stage(
|
1362 |
+
user_preference_elicitation_tab,
|
1363 |
+
user_id,
|
1364 |
+
user_preference_elicitation_session,
|
1365 |
+
system_description_user_elicitation,
|
1366 |
+
)
|
1367 |
+
with gr.Tab("Personalized Stock Assessment Module") as financial_decision:
|
1368 |
+
# Experiment Tag
|
1369 |
+
first_tab = tab_creation_exploration_stage(0, first_comp, first_context)
|
1370 |
+
first_general_instruction, first_round_instruction = (
|
1371 |
+
first_tab["general_instruction"],
|
1372 |
+
first_tab["round_instruction"],
|
1373 |
+
)
|
1374 |
+
click_control_exploration_stage(
|
1375 |
+
first_tab,
|
1376 |
+
user_id,
|
1377 |
+
first_comp_session,
|
1378 |
+
user_preference_elicitation_session,
|
1379 |
+
system_description_without_context,
|
1380 |
+
)
|
1381 |
+
second_tab = tab_creation_exploration_stage(1, second_comp, second_context)
|
1382 |
+
second_general_instruction, second_round_instruction = (
|
1383 |
+
second_tab["general_instruction"],
|
1384 |
+
second_tab["round_instruction"],
|
1385 |
+
)
|
1386 |
+
click_control_exploration_stage(
|
1387 |
+
second_tab,
|
1388 |
+
user_id,
|
1389 |
+
second_comp_session,
|
1390 |
+
user_preference_elicitation_session,
|
1391 |
+
system_description_without_context,
|
1392 |
+
)
|
1393 |
+
third_tab = tab_creation_exploration_stage(2, third_comp, third_context)
|
1394 |
+
third_general_instruction, third_round_instruction = (
|
1395 |
+
third_tab["general_instruction"],
|
1396 |
+
third_tab["round_instruction"],
|
1397 |
+
)
|
1398 |
+
click_control_exploration_stage(
|
1399 |
+
third_tab,
|
1400 |
+
user_id,
|
1401 |
+
third_comp_session,
|
1402 |
+
user_preference_elicitation_session,
|
1403 |
+
system_description_without_context,
|
1404 |
+
)
|
1405 |
+
fourth_tab = tab_creation_exploration_stage(3, fourth_comp, fourth_context)
|
1406 |
+
fourth_general_instruction, fourth_round_instruction = (
|
1407 |
+
fourth_tab["general_instruction"],
|
1408 |
+
fourth_tab["round_instruction"],
|
1409 |
+
)
|
1410 |
+
click_control_exploration_stage(
|
1411 |
+
fourth_tab,
|
1412 |
+
user_id,
|
1413 |
+
fourth_comp_session,
|
1414 |
+
user_preference_elicitation_session,
|
1415 |
+
system_description_without_context,
|
1416 |
+
)
|
1417 |
+
# with gr.Tab("Final Evaluation Stage") as final_evaluation:
|
1418 |
+
# final_evaluation_tab = tab_final_evaluation()
|
1419 |
+
# (
|
1420 |
+
# ranking_first_comp,
|
1421 |
+
# ranking_second_comp,
|
1422 |
+
# ranking_third_comp,
|
1423 |
+
# ranking_fourth_comp,
|
1424 |
+
# evaluators,
|
1425 |
+
# ) = (
|
1426 |
+
# final_evaluation_tab["first"],
|
1427 |
+
# final_evaluation_tab["second"],
|
1428 |
+
# final_evaluation_tab["third"],
|
1429 |
+
# final_evaluation_tab["fourth"],
|
1430 |
+
# final_evaluation_tab["evaluators"],
|
1431 |
+
# )
|
1432 |
+
# click_control_final_evaluation(
|
1433 |
+
# final_evaluation_tab, user_id, first_comp, second_comp, third_comp, fourth_comp, evaluators
|
1434 |
+
# )
|
1435 |
+
|
1436 |
+
demo.load(
|
1437 |
+
set_initial_values,
|
1438 |
+
inputs=None,
|
1439 |
+
outputs=[
|
1440 |
+
user_id,
|
1441 |
+
user_in_narrative_id,
|
1442 |
+
narrative_id,
|
1443 |
+
experiment_id,
|
1444 |
+
system_description_without_context,
|
1445 |
+
system_description_user_elicitation,
|
1446 |
+
raw_context_list,
|
1447 |
+
stock_context_list,
|
1448 |
+
user_narrative,
|
1449 |
+
first_comp,
|
1450 |
+
first_context,
|
1451 |
+
first_general_instruction,
|
1452 |
+
first_round_instruction,
|
1453 |
+
second_comp,
|
1454 |
+
second_context,
|
1455 |
+
second_general_instruction,
|
1456 |
+
second_round_instruction,
|
1457 |
+
third_comp,
|
1458 |
+
third_context,
|
1459 |
+
third_general_instruction,
|
1460 |
+
third_round_instruction,
|
1461 |
+
fourth_comp,
|
1462 |
+
fourth_context,
|
1463 |
+
fourth_general_instruction,
|
1464 |
+
fourth_round_instruction,
|
1465 |
+
],
|
1466 |
+
)
|
1467 |
+
return demo
|
1468 |
+
|
1469 |
+
|
1470 |
+
if __name__ == "__main__":
|
1471 |
+
login(token=os.environ["HUGGINGFACE_HUB_TOKEN"])
|
1472 |
+
file_path = os.path.join(ROOT_FILE, "./data/single_stock_data/experiment_processed_data.jsonl")
|
1473 |
+
topics = [
|
1474 |
+
"healthcare_growth_defensive",
|
1475 |
+
"dividend_value_defensive",
|
1476 |
+
"nondividend_value_cyclical",
|
1477 |
+
]
|
1478 |
+
context_info_list = get_context_list(file_path) # str to List of Dict
|
1479 |
+
# system instruction consist of Task, Personality, and Context
|
1480 |
+
"""
|
1481 |
+
Personality
|
1482 |
+
["extroverted", "introverted"]
|
1483 |
+
["agreeable", "antagonistic"]
|
1484 |
+
["conscientious", "unconscientious"]
|
1485 |
+
["neurotic", "emotionally stable"]
|
1486 |
+
["open to experience", "closed to experience"]]
|
1487 |
+
"""
|
1488 |
+
# Global variables
|
1489 |
+
terminator = ["<eos>", "<unk>", "<sep>", "<pad>", "<cls>", "<mask>"]
|
1490 |
+
demo = create_demo()
|
1491 |
+
# demo.launch(auth=("ecir_demo", "ecir_demo"))
|
1492 |
+
demo.launch(auth=[("user1", "pw1"), ("user2", "pw2")])
|
1493 |
+
demo.launch()
|
components/.ipynb_checkpoints/constant-checkpoint.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Configuration Constants
|
2 |
+
import os
|
3 |
+
|
4 |
+
ACCESS = os.getenv("HF_ACCESS_TOKEN")
|
5 |
+
QUERY_REWRITING = False
|
6 |
+
RAG = False
|
7 |
+
PERSONALITY = True
|
8 |
+
PERSONALITY_LIST = ["introverted", "antagonistic", "conscientious", "emotionally stable", "open to experience"]
|
9 |
+
REWRITE_PASSAGES = False
|
10 |
+
NUM_PASSAGES = 3
|
11 |
+
DEVICE = "cuda"
|
12 |
+
RESPONSE_GENERATOR = "meta-llama/Meta-Llama-3.1-8B-Instruct"
|
components/__pycache__/chat_conversation.cpython-310.pyc
ADDED
Binary file (4.81 kB). View file
|
|
components/__pycache__/chat_conversation.cpython-38.pyc
ADDED
Binary file (4.54 kB). View file
|
|
components/__pycache__/chat_conversation.cpython-39.pyc
ADDED
Binary file (4.81 kB). View file
|
|
components/__pycache__/constant.cpython-310.pyc
ADDED
Binary file (659 Bytes). View file
|
|
components/__pycache__/constant.cpython-38.pyc
ADDED
Binary file (697 Bytes). View file
|
|
components/__pycache__/constant.cpython-39.pyc
ADDED
Binary file (672 Bytes). View file
|
|
components/__pycache__/induce_personality.cpython-310.pyc
ADDED
Binary file (1.36 kB). View file
|
|
components/__pycache__/induce_personality.cpython-38.pyc
ADDED
Binary file (1.4 kB). View file
|
|
components/__pycache__/induce_personality.cpython-39.pyc
ADDED
Binary file (1.36 kB). View file
|
|
components/__pycache__/prompt.cpython-310.pyc
ADDED
Binary file (1.15 kB). View file
|
|
components/__pycache__/prompt.cpython-38.pyc
ADDED
Binary file (1.19 kB). View file
|
|
components/__pycache__/prompt.cpython-39.pyc
ADDED
Binary file (1.17 kB). View file
|
|
components/__pycache__/query_rewriting.cpython-310.pyc
ADDED
Binary file (2.02 kB). View file
|
|
components/__pycache__/query_rewriting.cpython-38.pyc
ADDED
Binary file (2.05 kB). View file
|
|
components/__pycache__/rag_components.cpython-310.pyc
ADDED
Binary file (5.96 kB). View file
|
|
components/__pycache__/rag_components.cpython-38.pyc
ADDED
Binary file (6 kB). View file
|
|
components/__pycache__/rewrite_passages.cpython-310.pyc
ADDED
Binary file (2.82 kB). View file
|
|
components/__pycache__/rewrite_passages.cpython-38.pyc
ADDED
Binary file (2.85 kB). View file
|
|
components/chat_conversation.py
ADDED
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from components.induce_personality import construct_big_five_words
|
2 |
+
from components.constant import (
|
3 |
+
ACCESS,
|
4 |
+
QUERY_REWRITING,
|
5 |
+
RAG,
|
6 |
+
PERSONALITY,
|
7 |
+
PERSONALITY_LIST,
|
8 |
+
REWRITE_PASSAGES,
|
9 |
+
NUM_PASSAGES,
|
10 |
+
DEVICE,
|
11 |
+
RESPONSE_GENERATOR,
|
12 |
+
TEMPLATE_PAYLOAD,
|
13 |
+
)
|
14 |
+
from components.prompt import SYSTEM_INSTRUCTION, RAG_INSTRUCTION, PERSONALITY_INSTRUCTION
|
15 |
+
import requests
|
16 |
+
import together
|
17 |
+
|
18 |
+
|
19 |
+
def generate_response_debugging(history):
|
20 |
+
# outputs_text = "This is a test response"
|
21 |
+
outputs_text = " ".join([item["content"] for item in history])
|
22 |
+
history = history + [{"role": "assistant", "content": outputs_text}]
|
23 |
+
return outputs_text, history
|
24 |
+
|
25 |
+
|
26 |
+
# REWRITER = "castorini/t5-base-canard"
|
27 |
+
def generate_response_together_api(history, max_tokens, client, model="meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"):
|
28 |
+
together_request = {
|
29 |
+
"model": model,
|
30 |
+
"messages": history,
|
31 |
+
"stream": False,
|
32 |
+
"logprobs": False,
|
33 |
+
"stop": ["<eos>", "<unk>", "<sep>", "<pad>", "<cls>", "<mask>"],
|
34 |
+
"max_tokens": max_tokens,
|
35 |
+
}
|
36 |
+
response = client.chat.completions.create(**together_request)
|
37 |
+
outputs_text = response.choices[0].message.content
|
38 |
+
history = history + [{"role": "assistant", "content": outputs_text}]
|
39 |
+
return outputs_text, history
|
40 |
+
|
41 |
+
|
42 |
+
def make_local_api_call(payload, api_url):
|
43 |
+
try:
|
44 |
+
# Send the POST request to the API
|
45 |
+
response = requests.post(api_url, json=payload)
|
46 |
+
|
47 |
+
# Check if the request was successful
|
48 |
+
if response.status_code == 200:
|
49 |
+
result = response.json()
|
50 |
+
# Print the generated text
|
51 |
+
return result.get("text", [""])[0]
|
52 |
+
# if "logits" in result:
|
53 |
+
# print(f"Logits: {result['logits']}")
|
54 |
+
else:
|
55 |
+
# If there was an error, print the status code and message
|
56 |
+
print(f"Error: {response.status_code}")
|
57 |
+
print(response.text)
|
58 |
+
|
59 |
+
except requests.exceptions.RequestException as e:
|
60 |
+
print(f"Request failed: {e}")
|
61 |
+
|
62 |
+
|
63 |
+
def generate_response_local_api(history, terminator, max_tokens, api_url):
|
64 |
+
payload = TEMPLATE_PAYLOAD.copy()
|
65 |
+
payload.update(
|
66 |
+
{
|
67 |
+
"prompt": history,
|
68 |
+
"max_tokens": max_tokens,
|
69 |
+
"stop_token_ids": terminator,
|
70 |
+
}
|
71 |
+
)
|
72 |
+
# Call the API to generate the response
|
73 |
+
outputs_text = make_local_api_call(payload, api_url)
|
74 |
+
|
75 |
+
if outputs_text:
|
76 |
+
# Update history with the assistant's response
|
77 |
+
history = history + [{"role": "assistant", "content": outputs_text}]
|
78 |
+
return outputs_text, history
|
79 |
+
else:
|
80 |
+
print("Failed to generate a response.")
|
81 |
+
return "Generation failed", history # Return the original history in case of failure
|
82 |
+
|
83 |
+
|
84 |
+
def conversation_window(history, N=100):
|
85 |
+
if len(history) > N:
|
86 |
+
return history[2:]
|
87 |
+
return history
|
88 |
+
|
89 |
+
|
90 |
+
def format_message_history(message, history):
|
91 |
+
if not history:
|
92 |
+
str_history = f"\n<user>: {message}\n<assistant>"
|
93 |
+
else:
|
94 |
+
# Query written
|
95 |
+
str_history = (
|
96 |
+
"".join(["".join(["\n<user>:" + item[0], "\n<assistant>:" + item[1]]) for item in history])
|
97 |
+
+ f"\n<user>: {message}\n<assistant>"
|
98 |
+
)
|
99 |
+
return str_history
|
100 |
+
|
101 |
+
|
102 |
+
def format_user_message(message, history):
|
103 |
+
return history + [{"role": "user", "content": message}]
|
104 |
+
|
105 |
+
|
106 |
+
def format_context(message, history):
|
107 |
+
return [{"role": "system", "content": message}] + history
|
108 |
+
|
109 |
+
|
110 |
+
def prepare_tokenizer(tokenizer):
|
111 |
+
special_tokens = ["<eos>", "<unk>", "<sep>", "<pad>", "<cls>", "<mask>"]
|
112 |
+
for token in special_tokens:
|
113 |
+
if tokenizer.convert_tokens_to_ids(token) is None:
|
114 |
+
tokenizer.add_tokens([token])
|
115 |
+
|
116 |
+
if tokenizer.eos_token_id is None:
|
117 |
+
tokenizer.eos_token_id = tokenizer.convert_tokens_to_ids("<eos>")
|
118 |
+
terminators = [
|
119 |
+
tokenizer.eos_token_id,
|
120 |
+
# self.pipeline.tokenizer.convert_tokens_to_ids(""),
|
121 |
+
]
|
122 |
+
return tokenizer, terminators
|
123 |
+
|
124 |
+
|
125 |
+
def gradio_to_huggingface_message(gradio_message):
|
126 |
+
huggingface_message = []
|
127 |
+
for user, bot in gradio_message:
|
128 |
+
huggingface_message.append({"role": "user", "content": user})
|
129 |
+
huggingface_message.append({"role": "assistant", "content": bot})
|
130 |
+
return huggingface_message
|
131 |
+
|
132 |
+
|
133 |
+
def huggingface_to_gradio_message(huggingface_message):
|
134 |
+
gradio_message = []
|
135 |
+
store = []
|
136 |
+
for utter in huggingface_message:
|
137 |
+
if utter["role"] in ["user", "assistant"]:
|
138 |
+
if utter["role"] == "assistant":
|
139 |
+
store.append(utter["content"])
|
140 |
+
gradio_message.append(store)
|
141 |
+
store = []
|
142 |
+
else:
|
143 |
+
store.append(utter["content"])
|
144 |
+
return gradio_message
|
145 |
+
|
146 |
+
|
147 |
+
def get_personality_instruction(personality):
|
148 |
+
return PERSONALITY_INSTRUCTION.format(personality)
|
149 |
+
|
150 |
+
|
151 |
+
def get_system_instruction(rag=RAG, personality_list=None):
|
152 |
+
if rag and personality_list:
|
153 |
+
return (
|
154 |
+
SYSTEM_INSTRUCTION
|
155 |
+
+ RAG_INSTRUCTION
|
156 |
+
+ get_personality_instruction(construct_big_five_words(personality_list))
|
157 |
+
)
|
158 |
+
elif personality_list:
|
159 |
+
return SYSTEM_INSTRUCTION + get_personality_instruction(construct_big_five_words(personality_list))
|
160 |
+
elif rag:
|
161 |
+
return SYSTEM_INSTRUCTION + RAG_INSTRUCTION
|
162 |
+
else:
|
163 |
+
return SYSTEM_INSTRUCTION
|
164 |
+
|
165 |
+
|
166 |
+
def format_rag_context(rag_context):
|
167 |
+
"""
|
168 |
+
rag_context [{"passage_id": clue_web, "passage_text": "abc"}, ...]
|
169 |
+
"""
|
170 |
+
passage_context = "Context: \n"
|
171 |
+
for passage_rank, info in enumerate(rag_context):
|
172 |
+
passage_context += f"Passage ID: {info['passage_id']}, Text: {info['passage_text']}\n\n"
|
173 |
+
return passage_context
|
components/constant.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Configuration Constants
|
2 |
+
import os
|
3 |
+
|
4 |
+
ACCESS = os.getenv("HF_ACCESS_TOKEN")
|
5 |
+
QUERY_REWRITING = False
|
6 |
+
RAG = False
|
7 |
+
PERSONALITY = True
|
8 |
+
PERSONALITY_LIST = ["introverted", "antagonistic", "conscientious", "emotionally stable", "open to experience"]
|
9 |
+
REWRITE_PASSAGES = False
|
10 |
+
NUM_PASSAGES = 3
|
11 |
+
DEVICE = "cuda"
|
12 |
+
RESPONSE_GENERATOR = "meta-llama/Meta-Llama-3.1-8B-Instruct"
|
13 |
+
CONV_WINDOW = 100
|
14 |
+
API_URL = "http://10.249.1.2:8888/generate"
|
15 |
+
TEMPLATE_PAYLOAD = {
|
16 |
+
"stream": False, # Set to True if you want to stream the results
|
17 |
+
"logprobs": False, # Set to True if you want the log probabilities of the tokens
|
18 |
+
"include_prompt": False, # Whether to include the original prompt in the response}
|
19 |
+
}
|
components/induce_personality.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import itertools
|
2 |
+
|
3 |
+
personality_types = [["extroverted", "introverted"], ["agreeable", "antagonistic"], ["conscientious", "unconscientious"], ["neurotic", "emotionally stable"], ["open to experience", "closed to experience"]]
|
4 |
+
|
5 |
+
|
6 |
+
def construct_big_five_words(persona_type: list):
|
7 |
+
"""Construct the list of personality traits
|
8 |
+
|
9 |
+
e.g., introverted + antagonistic + conscientious + emotionally stable + open to experience
|
10 |
+
"""
|
11 |
+
options = list(persona_type)
|
12 |
+
assert options[0] in ["extroverted", "introverted"], "Invalid personality type"
|
13 |
+
assert options[1] in ["agreeable", "antagonistic"], "Invalid personality type"
|
14 |
+
assert options[2] in ["conscientious", "unconscientious"], "Invalid personality type"
|
15 |
+
assert options[3] in ["neurotic", "emotionally stable"], "Invalid personality type"
|
16 |
+
assert options[4] in ["open to experience", "closed to experience"], "Invalid personality type"
|
17 |
+
last_item = "and " + options[-1]
|
18 |
+
options[-1] = last_item
|
19 |
+
return ", ".join(options)
|
20 |
+
|
21 |
+
def build_personality_prompt(persona_type: list):
|
22 |
+
return "You are a character who is {}.".format(construct_big_five_words(persona_type))
|
23 |
+
|
24 |
+
|
25 |
+
|
26 |
+
if __name__ == "__main__":
|
27 |
+
count = 0
|
28 |
+
for persona_type in itertools.product(*personality_types):
|
29 |
+
system_prompt = "You are a character who is {}.".format(construct_big_five_words(persona_type))
|
30 |
+
print(system_prompt)
|
31 |
+
print("\n")
|
32 |
+
count += 1
|
33 |
+
if count == 5:
|
34 |
+
break
|
components/prompt.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
SYSTEM_INSTRUCTION = """You are an AI financial advisor. Help the client by answering their questions based on conversation history and retrieved passages it if it is relevant and useful for answering the question."""
|
2 |
+
RAG_INSTRUCTION = """The retrieved passages are contained in the context. With the information contained in the context, give a comprehensive answer to the query. Only use the context if it is relevant and useful for answering the question. Your response should be concise and directly address the question asked. When applicable, mention the source document number."""
|
3 |
+
PERSONALITY_INSTRUCTION = """You are a character who is {}"""
|
4 |
+
DEMONSTRATION = """You are an AI financial advisor. Help the client by answering their questions based on retrieved passages from the web and conversation history. Only respond to the user’s latest message and only finish passages starting with <assistant> do not write <user> part.
|
5 |
+
Retrieved passages:
|
6 |
+
{}
|
7 |
+
|
8 |
+
Here is the conversation history:
|
9 |
+
{}
|
10 |
+
"""
|
components/query_rewriting.py
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from components.rag_components import get_length_without_special_tokens
|
2 |
+
import ipdb
|
3 |
+
|
4 |
+
QUERY_REWRITING = """Given a user query and its context (conversational history), decontextualize the question by addressing coreference and omission issues. The resulting question should retain its original meaning and be as informative as possible, and should not duplicate any previously asked questions in the context. JUST ANSWER THE RESOLVED QUERY WITHOUT ANY OTHER SENTENCES.\nContext: {}\n"""
|
5 |
+
REMINDER = """\nRemember you are a query rewriter. JUST ANSWER THE RESOLVED QUERY WITHOUT ANY OTHER SENTENCES."""
|
6 |
+
|
7 |
+
|
8 |
+
def get_context_from_message_history(message_history):
|
9 |
+
context = ""
|
10 |
+
for message in message_history:
|
11 |
+
if message["role"] not in ["system"]:
|
12 |
+
context += f'{message["role"]}: {message["content"]}\n'
|
13 |
+
return context if context else "No context available."
|
14 |
+
|
15 |
+
|
16 |
+
def rewrite_query(query: str, history: str, rewriter, rewriter_tokenizer, rewriter_terminator, device="cuda", max_tokens=256, temperature=0.0, top_p=0.9) -> str:
|
17 |
+
# ipdb.set_trace()
|
18 |
+
# DELETE LAST \n<assistant>\n
|
19 |
+
history = "\n".join(history.split("\n")[:-1])
|
20 |
+
system_prompt = QUERY_REWRITING.format(history)
|
21 |
+
|
22 |
+
query += REMINDER
|
23 |
+
user_prompt = [{"role": "system", "content": system_prompt}, {"role": "user", "content": f"user query: {query}"}]
|
24 |
+
prompt = rewriter_tokenizer.apply_chat_template(user_prompt, tokenize=False, add_generation_prompt=True)
|
25 |
+
print("user_prompt:", user_prompt)
|
26 |
+
print("PROMPT:", prompt)
|
27 |
+
# ipdb.set_trace()
|
28 |
+
print("System Prompt:", system_prompt)
|
29 |
+
print("Prompt:", prompt)
|
30 |
+
|
31 |
+
inputs = rewriter_tokenizer(prompt, return_tensors="pt").to(rewriter.device)
|
32 |
+
outputs = rewriter.generate(
|
33 |
+
**inputs,
|
34 |
+
max_new_tokens=max_tokens,
|
35 |
+
eos_token_id=rewriter_terminator,
|
36 |
+
do_sample=False, # Greedy decoding to be deterministic
|
37 |
+
# temperature=temperature,
|
38 |
+
top_p=top_p,
|
39 |
+
)
|
40 |
+
prompt_length = get_length_without_special_tokens(prompt, rewriter_tokenizer)
|
41 |
+
response = rewriter_tokenizer.decode(outputs[0], skip_special_tokens=True)[prompt_length:]
|
42 |
+
return response.strip()
|
43 |
+
|
44 |
+
|
45 |
+
# def rewrite_query(query: str, history: str, rewriter, rewriter_tokenizer, device="cuda") -> str:
|
46 |
+
# context = "|||".join([history, query])
|
47 |
+
# # rewriter = AutoModelForSeq2SeqLM.from_pretrained(model_name).to(device).eval()
|
48 |
+
# # rewriter_tokenizer = AutoTokenizer.from_pretrained(model_name)
|
49 |
+
# tokenized_context = rewriter_tokenizer.encode(context, return_tensors="pt").to(device)
|
50 |
+
# output_ids = rewriter.generate(
|
51 |
+
# tokenized_context,
|
52 |
+
# max_length=200,
|
53 |
+
# num_beams=4,
|
54 |
+
# repetition_penalty=2.5,
|
55 |
+
# length_penalty=1.0,
|
56 |
+
# early_stopping=True
|
57 |
+
# ).to(device)
|
58 |
+
|
59 |
+
# rewrite = rewriter_tokenizer.decode(output_ids[0], skip_special_tokens=True)
|
60 |
+
# return rewrite
|
components/rag_components.py
ADDED
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import json
|
3 |
+
|
4 |
+
# Load model and tokenizer from HuggingFace
|
5 |
+
import numpy as np
|
6 |
+
import pandas as pd
|
7 |
+
import torch
|
8 |
+
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
9 |
+
from sentence_transformers import CrossEncoder
|
10 |
+
|
11 |
+
# from pyserini.search.lucene import LuceneSearcher
|
12 |
+
import pyterrier as pt
|
13 |
+
from pyterrier_t5 import MonoT5ReRanker, DuoT5ReRanker
|
14 |
+
|
15 |
+
if not pt.started():
|
16 |
+
pt.init()
|
17 |
+
import ipdb
|
18 |
+
|
19 |
+
|
20 |
+
def extract_context(json_data, number, turn_id):
|
21 |
+
# Find the correct dictionary with the given number
|
22 |
+
data = None
|
23 |
+
for item in json_data:
|
24 |
+
if item["number"] == number:
|
25 |
+
data = item
|
26 |
+
break
|
27 |
+
|
28 |
+
# If we couldn't find the data for the given number
|
29 |
+
if not data:
|
30 |
+
print("No data found for the given number.")
|
31 |
+
return "No data found for the given number.", None
|
32 |
+
|
33 |
+
# Extract the utterance and response values
|
34 |
+
texts = []
|
35 |
+
current_utterance = ""
|
36 |
+
for turn in data["turns"]:
|
37 |
+
if turn["turn_id"] < turn_id:
|
38 |
+
texts.append(turn["utterance"])
|
39 |
+
texts.append(turn["response"])
|
40 |
+
elif turn["turn_id"] == turn_id:
|
41 |
+
current_utterance = turn["utterance"]
|
42 |
+
texts.append(current_utterance)
|
43 |
+
|
44 |
+
# Join the texts with "|||" separator
|
45 |
+
context = "|||".join(texts)
|
46 |
+
|
47 |
+
return current_utterance, context
|
48 |
+
|
49 |
+
|
50 |
+
def escape_special_characters(query):
|
51 |
+
# Escaping special characters
|
52 |
+
special_chars = ["?", "&", "|", "!", "{", "}", "[", "]", "^", "~", "*", ":", '"', "+", "-", "(", ")"]
|
53 |
+
for char in special_chars:
|
54 |
+
query = query.replace(char, "")
|
55 |
+
return query
|
56 |
+
|
57 |
+
|
58 |
+
def str_to_df_query(query):
|
59 |
+
if isinstance(query, str):
|
60 |
+
query = escape_special_characters(query)
|
61 |
+
return pd.DataFrame([[1, query]], columns=["qid", "query"])
|
62 |
+
elif isinstance(query, list):
|
63 |
+
query = [escape_special_characters(q) for q in query]
|
64 |
+
return pd.DataFrame([[i + 1, q] for i, q in enumerate(query)], columns=["qid", "query"])
|
65 |
+
else:
|
66 |
+
raise ValueError("The query must be a string or a list of strings.")
|
67 |
+
|
68 |
+
|
69 |
+
def retrieve_and_rerank(query, pipeline):
|
70 |
+
query_df = str_to_df_query(query)
|
71 |
+
res = pipeline.transform(query_df)
|
72 |
+
candidate_set = []
|
73 |
+
for i, row in res.iterrows():
|
74 |
+
passage_id = row["docno"]
|
75 |
+
rank = row["rank"]
|
76 |
+
score = row["score"]
|
77 |
+
passage_text = row["text"]
|
78 |
+
candidate_set.append({"passage_id": passage_id, "rank": i + 1, "score": score, "passage_text": passage_text})
|
79 |
+
return candidate_set
|
80 |
+
|
81 |
+
|
82 |
+
def rerank_passages(query, passages, reranker):
|
83 |
+
res = []
|
84 |
+
query_passage_pairs = [[query, passage["passage_text"]] for passage in passages]
|
85 |
+
scores = reranker.predict(query_passage_pairs)
|
86 |
+
|
87 |
+
for passage, score in zip(passages, scores):
|
88 |
+
passage["reranker_score"] = score
|
89 |
+
res.append(passage)
|
90 |
+
|
91 |
+
ranked_passages = sorted(passages, key=lambda x: x["reranker_score"], reverse=True)
|
92 |
+
return ranked_passages
|
93 |
+
|
94 |
+
|
95 |
+
def rag(rewrite, top_n_passages=3):
|
96 |
+
# Set up
|
97 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
98 |
+
# Set Up Index
|
99 |
+
index_path = os.path.join("/root/nfs/iKAT/2023/ikat_index/index_pyterrier_with_text", "data.properties")
|
100 |
+
index = pt.IndexFactory.of(index_path)
|
101 |
+
# Set up Pipeline for retrieval and reranking
|
102 |
+
bm25 = pt.BatchRetrieve(index, wmodel="BM25", metadata=["docno", "text"])
|
103 |
+
monoT5 = MonoT5ReRanker()
|
104 |
+
pipeline = (bm25 % 10) >> pt.text.get_text(index, "text") >> (monoT5 % 5) >> pt.text.get_text(index, "text")
|
105 |
+
# Passage retrieval and reranking
|
106 |
+
reranked_passages = retrieve_and_rerank(rewrite, pipeline)
|
107 |
+
passages = [{"passage_id": passage["passage_id"], "passage_text": passage["passage_text"]} for passage in reranked_passages][:top_n_passages]
|
108 |
+
return passages
|
109 |
+
|
110 |
+
|
111 |
+
def retrieve_passage(resolved_query, history, RAG, top_n_passages=3):
|
112 |
+
# TODO: RAG function
|
113 |
+
if RAG:
|
114 |
+
if len(history) >= 1:
|
115 |
+
rag_context = rag(resolved_query, top_n_passages)
|
116 |
+
else:
|
117 |
+
rag_context = rag(
|
118 |
+
resolved_query,
|
119 |
+
)
|
120 |
+
else:
|
121 |
+
rag_context = "No Context"
|
122 |
+
return rag_context
|
123 |
+
|
124 |
+
|
125 |
+
def get_length_without_special_tokens(text, tokenizer):
|
126 |
+
# Tokenize the prompt and get input IDs
|
127 |
+
inputs = tokenizer(text, return_tensors="pt")
|
128 |
+
# Extract the input IDs from the tokenized output
|
129 |
+
input_ids = inputs.input_ids[0]
|
130 |
+
# Decode the input IDs to a string, skipping special tokens
|
131 |
+
decoded_text = tokenizer.decode(input_ids, skip_special_tokens=True)
|
132 |
+
|
133 |
+
return len(decoded_text)
|
134 |
+
|
135 |
+
|
136 |
+
def response_generation(messages, model, tokenizer, device, terminators, max_tokens=512, temperature=0.0, top_p=0.9):
|
137 |
+
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
138 |
+
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
139 |
+
outputs = model.generate(
|
140 |
+
**inputs,
|
141 |
+
max_new_tokens=max_tokens,
|
142 |
+
eos_token_id=terminators,
|
143 |
+
do_sample=False, # Greedy_decoding to be deterministic
|
144 |
+
# temperature=temperature,
|
145 |
+
top_p=top_p,
|
146 |
+
)
|
147 |
+
|
148 |
+
prompt_length = get_length_without_special_tokens(prompt, tokenizer)
|
149 |
+
response = tokenizer.decode(outputs[0], skip_special_tokens=True)[prompt_length:]
|
150 |
+
# ipdb.set_trace()
|
151 |
+
return response.strip(), messages + [{"role": "assistant", "content": response.strip()}]
|
152 |
+
|
153 |
+
|
154 |
+
if __name__ == "__main__":
|
155 |
+
# Set up
|
156 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
157 |
+
demo_path = "/nfs/primary/iKAT/2023/"
|
158 |
+
with open(os.path.join(demo_path, "ikat_demo/test.json"), "r") as f:
|
159 |
+
topics = json.load(f)
|
160 |
+
|
161 |
+
# Set up Index
|
162 |
+
index_path = os.path.join("/root/nfs/iKAT/2023/index_pyterrier_with_text", "data.properties")
|
163 |
+
index = pt.IndexFactory.of(index_path)
|
164 |
+
|
165 |
+
# Set up Pipeline for retrieval and reranking
|
166 |
+
bm25 = pt.BatchRetrieve(index, wmodel="BM25", metadata=["docno", "text"])
|
167 |
+
monoT5 = MonoT5ReRanker()
|
168 |
+
pipeline = (bm25 % 10) >> pt.text.get_text(index, "text") >> (monoT5 % 5) >> pt.text.get_text(index, "text")
|
169 |
+
|
170 |
+
query = "Can you compare mozzarella with plant-based cheese?"
|
171 |
+
|
172 |
+
# Query rewriting
|
173 |
+
rewriter = AutoModelForSeq2SeqLM.from_pretrained("castorini/t5-base-canard").to(device).eval()
|
174 |
+
rewriter_tokenizer = AutoTokenizer.from_pretrained("castorini/t5-base-canard")
|
175 |
+
number_to_search = "10-1"
|
176 |
+
turn_id_to_search = 6
|
177 |
+
utterance, context = extract_context(topics, number_to_search, turn_id_to_search)
|
178 |
+
rewrite = rewrite_query(context, rewriter, rewriter_tokenizer, device)
|
179 |
+
|
180 |
+
# Passage Retrieval and Reranking
|
181 |
+
reranked_passages = retrieve_and_rerank(rewrite, pipeline)
|
182 |
+
|
183 |
+
# Response generation
|
184 |
+
summarizer = AutoModelForSeq2SeqLM.from_pretrained("mrm8488/t5-base-finetuned-summarize-news")
|
185 |
+
summarizer_tokenizer = AutoTokenizer.from_pretrained("mrm8488/t5-base-finetuned-summarize-news")
|
186 |
+
# We use the top-3 reranked passages to generate a response
|
187 |
+
passages = [passage["passage_text"] for passage in reranked_passages][:3]
|
188 |
+
print(json.dumps(passages, indent=4))
|
189 |
+
responses = generate_response(passages, summarizer, summarizer_tokenizer)
|
190 |
+
print("Done")
|
components/rewrite_passages.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from components.rag_components import get_length_without_special_tokens
|
2 |
+
|
3 |
+
REWRITE_PASSAGE_PROMPT = """
|
4 |
+
A passage has been retrieved from the web based on the query: {}. Please extract only the information that is essential for answering this query with at most two or three sentences. If the passage contains no relevant information, do not extract anything. Provide the extracted information directly without any introductory phrases or additional context.
|
5 |
+
Query: {}\n
|
6 |
+
Passage: {}\n
|
7 |
+
"""
|
8 |
+
|
9 |
+
|
10 |
+
def rewrite_rag_context(resolved_query, rag_context, model, tokenizer, terminator):
|
11 |
+
"""
|
12 |
+
Rewrites the passages in the RAG context based on the resolved query.
|
13 |
+
|
14 |
+
Args:
|
15 |
+
resolved_query (str): The resolved user query.
|
16 |
+
rag_context (list): A list of dictionaries, each containing 'passage_id' and 'passage_text'.
|
17 |
+
model: The model used for generating rewritten passages.
|
18 |
+
tokenizer: The tokenizer used for processing text.
|
19 |
+
terminator: The terminator token for the model.
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
list: A list of dictionaries with rewritten passages.
|
23 |
+
"""
|
24 |
+
retrieved_passages = []
|
25 |
+
for passage in rag_context:
|
26 |
+
rewrite = rewrite_passage(resolved_query, passage["passage_text"], model, tokenizer, terminator)
|
27 |
+
retrieved_passages.append({"passage_id": passage["passage_id"], "passage_text": rewrite})
|
28 |
+
return retrieved_passages
|
29 |
+
|
30 |
+
|
31 |
+
def rewrite_passage(resolved_query, passage, model, tokenizer, terminator, max_tokens=256, temperature=0.0, top_p=0.9):
|
32 |
+
"""
|
33 |
+
Rewrites a single passage based on the resolved query.
|
34 |
+
|
35 |
+
Args:
|
36 |
+
resolved_query (str): The resolved user query.
|
37 |
+
passage (str): The passage text to be rewritten.
|
38 |
+
model: The model used for generating rewritten passages.
|
39 |
+
tokenizer: The tokenizer used for processing text.
|
40 |
+
terminator: The terminator token for the model.
|
41 |
+
max_tokens (int): The maximum number of tokens to generate. Default is 256.
|
42 |
+
temperature (float): The temperature for sampling. Default is 0.6.
|
43 |
+
top_p (float): The nucleus sampling probability. Default is 0.9.
|
44 |
+
|
45 |
+
Returns:
|
46 |
+
str: The rewritten passage.
|
47 |
+
"""
|
48 |
+
chatbot = []
|
49 |
+
user_prompt = REWRITE_PASSAGE_PROMPT.format(resolved_query, passage, passage)
|
50 |
+
chatbot.append({"role": "user", "content": user_prompt})
|
51 |
+
prompt = tokenizer.apply_chat_template(chatbot, tokenize=False, add_generation_prompt=True)
|
52 |
+
|
53 |
+
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
54 |
+
outputs = model.generate(
|
55 |
+
**inputs,
|
56 |
+
max_new_tokens=max_tokens,
|
57 |
+
eos_token_id=terminator,
|
58 |
+
do_sample=False, # Greedy decoding to be deterministic
|
59 |
+
# temperature=temperature
|
60 |
+
top_p=top_p,
|
61 |
+
)
|
62 |
+
|
63 |
+
prompt_length = get_length_without_special_tokens(prompt, tokenizer)
|
64 |
+
response = tokenizer.decode(outputs[0], skip_special_tokens=True)[prompt_length:]
|
65 |
+
return response.strip()
|
66 |
+
|
67 |
+
|
68 |
+
# def rewrite_rag_context(resoloved_query, rag_context, model, tokenizer, terminator):
|
69 |
+
# """
|
70 |
+
# rag_context: [{"passage_id": passage["passage_id"], "passage_text": passage['passage_text']} for passage in reranked_passages]
|
71 |
+
# """
|
72 |
+
# retrieved_passages = []
|
73 |
+
# for passage in rag_context:
|
74 |
+
# rewrite = rewrite_passage(resoloved_query, passage["passage_text"], model, tokenizer, terminator)
|
75 |
+
# retrieved_passages.append([{"passage_id": passage["passage_id"], "passage_text":rewrite}])
|
76 |
+
# return retrieved_passages
|
77 |
+
|
78 |
+
# def rewrite_passage(resoloved_query, passage, model, tokenizer, terminator, max_tokens=256, temperature=0.6, top_p=0.9):
|
79 |
+
# chatbot = []
|
80 |
+
# user_prompt = REWRITE_PASSAGE_PROMPT.format(resoloved_query, passage, passage)
|
81 |
+
# chatbot.append({"role": "user", "content": message})
|
82 |
+
# prompt = tokenizer.apply_chat_template(chatbot, tokenize=False, add_generation_prompt=True)
|
83 |
+
# outputs = model.generate(
|
84 |
+
# **inputs,
|
85 |
+
# max_new_tokens=max_tokens,
|
86 |
+
# eos_token_id=terminators,
|
87 |
+
# do_sample=True,
|
88 |
+
# temperature=temperature,
|
89 |
+
# top_p=top_p,
|
90 |
+
# )
|
91 |
+
|
92 |
+
# prompt_length = get_length_without_special_tokens(prompt, tokenizer)
|
93 |
+
# response = tokenizer.decode(outputs[0], skip_special_tokens=True)[prompt_length:]
|
94 |
+
# return response.strip()
|
data/single_stock_data/experiment_processed_data.jsonl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
{"topic": "healthcare_growth_defensive", "data": [{"ticker": "LLY", "sector": "Healthcare", "industry": "Drug Manufacturers - General", "business_summary": "Eli Lilly and Company discovers, develops, and markets human pharmaceuticals worldwide. The company offers Basaglar, Humalog, Humalog Mix 75/25, Humalog U-100, Humalog U-200, Humalog Mix 50/50, insulin lispro, insulin lispro protamine, insulin lispro mix 75/25, Humulin, Humulin 70/30, Humulin N, Humulin R, and Humulin U-500 for diabetes; Jardiance, Mounjaro, and Trulicity for type 2 diabetes; and Zepbound for obesity. It also provides oncology products, including Alimta, Cyramza, Erbitux, Jaypirca, Retevmo, Tyvyt, and Verzenio. In addition, the company offers Olumiant for rheumatoid arthritis, atopic dermatitis, severe alopecia areata, and COVID-19; Taltz for plaque psoriasis, psoriatic arthritis, ankylosing spondylitis, and non-radiographic axial spondylarthritis; Omvoh for ulcerative colitis; Cymbalta for depressive disorder, diabetic peripheral neuropathic pain, generalized anxiety disorder, fibromyalgia, and chronic musculoskeletal pain; Ebglyss for severe atopic dermatitis; and Emgality for migraine prevention and episodic cluster headache. Further, it provides Cialis for erectile dysfunction and benign prostatic hyperplasia; and Forteo for osteoporosis. The company operates Lilly Seaport Innovation Center (LSC), a research and development facility in the Boston Seaport to advancing Lilly's efforts in RNA and DNA-based therapies as well as discovering new drug targets to create life-changing medicines across several disease states, including diabetes, obesity, cardiovascular diseases, neurodegeneration, and chronic pain. It has collaborations with Incyte Corporation; Boehringer Ingelheim Pharmaceuticals, Inc.; F. Hoffmann-La Roche Ltd and Genentech, Inc.; Biologics, Inc., AbCellera Biologics Inc.; and Chugai Pharmaceutical Co., Ltd, as well as development collaboration with Eli Lilly and Company for developing QIAstat-Dx IVD panel, for the detection of various APOE genotypes. The company was founded in 1876 and is headquartered in Indianapolis, Indiana.", "beta": 0.416, "short_name": "Eli Lilly and Company", "long_name": "Eli Lilly and Company", "price_data": "2023 Monthly Stock Price: Jan: 339.14, Feb: 307.68, Mar: 339.52, Apr: 391.36, May: 425.68, Jun: 464.85, Jul: 450.55, Aug: 550.50, Sep: 533.55, Oct: 550.23, Nov: 588.18, Dec: 580.10", "earning_summary": "Based on the provided conference call transcript, here's a summary of the key financial metrics discussed:\n\n1. **Revenue Growth**: Lilly's revenue increased 28% in Q2 2023 compared to Q2 2022. Excluding revenue from Baqsimi and COVID-19 antibodies, revenue grew 22% or 23% on a constant currency basis.\n2. **Gross Margin**: Gross margin as a percent of revenue was flat in Q2 at 79.8%. Gross margin benefited from product mix, including one-time revenue from the sales of rights to Baqsimi, which was offset by increases in manufacturing expenses related to labor costs and investments in capacity expansion.\n3. **Operating Expenses**: Total operating expenses increased 14% in Q2. Marketing, selling, and administrative expenses increased 18%, driven by higher marketing and selling expenses associated with recent and upcoming new product launches and additional indications. R&D expenses increased 32%, driven by higher development expenses for late-stage assets and additional investments in early-stage research.\n4. **Operating Income**: Operating income increased 69% in Q2 driven by higher revenue, including revenue associated with the sales of rights for Baqsimi and lower IPR&D charges, partially offset by higher R&D and SG&A expenses.\n5. **EPS**: Earnings per share (EPS) was $2.11 in Q2, a 69% increase versus Q2 of 2022, inclusive of $0.43 of EPS associated with the sales of rights for Baqsimi.\n6. **Price, Rate, and Volume**: In the U.S., net price increased 2% for the quarter driven by Mounjaro access and savings cards dynamics. Excluding Mounjaro, net price in the U.S. decreased by low single digits, consistent with prior trends.\n7. **Guidance**: Lilly updated its 2023 financial guidance, increasing revenue guidance by $2.2 billion to a range of $33.4 billion to $33.9 billion. The company also increased its guidance for gross margin as a percent of revenue to approximately 80%, driven by the sales of rights for Baqsimi and its olanzapine portfolio. Operating expense guidance was also increased, with marketing, selling, and administrative costs expected to be in the range of $7.2 billion to $7.4 billion, and research and development expenses expected to be in the range of $8.9", "topic": "healthcare_growth_defensive", "user_narrative": "**Name**: Alex Carter\n**Age**: 27\n**Occupation**: Healthcare Consultant\n**Marital Status**: Single\n**Children**: None\nAlex is a driven healthcare consultant who has been working in the industry for a few years. With a deep interest in healthcare, Alex is passionate about staying informed on medical innovations and the future of biotech companies. Although still in the early stages of their career, Alex is motivated by both personal and professional growth.\nTheir financial goals focus on growing wealth over time, particularly through investing in industries they understand. Alex\u2019s work has made them familiar with the unpredictable nature of the healthcare industry, but Alex maintains a strong belief in its potential for growth.\nAlex is not overly conservative and is willing to take measured risks, favoring rapidly expanding companies over those with more stable, predictable growth. Concerned about market downturns, Alex seeks stocks that can withstand economic shifts. Alex is uninterested in dividends, focusing instead on investments with strong potential for capital gains.", "label": 1}, {"ticker": "JNJ", "sector": "Healthcare", "industry": "Drug Manufacturers - General", "business_summary": "Johnson & Johnson, together with its subsidiaries, researches, develops, manufactures, and sells various products in the healthcare field worldwide. The company's Innovative Medicine segment offers products for various therapeutic areas, such as immunology, including rheumatoid arthritis, psoriatic arthritis, inflammatory bowel disease, and psoriasis; infectious diseases comprising HIV/AIDS; neuroscience, consisting of mood disorders, neurodegenerative disorders, and schizophrenia; oncology, such as prostate cancer, hematologic malignancies, lung cancer, and bladder cancer; cardiovascular and metabolism, including thrombosis, diabetes, and macular degeneration; and pulmonary hypertension comprising pulmonary arterial hypertension through retailers, wholesalers, distributors, hospitals, and healthcare professionals for prescription use. Its MedTech segment provides Interventional Solutions, including electrophysiology products to treat heart rhythm disorders; the heart recovery portfolio, which includes technologies to treat severe coronary artery disease requiring high-risk PCI or AMI cardiogenic shock; and neurovascular care that treats hemorrhagic and ischemic stroke. this segment also offers an orthopaedics portfolio that includes products and enabling technologies that support hips, knees, trauma, spine, sports, and other; surgery portfolios comprising advanced and general surgery technologies, as well as solutions for breast aesthetics, ear, nose, and throat procedures; contact lenses under the ACUVUE Brand; and TECNIS intraocular lenses for cataract surgery. It distributes its products to wholesalers, hospitals, and retailers, as well as physicians, nurses, hospitals, eye care professionals, and clinics. Johnson & Johnson was founded in 1886 and is based in New Brunswick, New Jersey.", "beta": 0.518, "short_name": "Johnson & Johnson", "long_name": "Johnson & Johnson", "price_data": "2023 Monthly Stock Price: Jan: 156.15, Feb: 147.49, Mar: 149.17, Apr: 157.54, May: 150.35, Jun: 160.50, Jul: 162.44, Aug: 157.91, Sep: 152.12, Oct: 144.88, Nov: 152.26, Dec: 154.31", "earning_summary": "Based on the provided conference call transcript, here's a detailed summary of the key financial metrics discussed:\n\n**Revenue and Sales:**\n\n* Worldwide sales: $21.4 billion, an increase of 6.8% versus the third quarter of 2022.\n* Operational sales growth: 6.4% (excluding the effect of translational currency).\n* U.S. sales: $11.1% increase.\n* Regions outside the U.S.: 1.6% reported growth, 0.7% operational growth.\n* Innovative medicine sales: $13.9 billion, an increase of 5.1% (excluding COVID-19 vaccine sales, worldwide operational sales growth was 8.2%).\n* MedTech sales: $7.5 billion, an increase of 10% (excluding the impact of acquisition and divestitures, worldwide adjusted operational sales growth was 6%).\n\n**Earnings:**\n\n* Net earnings: $4.3 billion.\n* Diluted earnings per share: $1.69.\n* Adjusted net earnings: $6.8 billion, an increase of 14.1% compared to the third quarter of 2022.\n* Adjusted diluted earnings per share: $2.66, an increase of 19.3% compared to the third quarter of 2022.\n\n**Guidance Update:**\n\n* Full-year sales guidance: $84.4 billion to $84.8 billion (constant currency basis), an increase of 8.5% to 9.0% (operational sales growth).\n* Adjusted operational sales growth: 7.2% to 7.7%.\n* Adjusted pre-tax operating margin: expected to improve by approximately 50 basis points versus prior year.\n* Net other income: $1.7 billion to $1.9 billion.\n* Net interest income: $300 million to $400 million.\n* Effective tax rate: 15.0% to 15.5%.\n\n**Cash and Capital Allocation:**\n\n* Cash and marketable securities: approximately $24 billion.\n* Debt: approximately $30 billion.\n* Net debt position: $6 billion.\n* Free cash flow: approximately $12 billion (year-to-date through the third quarter).\n\n**Preliminary Perspectives for 2024:**\n\n* Innovative medicine: confident in delivering growth from key brands and newly launched products, with continued progress from the pipeline.\n* MedTech: expect commercial capabilities and continued adoption of recently launched products to drive growth and improve competitiveness", "topic": "healthcare_growth_defensive", "user_narrative": "**Name**: Alex Carter\n**Age**: 27\n**Occupation**: Healthcare Consultant\n**Marital Status**: Single\n**Children**: None\nAlex is a driven healthcare consultant who has been working in the industry for a few years. With a deep interest in healthcare, Alex is passionate about staying informed on medical innovations and the future of biotech companies. Although still in the early stages of their career, Alex is motivated by both personal and professional growth.\nTheir financial goals focus on growing wealth over time, particularly through investing in industries they understand. Alex\u2019s work has made them familiar with the unpredictable nature of the healthcare industry, but Alex maintains a strong belief in its potential for growth.\nAlex is not overly conservative and is willing to take measured risks, favoring rapidly expanding companies over those with more stable, predictable growth. Concerned about market downturns, Alex seeks stocks that can withstand economic shifts. Alex is uninterested in dividends, focusing instead on investments with strong potential for capital gains.", "label": 2}, {"ticker": "PM", "sector": "Consumer Defensive", "industry": "Tobacco", "business_summary": "Philip Morris International Inc. operates as a tobacco company working to delivers a smoke-free future and evolving portfolio for the long-term to include products outside of the tobacco and nicotine sector. The company's product portfolio primarily consists of cigarettes and smoke-free products, including heat-not-burn, vapor, and oral nicotine products primarily under the IQOS and ZYN brands; and consumer accessories, such as lighters and matches. It also offers wellness and healthcare products. Philip Morris International Inc. was incorporated in 1987 and is headquartered in Stamford, Connecticut.", "beta": 0.576, "short_name": "Philip Morris International Inc", "long_name": "Philip Morris International Inc.", "price_data": "2023 Monthly Stock Price: Jan: 96.12, Feb: 89.73, Mar: 90.89, Apr: 93.43, May: 84.12, Jun: 92.45, Jul: 94.44, Aug: 90.97, Sep: 88.91, Oct: 85.63, Nov: 89.66, Dec: 91.60", "earning_summary": "Based on the provided transcript, here's a detailed summary of the key financial metrics discussed during the Q3 2023 earnings call of Philip Morris International Inc. (PMI):\n\n**Key Highlights:**\n\n1. **Revenue Growth:** PMI reported a strong Q3 2023 with net revenues of $9 billion, a 9.3% organic net revenue growth, and a 20.3% adjusted diluted EPS growth.\n2. **Volume Growth:** Total shipment volume increased by 2.2% in Q3 and 1.5% year-to-date, with HTU shipment volumes growing by 18% in Q3.\n3. **IQOS Performance:** IQOS HTU shipment volumes grew by 18% in Q3, with a 16.5% organic net revenue growth from smoke-free products.\n4. **ZYN Performance:** ZYN delivered a remarkable 66% volume growth in Q3, with a 70.8% category volume share and 76% retail value share in the US.\n5. **Operating Income Growth:** Adjusted operating income grew by 11.3% organically, with a 70 basis points organic margin expansion.\n6. **Cost Management:** PMI delivered a further $120 million in gross cost efficiencies in Q3, surpassing the $2 billion target for 2021-2023.\n7. **Full-Year Outlook:** PMI raised its volume, organic sales growth, and currency-neutral adjusted bottom-line growth forecast, with a 1% to 2% cigarette volume decline and a 390 million to 410 million cans of nicotine pouch forecast.\n8. **Dividend:** PMI has delivered 16 years of continuous dividend increase since 2008, with a cumulative 183% increase and a CAGR of 77.2%.\n\n**Key Financial Metrics:**\n\n1. **Net Revenues:** $9 billion (Q3 2023)\n2. **Organic Net Revenue Growth:** 9.3% (Q3 2023)\n3. **Adjusted Diluted EPS Growth:** 20.3% (Q3 2023)\n4. **Total Shipment Volume:** 2.2% growth (Q3 2023)\n5. **HTU Shipment Volumes:** 18% growth (Q3 2023)\n6. **IQOS HTU Shipment Volumes:** 18% growth (Q3", "topic": "healthcare_growth_defensive", "user_narrative": "**Name**: Alex Carter\n**Age**: 27\n**Occupation**: Healthcare Consultant\n**Marital Status**: Single\n**Children**: None\nAlex is a driven healthcare consultant who has been working in the industry for a few years. With a deep interest in healthcare, Alex is passionate about staying informed on medical innovations and the future of biotech companies. Although still in the early stages of their career, Alex is motivated by both personal and professional growth.\nTheir financial goals focus on growing wealth over time, particularly through investing in industries they understand. Alex\u2019s work has made them familiar with the unpredictable nature of the healthcare industry, but Alex maintains a strong belief in its potential for growth.\nAlex is not overly conservative and is willing to take measured risks, favoring rapidly expanding companies over those with more stable, predictable growth. Concerned about market downturns, Alex seeks stocks that can withstand economic shifts. Alex is uninterested in dividends, focusing instead on investments with strong potential for capital gains.", "label": 3}, {"ticker": "XOM", "sector": "Energy", "industry": "Oil & Gas Integrated", "business_summary": "Exxon Mobil Corporation engages in the exploration and production of crude oil and natural gas in the United States and internationally. It operates through Upstream, Energy Products, Chemical Products, and Specialty Products segments. The Upstream segment explores for and produces crude oil and natural gas. The Energy Products segment offers fuels, aromatics, and catalysts, as well as licensing services. It sells its products under the Exxon, Esso, and Mobil brands. The Chemical Products segment manufactures and markets petrochemicals including olefins, polyolefins, and intermediates. The Specialty Products segment offers performance products, including lubricants, basestocks, waxes, synthetics, elastomers, and resins. The company also involves in the manufacturing, trade, transport, and sale of crude oil, natural gas, petroleum products, petrochemicals, and other specialty products; and pursuit lower-emission business opportunities, including carbon capture and storage, hydrogen, lower-emission fuels, and lithium. Exxon Mobil Corporation was founded in 1870 and is based in Spring, Texas.", "beta": 0.877, "short_name": "Exxon Mobil Corporation", "long_name": "Exxon Mobil Corporation", "price_data": "2023 Monthly Stock Price: Jan: 109.37, Feb: 104.42, Mar: 104.18, Apr: 112.43, May: 97.92, Jun: 102.77, Jul: 102.76, Aug: 107.42, Sep: 113.60, Oct: 102.26, Nov: 100.17, Dec: 97.48", "earning_summary": "**Summary of Key Financial Metrics:**\n\n1. **Earnings:** Exxon Mobil Corporation reported $9.1 billion in earnings for the third quarter of 2023, a $1.2 billion increase from the previous quarter.\n2. **Cash Flow from Operations:** The company generated $16 billion in cash flow from operations during the third quarter.\n3. **Dividend:** Exxon Mobil announced a 4% increase to the quarterly dividend to $0.95 per share, marking the 41st consecutive year of annual dividend increases.\n4. **Capital Expenditures (Capex):** The company's capex investments for the year-to-date are $18.6 billion, on track to finish the year at the top end of the guidance range.\n5. **Production:** Exxon Mobil's year-to-date production of 3.7 million oil-equivalent barrels per day is on track with the full-year guidance.\n6. **Shareholder Distributions:** The company delivered $8.1 billion in shareholder distributions in the third quarter, consisting of $3.7 billion in dividends and $4.4 billion in share repurchases.\n7. **Pioneer Natural Resources Acquisition:** Exxon Mobil expects to close the acquisition of Pioneer Natural Resources in early November, with synergies of approximately $1 billion before tax annually, beginning in the second year post-closing, and an average of about $2 billion per year over the next decade.\n8. **Permian Production:** The combined Permian production is expected to increase to approximately 2 million oil-equivalent barrels per day by the end of 2027.\n9. **Guyana Production:** Exxon Mobil's production in Guyana is expected to increase, with the company aiming to keep the FPSOs filled and striving to achieve maximum production.\n10. **Capex Guidance:** The company's capex guidance for the year is being updated, with the top end of the range being the new target, and the company is expected to provide further guidance in December.\n\n**Key Takeaways:**\n\n* Exxon Mobil's earnings and cash flow from operations continue to be strong, driven by the company's operational performance and structural earnings improvements.\n* The company's dividend increase and shareholder distributions demonstrate its commitment to returning value to shareholders.\n* The acquisition of Pioneer Natural Resources is expected to strengthen Exxon Mobil's position in the Permian Basin and drive synergies and growth.\n* The company's focus on high-return, advantaged projects and its efforts to", "topic": "healthcare_growth_defensive", "user_narrative": "**Name**: Alex Carter\n**Age**: 27\n**Occupation**: Healthcare Consultant\n**Marital Status**: Single\n**Children**: None\nAlex is a driven healthcare consultant who has been working in the industry for a few years. With a deep interest in healthcare, Alex is passionate about staying informed on medical innovations and the future of biotech companies. Although still in the early stages of their career, Alex is motivated by both personal and professional growth.\nTheir financial goals focus on growing wealth over time, particularly through investing in industries they understand. Alex\u2019s work has made them familiar with the unpredictable nature of the healthcare industry, but Alex maintains a strong belief in its potential for growth.\nAlex is not overly conservative and is willing to take measured risks, favoring rapidly expanding companies over those with more stable, predictable growth. Concerned about market downturns, Alex seeks stocks that can withstand economic shifts. Alex is uninterested in dividends, focusing instead on investments with strong potential for capital gains.", "label": 4}]}
|
2 |
+
{"topic": "dividend_value_defensive", "data": [{"ticker": "AMZN", "sector": "Consumer Cyclical", "industry": "Internet Retail", "business_summary": "Amazon.com, Inc. engages in the retail sale of consumer products, advertising, and subscriptions service through online and physical stores in North America and internationally. The company operates through three segments: North America, International, and Amazon Web Services (AWS). It also manufactures and sells electronic devices, including Kindle, Fire tablets, Fire TVs, Echo, Ring, Blink, and eero; and develops and produces media content. In addition, the company offers programs that enable sellers to sell their products in its stores; and programs that allow authors, independent publishers, musicians, filmmakers, Twitch streamers, skill and app developers, and others to publish and sell content. Further, it provides compute, storage, database, analytics, machine learning, and other services, as well as advertising services through programs, such as sponsored ads, display, and video advertising. Additionally, the company offers Amazon Prime, a membership program. The company's products offered through its stores include merchandise and content purchased for resale and products offered by third-party sellers. It serves consumers, sellers, developers, enterprises, content creators, advertisers, and employees. Amazon.com, Inc. was incorporated in 1994 and is headquartered in Seattle, Washington.", "beta": 1.147, "short_name": "Amazon.com, Inc.", "long_name": "Amazon.com, Inc.", "price_data": "2023 Monthly Stock Price: Jan: 103.13, Feb: 94.23, Mar: 103.29, Apr: 105.45, May: 120.58, Jun: 130.36, Jul: 133.68, Aug: 138.01, Sep: 127.12, Oct: 133.09, Nov: 146.09, Dec: 151.94", "earning_summary": "Based on the provided conference call transcript, here's a summary of the key financial metrics and insights:\n\n**Revenue and Growth**\n\n* Amazon's Q3 2023 revenue was $143.1 billion, up 11% year-over-year.\n* AWS revenue grew 12% year-over-year, with $919 million of incremental quarter-over-quarter revenue.\n* North America revenue was $87.9 billion, an increase of 11% year-over-year.\n* International revenue was $32.1 billion, an increase of 11% year-over-year, excluding foreign exchange.\n\n**Operating Income and Margin**\n\n* Amazon's Q3 2023 operating income was $11.2 billion, up 343% year-over-year.\n* North America operating income was $4.3 billion, an increase of $4.7 billion year-over-year, resulting in an operating margin of 4.9%, up 100 basis points quarter-over-quarter.\n* AWS operating income was $7 billion, an increase of $1.6 billion year-over-year, with an operating margin of 30.3%.\n\n**Free Cash Flow**\n\n* Trailing 12-month free cash flow adjusted for finance leases was $20.2 billion, an improvement of $41.7 billion year-over-year.\n* The largest driver of the improvement in free cash flow was increased operating income across all three segments.\n\n**Capital Investments**\n\n* Capital investments, defined as a combination of CapEx plus equipment finance leases, were $50 billion for the trailing 12-month period ended September 30, down from $60 billion in the comparable prior year period.\n* For the full year 2023, Amazon expects capital investments to be approximately $50 billion compared to $59 billion in 2022.\n\n**Guidance and Outlook**\n\n* Amazon is ready to make the holiday season a great one for customers, with inventory in the best position it's ever been heading into the holiday season.\n* The company continues to believe that putting customers first is the only reliable way to create lasting value for shareholders.\n\n**Key Takeaways**\n\n* Amazon's regional fulfillment network is exceeding expectations, with benefits including shorter transportation distances, faster delivery to customers, and increased purchase frequency by Prime members.\n* The company is seeing strong growth in everyday essentials and consumables, driven by faster delivery speeds.\n* AWS is seeing a stabilization of its year-over-year growth rate, with $919 million of incremental quarter-over-quarter revenue.\n* The company is optimistic about its generative AI business, with growth rates that compare", "topic": "dividend_value_defensive", "user_narrative": "**Name:** Jason Matthews\n**Age:** 30\n**Occupation:** IT Systems Administrator\n**Marital Status:** Married\n**Children:** None\nJason Matthews is a 30-year-old IT systems administrator who works for a mid-sized insurance company. He enjoys the stability of his job and appreciates the predictable nature of his day-to-day responsibilities. Jason is married, and though he and his spouse don\u2019t have children yet, they are planning to start a family in the next few years.\nWhile Jason is young, he\u2019s always been a cautious planner. He has a conservative approach to managing his finances and prefers strategies that offer steady, reliable returns over time. He\u2019s not the type to take big risks in pursuit of higher rewards. His financial goal is to create a portfolio that will generate stable income streams, so he can enjoy peace of mind knowing he\u2019s building for the long term.\nJason is drawn to investments in companies that are well-established, with a history of resilience. He tends to prioritize companies that are more likely to sustain their performance over time, regardless of market volatility. Additionally, Jason appreciates investments that offer regular payouts, as he sees this as a way to gradually enhance his financial position without needing to constantly monitor the market. Jason isn’t focused on any particular industry at this time. ", "label": 4}, {"ticker": "JPM", "sector": "Financial Services", "industry": "Banks - Diversified", "business_summary": "JPMorgan Chase & Co. operates as a financial services company worldwide. It operates through four segments: Consumer & Community Banking (CCB), Corporate & Investment Bank (CIB), Commercial Banking (CB), and Asset & Wealth Management (AWM). The CCB segment offers deposit, investment and lending products, cash management, and payments and services; mortgage origination and servicing activities; residential mortgages and home equity loans; and credit cards, auto loans, leases, and travel services to consumers and small businesses through bank branches, ATMs, and digital and telephone banking. The CIB segment provides investment banking products and services, including corporate strategy and structure advisory, and equity and debt market capital-raising services, as well as loan origination and syndication; payments; and cash and derivative instruments, risk management solutions, prime brokerage, and research. This segment also offers securities services, including custody, fund accounting and administration, and securities lending products for asset managers, insurance companies, and public and private investment funds. The CB segment provides financial solutions, including lending, payments, investment banking, and asset management to small and midsized companies, local governments, nonprofit clients, and large corporations, as well as investors, developers, and owners of multifamily, office, retail, industrial, and affordable housing properties. The AWM segment offers multi-asset investment management solutions in equities, fixed income, alternatives, and money market funds to institutional clients and retail investors; and retirement products and services, brokerage, custody, estate planning, lending, deposits, and investment management products to high net worth clients. JPMorgan Chase & Co. was founded in 1799 and is headquartered in New York, New York.", "beta": 1.102, "short_name": "JP Morgan Chase & Co.", "long_name": "JPMorgan Chase & Co.", "price_data": "2023 Monthly Stock Price: Jan: 134.54, Feb: 137.80, Mar: 125.26, Apr: 133.93, May: 131.48, Jun: 140.90, Jul: 154.08, Aug: 142.74, Sep: 141.46, Oct: 136.65, Nov: 153.37, Dec: 167.15", "earning_summary": "Based on the provided transcript, here's a detailed summary of the key financial metrics discussed during the Q3 2023 earnings call of JPMorgan Chase & Co.:\n\n**Key Financial Metrics:**\n\n1. **Net Income:** $13.2 billion\n2. **Earnings Per Share (EPS):** $4.33\n3. **Revenue:** $40.7 billion\n4. **Return on Tangible Common Equity (ROTC):** 22%\n5. **Net Interest Income (NII):** $88.5 billion (2023 estimate)\n6. **Net Interest Income ex-Markets:** $89 billion (2023 estimate)\n7. **Adjusted Expense:** $84 billion (2023 estimate)\n8. **Credit Costs:** $1.4 billion\n9. **Net Charge-offs:** $720 million (year-over-year increase)\n10. **Net Reserve Build:** $49 million\n11. **Common Equity Tier 1 (CET1) Ratio:** 14.3% (up 50 basis points from the prior quarter)\n12. **Return on Equity (ROE):** 17% (natural return profile)\n13. **Return on Common Equity (ROCE):** 22% (ROTCE)\n14. **Net Investment Securities Losses:** $669 million\n15. **Firmwide Legal Expense:** $665 million\n\n**Business Segment Performance:**\n\n1. **Consumer & Community Banking (CCB):** Net income of $5.3 billion, revenue of $17 billion (up 19% year-over-year)\n2. **Banking & Wealth Management:** Revenue up 30% year-over-year, driven by higher NII on higher rates\n3. **Card Services & Auto:** Revenue up 7% year-over-year, driven by higher Card Services NII on higher revolving balances\n4. **Commercial Banking:** Net income of $1.7 billion, revenue of $3.7 billion (up 20% year-over-year)\n5. **Investment Banking & Markets:** Revenue of $11.7 billion, down 3% year-over-year\n6. **Asset & Wealth Management (AWM):** Net income of $1.1 billion, pretax margin of 31%\n7. **Corporate:** Net income of $911 million, revenue of $1.5 billion (up $1.8 billion year-over-year)", "topic": "dividend_value_defensive", "user_narrative": "**Name:** Jason Matthews\n**Age:** 30\n**Occupation:** IT Systems Administrator\n**Marital Status:** Married\n**Children:** None\nJason Matthews is a 30-year-old IT systems administrator who works for a mid-sized insurance company. He enjoys the stability of his job and appreciates the predictable nature of his day-to-day responsibilities. Jason is married, and though he and his spouse don\u2019t have children yet, they are planning to start a family in the next few years.\nWhile Jason is young, he\u2019s always been a cautious planner. He has a conservative approach to managing his finances and prefers strategies that offer steady, reliable returns over time. He\u2019s not the type to take big risks in pursuit of higher rewards. His financial goal is to create a portfolio that will generate stable income streams, so he can enjoy peace of mind knowing he\u2019s building for the long term.\nJason is drawn to investments in companies that are well-established, with a history of resilience. He tends to prioritize companies that are more likely to sustain their performance over time, regardless of market volatility. Additionally, Jason appreciates investments that offer regular payouts, as he sees this as a way to gradually enhance his financial position without needing to constantly monitor the market. Jason isn’t focused on any particular industry at this time. ", "label": 3}, {"ticker": "KO", "sector": "Consumer Defensive", "industry": "Beverages - Non-Alcoholic", "business_summary": "The Coca-Cola Company, a beverage company, manufactures, markets, and sells various nonalcoholic beverages worldwide. The company provides sparkling soft drinks, sparkling flavors; water, sports, coffee, and tea; juice, value-added dairy, and plant-based beverages; and other beverages. It also offers beverage concentrates and syrups, as well as fountain syrups to fountain retailers, such as restaurants and convenience stores. The company sells its products under the Coca-Cola, Diet Coke/Coca-Cola Light, Coca-Cola Zero Sugar, caffeine free Diet Coke, Cherry Coke, Fanta Orange, Fanta Zero Orange, Fanta Zero Sugar, Fanta Apple, Sprite, Sprite Zero Sugar, Simply Orange, Simply Apple, Simply Grapefruit, Fresca, Schweppes, Thums Up, Aquarius, Ayataka, BODYARMOR, Ciel, Costa, Dasani, dogadan, FUZE TEA, Georgia, glac\u00e9au smartwater, glac\u00e9au vitaminwater, Gold Peak, Ice Dew, I LOHAS, Powerade, Topo Chico, AdeS, Del Valle, fairlife, innocent, Minute Maid, and Minute Maid Pulpy brands. It operates through a network of independent bottling partners, distributors, wholesalers, and retailers, as well as through bottling and distribution operators. The company was founded in 1886 and is headquartered in Atlanta, Georgia.", "beta": 0.608, "short_name": "Coca-Cola Company ", "long_name": "The Coca-Cola Company", "price_data": "2023 Monthly Stock Price: Jan: 58.52, Feb: 56.79, Mar: 59.65, Apr: 61.69, May: 57.37, Jun: 58.35, Jul: 60.01, Aug: 57.97, Sep: 54.67, Oct: 55.17, Nov: 57.53, Dec: 58.01", "earning_summary": "Based on the provided conference call transcript, here's a detailed summary of the key financial metrics discussed:\n\n**Revenue Growth:**\n\n* The company delivered 11% organic revenue growth in Q3 2023.\n* The revenue growth was driven by positive volume growth, pricing actions, and carryover pricing from the previous year.\n* The company expects to deliver 10% to 11% organic revenue growth for the full year 2023.\n\n**Volume Growth:**\n\n* The company delivered 2% unit case growth in Q3 2023.\n* The company expects to deliver positive volume growth for the full year 2023.\n\n**Price/Mix Growth:**\n\n* The company delivered 9% price/mix growth in Q3 2023, driven by pricing actions across operating segments and the impact of hyperinflationary markets.\n* The company expects price/mix growth to moderate in the fourth quarter as they cycle pricing initiatives from the previous year.\n\n**Gross Margin:**\n\n* The company's comparable gross margin expanded by approximately 130 basis points in Q3 2023, driven by underlying expansion and a slight benefit from bottler refranchising, partially offset by the impact of currency headwinds.\n\n**Operating Margin:**\n\n* The company's comparable operating margin expanded by approximately 20 basis points in Q3 2023, driven by strong top-line growth and the impact of refranchising bottling operations, partially offset by an increase in marketing investments and currency headwinds.\n\n**EPS Growth:**\n\n* The company delivered 7% year-over-year comparable EPS growth in Q3 2023, despite higher-than-expected 4% currency headwinds.\n* The company expects to deliver 13% to 14% comparable currency-neutral earnings per share growth for the full year 2023.\n\n**Free Cash Flow:**\n\n* The company generated approximately $7.9 billion in free cash flow year-to-date.\n* The company expects to generate approximately $9.5 billion in free cash flow for the full year 2023.\n\n**Balance Sheet:**\n\n* The company's net debt leverage is 1.5x EBITDA, below its target range of 2 to 2.5x.\n* The company has a strong balance sheet and expects to have increased flexibility to continue to reinvest in the business and return capital to shareholders.\n\n**Guidance:**\n\n* The company raised its 2023 guidance to 10% to 11% organic revenue growth and 13% to", "topic": "dividend_value_defensive", "user_narrative": "**Name:** Jason Matthews\n**Age:** 30\n**Occupation:** IT Systems Administrator\n**Marital Status:** Married\n**Children:** None\nJason Matthews is a 30-year-old IT systems administrator who works for a mid-sized insurance company. He enjoys the stability of his job and appreciates the predictable nature of his day-to-day responsibilities. Jason is married, and though he and his spouse don\u2019t have children yet, they are planning to start a family in the next few years.\nWhile Jason is young, he\u2019s always been a cautious planner. He has a conservative approach to managing his finances and prefers strategies that offer steady, reliable returns over time. He\u2019s not the type to take big risks in pursuit of higher rewards. His financial goal is to create a portfolio that will generate stable income streams, so he can enjoy peace of mind knowing he\u2019s building for the long term.\nJason is drawn to investments in companies that are well-established, with a history of resilience. He tends to prioritize companies that are more likely to sustain their performance over time, regardless of market volatility. Additionally, Jason appreciates investments that offer regular payouts, as he sees this as a way to gradually enhance his financial position without needing to constantly monitor the market. Jason isn’t focused on any particular industry at this time. ", "label": 1}, {"ticker": "WMT", "sector": "Consumer Defensive", "industry": "Discount Stores", "business_summary": "Walmart Inc. engages in the operation of retail, wholesale, other units, and eCommerce worldwide. The company operates through three segments: Walmart U.S., Walmart International, and Sam's Club. It operates supercenters, supermarkets, hypermarkets, warehouse clubs, cash and carry stores, and discount stores under Walmart and Walmart Neighborhood Market brands; membership-only warehouse clubs; ecommerce websites, such as walmart.com.mx, walmart.ca, flipkart.com, PhonePe and other sites; and mobile commerce applications. The company offers grocery and consumables, including dairy, meat, bakery, deli, produce, dry, chilled or frozen packaged foods, alcoholic and nonalcoholic beverages, floral, snack foods, candy, other grocery items, health and beauty aids, paper goods, laundry and home care, baby care, pet supplies, and other consumable items; fuel, tobacco and other categories. It is also involved in the provision of health and wellness products covering pharmacy, optical and hearing services, and over-the-counter drugs and other medical products; and home and apparel including home improvement, outdoor living, gardening, furniture, apparel, jewelry, tools and power equipment, housewares, toys, seasonal items, mattresses and tire and battery centers. In addition, the company offers consumer electronics and accessories, software, video games, office supplies, appliances, and third-party gift cards. Further, it operates digital payment platforms; and offers financial services and related products, including money transfers, bill payments, money orders, check cashing, prepaid access, co-branded credit cards, installment lending, and earned wage access. Additionally, the company markets lines of merchandise under private brands, including Allswell, Athletic Works, Equate, and Free Assembly. The company was formerly known as Wal-Mart Stores, Inc. and changed its name to Walmart Inc. in February 2018. Walmart Inc. was founded in 1945 and is based in Bentonville, Arkansas.", "beta": 0.516, "short_name": "Walmart Inc.", "long_name": "Walmart Inc.", "price_data": "2023 Monthly Stock Price: Jan: 46.78, Feb: 46.21, Mar: 48.14, Apr: 49.29, May: 48.13, Jun: 51.51, Jul: 52.39, Aug: 53.48, Sep: 52.60, Oct: 53.74, Nov: 51.21, Dec: 52.04", "earning_summary": "Here's a detailed summary of the key financial metrics discussed during the Walmart Q3 2024 earnings conference call:\n\n**Revenue and Sales Growth**\n\n* Total revenue grew 4.4% in constant currency, or $7 billion, year-over-year.\n* Walmart U.S. comp sales increased 4.9%, while Sam's Club U.S. comp sales grew 3.8% (excluding fuel).\n* International sales grew 5.4% in constant currency, with Walmex sales up 9% and China sales up 25%.\n* E-commerce sales grew 24% in Walmart U.S., 16% in Sam's Club U.S., and 15% globally.\n\n**Gross Margin**\n\n* Gross margin expanded 32 basis points, driven by the timing shift of Big Billion Days in India and lapping last year's LIFO charge at Sam's Club U.S.\n* Walmart U.S. gross margin increased 5 basis points, reflecting lower markdowns and supply chain costs.\n\n**Operating Income and Expenses**\n\n* Adjusted operating income grew 3%, including a 270 basis point currency tailwind.\n* SG&A expenses deleveraged 37 basis points on an adjusted basis, impacted by higher year-over-year wage-related costs and store remodel costs.\n* Legal expenses increased, primarily due to a $70 million to $75 million accrual related to prior periods.\n\n**Return on Investment (ROI)**\n\n* ROI improved 130 basis points to 14.1% over the last 12 months, driven by lapping last year's Q3 charge related to the opioid legal settlement framework and productivity initiatives.\n* The company expects ROI to increase over the coming years.\n\n**Guidance**\n\n* The company raised its full-year sales guidance to 5% to 5.5% from 4% to 4.5% previously.\n* Operating income guidance remains at 7% to 7.5% growth.\n* EPS guidance was raised to $6.40 to $6.48.\n* The company expects merchandise mix pressure to continue in Q4, with grocery and health and wellness sales rates outpacing general merchandise.\n\n**E-commerce and Marketplace Growth**\n\n* E-commerce sales grew 24% in Walmart U.S., 16% in Sam's Club U.S., and 15% globally.\n* Marketplace sales grew 16% in Walmex, 16% in Canada, and 38% in China.\n* The company has more than doubled the number of items available to", "topic": "dividend_value_defensive", "user_narrative": "**Name:** Jason Matthews\n**Age:** 30\n**Occupation:** IT Systems Administrator\n**Marital Status:** Married\n**Children:** None\nJason Matthews is a 30-year-old IT systems administrator who works for a mid-sized insurance company. He enjoys the stability of his job and appreciates the predictable nature of his day-to-day responsibilities. Jason is married, and though he and his spouse don\u2019t have children yet, they are planning to start a family in the next few years.\nWhile Jason is young, he\u2019s always been a cautious planner. He has a conservative approach to managing his finances and prefers strategies that offer steady, reliable returns over time. He\u2019s not the type to take big risks in pursuit of higher rewards. His financial goal is to create a portfolio that will generate stable income streams, so he can enjoy peace of mind knowing he\u2019s building for the long term.\nJason is drawn to investments in companies that are well-established, with a history of resilience. He tends to prioritize companies that are more likely to sustain their performance over time, regardless of market volatility. Additionally, Jason appreciates investments that offer regular payouts, as he sees this as a way to gradually enhance his financial position without needing to constantly monitor the market. Jason isn’t focused on any particular industry at this time. ", "label": 2}]}
|
3 |
+
{"topic": "nondividend_value_cyclical", "data": [{"ticker": "AAPL", "sector": "Technology", "industry": "Consumer Electronics", "business_summary": "Apple Inc. designs, manufactures, and markets smartphones, personal computers, tablets, wearables, and accessories worldwide. The company offers iPhone, a line of smartphones; Mac, a line of personal computers; iPad, a line of multi-purpose tablets; and wearables, home, and accessories comprising AirPods, Apple TV, Apple Watch, Beats products, and HomePod. It also provides AppleCare support and cloud services; and operates various platforms, including the App Store that allow customers to discover and download applications and digital content, such as books, music, video, games, and podcasts. In addition, the company offers various services, such as Apple Arcade, a game subscription service; Apple Fitness+, a personalized fitness service; Apple Music, which offers users a curated listening experience with on-demand radio stations; Apple News+, a subscription news and magazine service; Apple TV+, which offers exclusive original content; Apple Card, a co-branded credit card; and Apple Pay, a cashless payment service, as well as licenses its intellectual property. The company serves consumers, and small and mid-sized businesses; and the education, enterprise, and government markets. It distributes third-party applications for its products through the App Store. The company also sells its products through its retail and online stores, and direct sales force; and third-party cellular network carriers, wholesalers, retailers, and resellers. Apple Inc. was founded in 1976 and is headquartered in Cupertino, California.", "beta": 1.239, "short_name": "Apple Inc.", "long_name": "Apple Inc.", "price_data": "2023 Monthly Stock Price: Jan: 142.95, Feb: 146.26, Mar: 163.61, Apr: 168.36, May: 176.11, Jun: 192.72, Jul: 195.19, Aug: 186.91, Sep: 170.34, Oct: 169.90, Nov: 189.23, Dec: 191.80", "earning_summary": "Based on the provided conference call transcript, here's a detailed summary of the key financial metrics discussed:\n\n1. **Revenue**: Apple reported revenue of $89.5 billion for the September quarter, a decrease of less than 1% from the same period last year. On a constant-currency basis, revenue grew year-over-year in total and in each geographic segment.\n2. **iPhone Revenue**: iPhone revenue came in at $43.8 billion, a 3% increase from the same period last year and a new September quarter record. The company set an all-time revenue record in India and September quarter records in several countries, including Brazil, Canada, France, Indonesia, Mexico, the Philippines, Saudi Arabia, Turkey, the UAE, Vietnam, and more.\n3. **Services Revenue**: Services revenue set an all-time record of $22.3 billion, a 16% year-over-year increase. The company achieved all-time revenue records across App Store, advertising, AppleCare, iCloud, payment services, and video, as well as a September quarter revenue record in Apple Music.\n4. **Gross Margin**: Company gross margin set a September quarter record at 45.2%, up 70 basis points sequentially, driven by leverage and favorable mix, partially offset by foreign exchange. Products gross margin was 36.6%, up 120 basis points sequentially, also driven by leverage and mix, partially offset by foreign exchange. Services gross margin was 70.9%, up 40 basis points from last quarter due to a different mix.\n5. **Operating Expenses**: Operating expenses of $13.5 billion were at the low end of the guidance range, up 2% year-over-year.\n6. **Net Income**: Net income was $23 billion, and diluted earnings per share was $1.46, up 13% versus last year and a September quarter record.\n7. **Operating Cash Flow**: Operating cash flow was strong at $21.6 billion.\n8. **Capital Return Program**: The company returned nearly $25 billion to shareholders, including $3.8 billion in dividends and equivalents and $15.5 billion through open market repurchases of 85 million Apple shares.\n9. **Guidance**: For the December quarter, the company expects:\n\t* Revenue to be similar to last year, despite having one less week this year.\n\t* iPhone revenue to grow year-over-year on an absolute basis.\n\t* Mac year-over-year performance to significantly accelerate from", "topic": "nondividend_value_cyclical", "user_narrative": "**Name:** Malik Johnson\n**Age:** 25\n**Occupation:** Software Developer\n**Marital Status:** Single\n**Children:** None\nMalik Johnson is a 25-year-old software developer working at a growing tech startup. His background in engineering has given him a methodical approach to problem-solving, which he also applies to his personal finances. Being single with no children allows him the flexibility to focus on building his career and making strategic financial decisions aligned with his long-term goals.\nAt this stage, he isn\u2019t particularly interested in receiving dividends from his investments. Instead, his focus is on identifying undervalued companies with strong long-term potential. Malik stays informed about market trends and enjoys researching sectors that perform well during periods of economic growth. He prefers to invest in businesses well-positioned to take advantage of economic cycles, even if that means accepting some short-term volatility. His goal is to build wealth by capitalizing on companies that will benefit from economic upturns, rather than chasing short-term gains. He isn’t focused on any particular industry at this time.", "label": 4}, {"ticker": "PG", "sector": "Consumer Defensive", "industry": "Household & Personal Products", "business_summary": "The Procter & Gamble Company engages in the provision of branded consumer packaged goods worldwide. The company operates through five segments: Beauty; Grooming; Health Care; Fabric & Home Care; and Baby, Feminine & Family Care. The Beauty segment offers conditioners, shampoos, styling aids, and treatments under the Head & Shoulders, Herbal Essences, Pantene, and Rejoice brands; and antiperspirants and deodorants, personal cleansing, and skin care products under the Olay, Old Spice, Safeguard, Secret, SK-II, and Native brands. The Grooming segment provides blades and razors, shave products, appliances, and other grooming products under the Braun, Gillette, and Venus brand names. The Health Care segment offers toothbrushes, toothpastes, and other oral care products under the Crest and Oral-B brand names; and gastrointestinal, pain relief, rapid diagnostics, respiratory, vitamins/minerals/supplements, and other personal health care products under Metamucil, Neurobion, Pepto-Bismol, and Vicks brands. The Fabric & Home Care segment provides fabric enhancers, laundry additives, and laundry detergents under the Ariel, Downy, Gain, and Tide brands; and air care, dish care, P&G professional, and surface care products under the Cascade, Dawn, Fairy, Febreze, Mr. Clean, and Swiffer brands. The Baby, Feminine & Family Care segment offers baby wipes, and taped diapers and pants under the Luvs and Pampers brands; adult incontinence and feminine care products under the Always, Always Discreet, and Tampax brands; and paper towels, tissues, and toilet papers under the Bounty, Charmin, and Puffs brands. It sells its products primarily through mass merchandisers, e-commerce, grocery stores, membership club stores, drug stores, department stores, distributors, wholesalers, specialty beauty stores, high-frequency stores, pharmacies, electronics stores, and professional channels, as well as directly to consumers. The company was founded in 1837 and is headquartered in Cincinnati, Ohio.", "beta": 0.407, "short_name": "Procter & Gamble Company ", "long_name": "The Procter & Gamble Company", "price_data": "2023 Monthly Stock Price: Jan: 137.13, Feb: 132.49, Mar: 143.21, Apr: 151.56, May: 138.11, Jun: 147.06, Jul: 152.44, Aug: 150.53, Sep: 142.26, Oct: 147.25, Nov: 150.67, Dec: 143.82", "earning_summary": "**Summary of Key Financial Metrics:**\n\n1. **Organic Sales Growth:** 7% in Q1 2024, with a guidance range of 4% to 5% for the fiscal year.\n2. **Pricing Contribution:** 7 points to sales growth in Q1 2024, expected to decrease by 3 to 4 points in Q2 and Q3.\n3. **Volume Growth:** Modest volume growth outside of China, with a decline of 6% in Greater China.\n4. **Core Earnings Per Share (EPS):** $1.83 in Q1 2024, up 17% year-over-year, with a guidance range of 6% to 9% growth for the fiscal year.\n5. **Core Operating Margin:** Increased by 240 basis points in Q1 2024, with a currency-neutral increase of 340 basis points.\n6. **Adjusted Free Cash Flow Productivity:** 97% in Q1 2024.\n7. **Cash Return to Share Owners:** $3.8 billion in Q1 2024, with a plan to return $14 billion to $15 billion of cash to shareholders this fiscal year.\n8. **Commodity Costs:** Expected to be a tailwind of around $800 million after tax in fiscal '24, with a headwind of approximately $1 billion after tax due to foreign exchange rates.\n9. **Foreign Exchange (FX) Impact:** A headwind of approximately $1 billion after tax, with a 7-point EPS impact from FX.\n10. **Guidance Ranges:** Organic sales growth of 4% to 5%, core EPS growth of 6% to 9%, cash productivity of 90%, and cash return to share owners of $14 billion to $15 billion.\n\n**Key Takeaways:**\n\n* Procter & Gamble's Q1 2024 results were strong, with 7% organic sales growth and 17% core EPS growth.\n* The company expects a normalization in underlying market growth rate to around 4% for the fiscal year.\n* Pricing will start to lap in Q2, with a 3 to 4 point decrease in price contribution.\n* Volume growth is expected to progress sequentially, with a focus on driving wholesale penetration and creating volume growth.\n* The company is committed to investing in superiority, productivity, and innovation to drive growth and value creation.\n* Procter &", "topic": "nondividend_value_cyclical", "user_narrative": "**Name:** Malik Johnson\n**Age:** 25\n**Occupation:** Software Developer\n**Marital Status:** Single\n**Children:** None\nMalik Johnson is a 25-year-old software developer working at a growing tech startup. His background in engineering has given him a methodical approach to problem-solving, which he also applies to his personal finances. Being single with no children allows him the flexibility to focus on building his career and making strategic financial decisions aligned with his long-term goals.\nAt this stage, he isn\u2019t particularly interested in receiving dividends from his investments. Instead, his focus is on identifying undervalued companies with strong long-term potential. Malik stays informed about market trends and enjoys researching sectors that perform well during periods of economic growth. He prefers to invest in businesses well-positioned to take advantage of economic cycles, even if that means accepting some short-term volatility. His goal is to build wealth by capitalizing on companies that will benefit from economic upturns, rather than chasing short-term gains. He isn’t focused on any particular industry at this time.", "label": 3}, {"ticker": "TSLA", "sector": "Consumer Cyclical", "industry": "Auto Manufacturers", "business_summary": "Tesla, Inc. designs, develops, manufactures, leases, and sells electric vehicles, and energy generation and storage systems in the United States, China, and internationally. The company operates in two segments, Automotive, and Energy Generation and Storage. The Automotive segment offers electric vehicles, as well as sells automotive regulatory credits; and non-warranty after-sales vehicle, used vehicles, body shop and parts, supercharging, retail merchandise, and vehicle insurance services. This segment also provides sedans and sport utility vehicles through direct and used vehicle sales, a network of Tesla Superchargers, and in-app upgrades; purchase financing and leasing services; services for electric vehicles through its company-owned service locations and Tesla mobile service technicians; and vehicle limited warranties and extended service plans. The Energy Generation and Storage segment engages in the design, manufacture, installation, sale, and leasing of solar energy generation and energy storage products, and related services to residential, commercial, and industrial customers and utilities through its website, stores, and galleries, as well as through a network of channel partners; and provision of service and repairs to its energy product customers, including under warranty, as well as various financing options to its solar customers. The company was formerly known as Tesla Motors, Inc. and changed its name to Tesla, Inc. in February 2017. Tesla, Inc. was incorporated in 2003 and is headquartered in Austin, Texas.", "beta": 2.297, "short_name": "Tesla, Inc.", "long_name": "Tesla, Inc.", "price_data": "2023 Monthly Stock Price: Jan: 173.22, Feb: 205.71, Mar: 207.46, Apr: 164.31, May: 203.93, Jun: 261.77, Jul: 267.43, Aug: 258.08, Sep: 250.22, Oct: 200.84, Nov: 240.08, Dec: 248.48", "earning_summary": "**Summary Report: Tesla, Inc. Q3 2023 Earnings Conference Call**\n\n**Key Financial Metrics:**\n\n1. **Vehicle Deliveries:** Tesla expects to deliver 1.8 million vehicles in 2023, with a growth rate of 28% in 2024, assuming 2.3 million deliveries.\n2. **Cost per Vehicle:** The cost per vehicle decreased to approximately $37,500 in Q3 2023, with a sequential decrease in material cost and freight.\n3. **Gross Margin:** The company aims to maintain or exceed the trend of cost reduction efforts in 2024, with a focus on engineering, factory operations, and supply chain improvements.\n4. **Energy Storage:** The energy division is becoming the company's highest-margin business, with 4 gigawatt hours of energy storage products deployed in Q3 2023.\n5. **Cybertruck:** The company expects to deliver around 250,000 Cybertrucks in 2025, with a significant ramp-up in production, but acknowledges that reaching volume production and cash flow positivity will take time.\n6. **4680 Cell:** Production in Texas increased 40% quarter-over-quarter, with a focus on quality and scrap reduction.\n7. **Gigafactory Mexico:** The company is laying the groundwork for construction, but is cautious about the high-interest rate environment and its impact on car affordability.\n8. **Robotaxi:** The company is making progress with autonomy, with the end-to-end AI system driving around Austin with no interventions.\n9. **FSD Pricing:** The company plans to make FSD more affordable as it improves, with a temporary low price point, and expects to increase the price as the technology improves.\n10. **Gross Margin Evolution:** The company expects to see a sequential benefit from production ramping at Berlin and Austin, but acknowledges that there will be headwinds from the ramp-up of Cybertruck production.\n\n**Key Takeaways:**\n\n1. Tesla is focused on reducing costs, maximizing delivery volumes, and investing in the future, particularly in AI and next-generation platforms.\n2. The company is cautious about the high-interest rate environment and its impact on car affordability.\n3. Tesla is making progress with autonomy, with the end-to-end AI system driving around Austin with no interventions.\n4. The company plans to make FSD more affordable as it improves, with a temporary low price point.\n5. Tesla is focused", "topic": "nondividend_value_cyclical", "user_narrative": "**Name:** Malik Johnson\n**Age:** 25\n**Occupation:** Software Developer\n**Marital Status:** Single\n**Children:** None\nMalik Johnson is a 25-year-old software developer working at a growing tech startup. His background in engineering has given him a methodical approach to problem-solving, which he also applies to his personal finances. Being single with no children allows him the flexibility to focus on building his career and making strategic financial decisions aligned with his long-term goals.\nAt this stage, he isn\u2019t particularly interested in receiving dividends from his investments. Instead, his focus is on identifying undervalued companies with strong long-term potential. Malik stays informed about market trends and enjoys researching sectors that perform well during periods of economic growth. He prefers to invest in businesses well-positioned to take advantage of economic cycles, even if that means accepting some short-term volatility. His goal is to build wealth by capitalizing on companies that will benefit from economic upturns, rather than chasing short-term gains. He isn’t focused on any particular industry at this time.", "label": 2}, {"ticker": "BAC", "sector": "Financial Services", "industry": "Banks - Diversified", "business_summary": "Bank of America Corporation, through its subsidiaries, provides banking and financial products and services for individual consumers, small and middle-market businesses, institutional investors, large corporations, and governments worldwide. It operates in four segments: Consumer Banking, Global Wealth & Investment Management (GWIM), Global Banking, and Global Markets. The Consumer Banking segment offers traditional and money market savings accounts, certificates of deposit and IRAs, non-interest and interest-bearing checking accounts, and investment accounts and products; credit and debit cards; residential mortgages, and home equity loans; and direct and indirect loans, such as automotive, recreational vehicle, and consumer personal loans. The GWIM segment provides investment management, brokerage, banking, and trust and retirement products and services; wealth management solutions; and customized solutions, including specialty asset management services. The Global Banking segment offers lending products and services, including commercial loans, leases, commitment facilities, trade finance, and commercial real estate and asset-based lending; treasury solutions, such as treasury management, foreign exchange, short-term investing options, and merchant services; working capital management solutions; debt and equity underwriting and distribution, and merger-related and other advisory services; and fixed-income and equity research, and certain market-based services. The Global Markets segment provides market-making, financing, securities clearing, settlement, and custody services; securities and derivative products; and risk management products using interest rate, equity, credit, currency and commodity derivatives, foreign exchange, fixed-income, and mortgage-related products. Bank of America Corporation was founded in 1784 and is based in Charlotte, North Carolina.", "beta": 1.338, "short_name": "Bank of America Corporation", "long_name": "Bank of America Corporation", "price_data": "2023 Monthly Stock Price: Jan: 33.96, Feb: 32.83, Mar: 27.55, Apr: 28.21, May: 26.77, Jun: 27.86, Jul: 31.08, Aug: 28.07, Sep: 26.81, Oct: 25.79, Nov: 30.09, Dec: 33.23", "earning_summary": "Based on the provided transcript, here's a summary of the key financial metrics discussed during the Bank of America Corporation's Q3 2023 earnings call:\n\n1. **Net Income**: $7.8 billion, a 10% increase from the year-ago quarter.\n2. **Return on Tangible Common Equity (ROTC)**: Over 15%, indicating strong profitability.\n3. **Net Interest Income (NII)**: $14.5 billion, a 4% increase from the year-ago quarter and above the guided range of $14.2 billion to $14.3 billion.\n4. **Expense**: $15.8 billion, a decline of $200 million from the previous quarter, and expected to decline further to $15.6 billion in the fourth quarter.\n5. **Provision Expense**: $1.2 billion, reflecting a macroeconomic outlook with an unemployment rate rising to over 5% in 2024.\n6. **Credit Quality Metrics**: Consumer delinquencies remain below historical averages, and commercial net charge-offs declined from the previous quarter.\n7. **Asset Sensitivity**: A 100 basis point parallel shift in the forward yield curve is expected to result in a $3.1 billion NII benefit over the next 12 months.\n8. **Capital**: The bank has more than $30 billion of excess capital, and the proposed capital rules would require an additional $195 billion of total capital, which the bank believes it can meet.\n9. **Return on Assets (ROA)**: 1%, indicating a relatively low return on assets.\n10. **Dividend**: A 9% dividend increase, with $2.9 billion returned to shareholders in the quarter.\n11. **Tangible Book Value per Share**: Up 12% year-over-year.\n12. **CET1 Ratio**: Improved to 11.9%, well above the current 9.5% requirement.\n13. **Supplemental Leverage Ratio**: 62%, well above the minimum requirement of 5%.\n14. **LCR Ratios**: Remain well above minimums for BAC metrics and stronger at the bank level.\n15. **Loan Growth**: Slowed in the quarter due to a decline in demand for commercial borrowing and lower revolver utilization.\n16. **Deposit Growth**: Average deposits are up 33% from pre-pandemic levels, with consumer deposits up 36% and consumer checking up 45%.\n17. **Ex", "topic": "nondividend_value_cyclical", "user_narrative": "**Name:** Malik Johnson\n**Age:** 25\n**Occupation:** Software Developer\n**Marital Status:** Single\n**Children:** None\nMalik Johnson is a 25-year-old software developer working at a growing tech startup. His background in engineering has given him a methodical approach to problem-solving, which he also applies to his personal finances. Being single with no children allows him the flexibility to focus on building his career and making strategic financial decisions aligned with his long-term goals.\nAt this stage, he isn\u2019t particularly interested in receiving dividends from his investments. Instead, his focus is on identifying undervalued companies with strong long-term potential. Malik stays informed about market trends and enjoys researching sectors that perform well during periods of economic growth. He prefers to invest in businesses well-positioned to take advantage of economic cycles, even if that means accepting some short-term volatility. His goal is to build wealth by capitalizing on companies that will benefit from economic upturns, rather than chasing short-term gains. He isn’t focused on any particular industry at this time.", "label": 1}]}
|
data/single_stock_data/single_stock_demo.jsonl
ADDED
The diff for this file is too large to render.
See raw diff
|
|
requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
transformers==4.44.1
|
2 |
+
together==1.3.0
|
3 |
+
markdown==3.4.1
|