TTsamurai commited on
Commit
edf52d9
·
0 Parent(s):

first commit

Browse files
Files changed (49) hide show
  1. .DS_Store +0 -0
  2. .gitattributes +35 -0
  3. .gitignore +164 -0
  4. .python-version +1 -0
  5. README.md +13 -0
  6. _static/html/evaluation_instruction.html +21 -0
  7. _static/html/final_evaluation.html +36 -0
  8. _static/html/general_instruction.html +27 -0
  9. _static/html/instruction_page.html +55 -0
  10. _static/html/system_instruction_preference_elicitation.html +21 -0
  11. _static/html/user_narrative.html +8 -0
  12. _static/txt/general_instruction_button.txt +1 -0
  13. _static/txt/general_instruction_task.txt +1 -0
  14. _static/txt/personality_ext.txt +1 -0
  15. _static/txt/personality_int.txt +1 -0
  16. _static/txt/system_instruction_non_personalization.txt +1 -0
  17. _static/txt/system_instruction_personality.txt +1 -0
  18. _static/txt/system_instruction_personalization.txt +1 -0
  19. _static/txt/system_instruction_preference_elicitation.txt +5 -0
  20. _static/txt/system_instruction_preference_elicitation_personality.txt +5 -0
  21. _static/txt/system_summarization_user_preference_elicitation.txt +1 -0
  22. app.py +1392 -0
  23. components/chat_conversation.py +173 -0
  24. components/constant.py +19 -0
  25. components/induce_personality.py +34 -0
  26. components/prompt.py +10 -0
  27. components/query_rewriting.py +60 -0
  28. components/rag_components.py +190 -0
  29. components/rewrite_passages.py +94 -0
  30. data/single_stock_data/experiment_processed_data.jsonl +3 -0
  31. data/single_stock_data/single_stock_demo.jsonl +0 -0
  32. dum.txt +352 -0
  33. experiments/experiment_with_api_without_personalization.py +665 -0
  34. experiments/personality_simulation.py +60 -0
  35. experiments/separate_preference_elicitation_and_interaction.py +851 -0
  36. experiments/single_stock_experiment.py +574 -0
  37. requirements.txt +3 -0
  38. user_feedback/interaction_3a48b93b-0de7-4e2a-b779-8f1f0c27af24_first.json +2 -0
  39. user_feedback/interaction_462c2c52-b14f-44f1-8030-6f06d5a7d925_first.json +2 -0
  40. user_feedback/interaction_7017b92d-6932-4d3a-b189-1267c2386995_first.json +2 -0
  41. user_feedback/interaction_7e25ac2e-3849-4817-9ae3-e883bca2fb10_first.json +4 -0
  42. user_feedback/interaction_8611c342-840f-4529-b9ff-d1dabb754ded_first.json +6 -0
  43. user_feedback/interaction_8e1566fb-6de9-46da-a3de-c6a580fb5b83_first.json +2 -0
  44. user_feedback/interaction_abfb0425-8dff-4b63-91d0-372276758a8f_first.json +4 -0
  45. user_feedback/interaction_b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea_first.json +16 -0
  46. user_feedback/interaction_d34ca619-e30a-4267-9538-cc8f99aff079.json +4 -0
  47. user_feedback/interaction_e7f30c05-4668-4b35-a706-ba27b7c0a0a9_first.json +2 -0
  48. user_feedback/summarization_8611c342-840f-4529-b9ff-d1dabb754ded_first.json +1 -0
  49. user_feedback/summarization_d34ca619-e30a-4267-9538-cc8f99aff079.json +1 -0
.DS_Store ADDED
Binary file (6.15 kB). View file
 
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ log/
2
+ old_user_feedback/
3
+ # Byte-compiled / optimized / DLL files
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ build/
14
+ develop-eggs/
15
+ dist/
16
+ downloads/
17
+ eggs/
18
+ .eggs/
19
+ lib/
20
+ lib64/
21
+ parts/
22
+ sdist/
23
+ var/
24
+ wheels/
25
+ share/python-wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+ MANIFEST
30
+
31
+ # PyInstaller
32
+ # Usually these files are written by a python script from a template
33
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
34
+ *.manifest
35
+ *.spec
36
+
37
+ # Installer logs
38
+ pip-log.txt
39
+ pip-delete-this-directory.txt
40
+
41
+ # Unit test / coverage reports
42
+ htmlcov/
43
+ .tox/
44
+ .nox/
45
+ .coverage
46
+ .coverage.*
47
+ .cache
48
+ nosetests.xml
49
+ coverage.xml
50
+ *.cover
51
+ *.py,cover
52
+ .hypothesis/
53
+ .pytest_cache/
54
+ cover/
55
+
56
+ # Translations
57
+ *.mo
58
+ *.pot
59
+
60
+ # Django stuff:
61
+ *.log
62
+ local_settings.py
63
+ db.sqlite3
64
+ db.sqlite3-journal
65
+
66
+ # Flask stuff:
67
+ instance/
68
+ .webassets-cache
69
+
70
+ # Scrapy stuff:
71
+ .scrapy
72
+
73
+ # Sphinx documentation
74
+ docs/_build/
75
+
76
+ # PyBuilder
77
+ .pybuilder/
78
+ target/
79
+
80
+ # Jupyter Notebook
81
+ .ipynb_checkpoints
82
+
83
+ # IPython
84
+ profile_default/
85
+ ipython_config.py
86
+
87
+ # pyenv
88
+ # For a library or package, you might want to ignore these files since the code is
89
+ # intended to run in multiple environments; otherwise, check them in:
90
+ # .python-version
91
+
92
+ # pipenv
93
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
95
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
96
+ # install all needed dependencies.
97
+ #Pipfile.lock
98
+
99
+ # poetry
100
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
101
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
102
+ # commonly ignored for libraries.
103
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
104
+ #poetry.lock
105
+
106
+ # pdm
107
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
108
+ #pdm.lock
109
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
110
+ # in version control.
111
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
112
+ .pdm.toml
113
+ .pdm-python
114
+ .pdm-build/
115
+
116
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
117
+ __pypackages__/
118
+
119
+ # Celery stuff
120
+ celerybeat-schedule
121
+ celerybeat.pid
122
+
123
+ # SageMath parsed files
124
+ *.sage.py
125
+
126
+ # Environments
127
+ .env
128
+ .venv
129
+ env/
130
+ venv/
131
+ ENV/
132
+ env.bak/
133
+ venv.bak/
134
+
135
+ # Spyder project settings
136
+ .spyderproject
137
+ .spyproject
138
+
139
+ # Rope project settings
140
+ .ropeproject
141
+
142
+ # mkdocs documentation
143
+ /site
144
+
145
+ # mypy
146
+ .mypy_cache/
147
+ .dmypy.json
148
+ dmypy.json
149
+
150
+ # Pyre type checker
151
+ .pyre/
152
+
153
+ # pytype static type analyzer
154
+ .pytype/
155
+
156
+ # Cython debug symbols
157
+ cython_debug/
158
+
159
+ # PyCharm
160
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
161
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
162
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
163
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
164
+ #.idea/
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.9.7
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: UserStudyFinancialAdvisor
3
+ emoji: 💻
4
+ colorFrom: pink
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: 4.44.1
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
_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,1392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = "first"
68
+ feedback_dir = Path("user_feedback_debug/")
69
+ feedback_file_interaction = feedback_dir / f"interaction_{uuid_this_session}_{system_order}.json"
70
+ feedback_file_summarization = feedback_dir / f"summarization_{uuid_this_session}_{system_order}.json"
71
+ feedback_file_round_evaluation = feedback_dir / f"round_evaluation_{uuid_this_session}_{system_order}.json"
72
+ feedback_file_final_ranking = feedback_dir / f"final_ranking_{uuid_this_session}_{system_order}.json"
73
+ feedback_file_final_survey = feedback_dir / f"final_survey_{uuid_this_session}_{system_order}.json"
74
+ feedback_folder = feedback_file_interaction.parent
75
+ feedback_folder.mkdir(parents=True, exist_ok=True) # Ensure the directory exists
76
+
77
+ scheduler = CommitScheduler(
78
+ repo_id=os.getenv("LOGGING_FILE"),
79
+ repo_type="dataset",
80
+ folder_path=feedback_folder,
81
+ path_in_repo="data",
82
+ token=os.getenv("HUGGINGFACE_HUB_TOKEN"),
83
+ every=1,
84
+ )
85
+
86
+
87
+ # Function to save user feedback
88
+ def save_feedback(user_id: str, uuid: str, type: str, value, feedback_file) -> None:
89
+ """
90
+ Append input/outputs and user feedback to a JSON Lines file using a thread lock to avoid concurrent writes from different users.
91
+ """
92
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
93
+ with scheduler.lock:
94
+ with feedback_file.open("a") as f:
95
+ f.write(
96
+ json.dumps({"user_id": user_id, "uuid": uuid, "timestamp": timestamp, "type": type, "value": value})
97
+ )
98
+ f.write("\n")
99
+
100
+
101
+ # Load the required static content from files
102
+ def load_static_content(file_path):
103
+
104
+ with open(file_path, "r") as f:
105
+ return f.read()
106
+
107
+
108
+ def ensure_directory_exists(directory_path):
109
+ """Ensures the given directory exists; creates it if it does not."""
110
+ if not os.path.exists(directory_path):
111
+ os.makedirs(directory_path)
112
+
113
+
114
+ INSTRUCTION_PAGE = load_static_content(INSTRUCTION_PAGE_FILE)
115
+ EVALUATION_INSTRUCTION = load_static_content(EVALUATION_INSTRUCTION_FILE)
116
+ GENERAL_INSTRUCTION = load_static_content(GENERAL_INSTRUCTION_FILE)
117
+ USER_NARRATIVE = load_static_content(USER_NARRATIVE_FILE)
118
+ PREFERENCE_ELICITATION_TASK = load_static_content(PREFERENCE_ELICITATION_TASK_FILE)
119
+ FINAL_EVALUATION = load_static_content(FINAL_EVALUATION_FILE)
120
+ SYSTEM_INSTRUCTION_PERSONALIZATION = load_static_content(SYSTEM_INSTRUCTION_PERSONALIZATION_FILE)
121
+ SYSTEM_INSTRUCTION_NON_PERSONALIZATION = load_static_content(SYSTEM_INSTRUCTION_NON_PERSONALIZATION_FILE)
122
+ SYSTEM_INSTRUCTION_PERSONALITY = load_static_content(SYSTEM_INSTRUCTION_PERSONALITY_FILE)
123
+ SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION = load_static_content(SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_FILE)
124
+ SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY = load_static_content(
125
+ SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY_FILE
126
+ )
127
+ SUMMARIZATION_PROMPT = load_static_content(SUMMARIZATION_PROMPT_FILE)
128
+ PERSONALITY_EXT = load_static_content(PERSONALITY_EXT_FILE)
129
+ PERSONALITY_INT = load_static_content(PERSONALITY_INT_FILE)
130
+
131
+ # Other constants
132
+ FIRST_MESSAGE = "Hey"
133
+ USER_PREFERENCE_SUMMARY = True
134
+ DEBUG = False
135
+ API_TYPE = "together"
136
+ assert API_TYPE in ["together", "local", "debug"], "The API should be either 'together' or 'local'"
137
+ if API_TYPE == "together":
138
+ TOGETHER_CLIENT = Together(api_key=os.getenv("TOGETHER_API_KEY"))
139
+
140
+
141
+ def generate_username_pwd_list(data):
142
+ user_list = []
143
+ demo_list = []
144
+ for index, row in data.iterrows():
145
+ user_list.append((row["user"], str(row["pwd"])))
146
+ demo_list.append((row["demo"], str(row["pwd"])))
147
+ return user_list, demo_list
148
+
149
+
150
+ def load_username_and_pwd():
151
+ login(token=os.environ["HUGGINGFACE_HUB_TOKEN"])
152
+ dataset = load_dataset(os.getenv("USER_PWD_FILE"))
153
+ df = dataset["train"].to_pandas()
154
+ user_list, demo_list = generate_username_pwd_list(df)
155
+ return user_list, demo_list
156
+
157
+
158
+ def get_context_list(synthetic_data_path):
159
+ # Load data from the synthetic data file
160
+ with open(synthetic_data_path, "r") as f:
161
+ data = [json.loads(line) for line in f]
162
+
163
+ return data
164
+
165
+
166
+ def add_ticker_prefix(ticker_list, context_list):
167
+ res = []
168
+ for ticker, context in zip(ticker_list, context_list):
169
+ res.append(f"{ticker}: {context}")
170
+ return res
171
+
172
+
173
+ def build_raw_context_list(context_dict):
174
+ return context_dict["data"]
175
+
176
+
177
+ def build_context(context_dict):
178
+ return [build_context_element(context) for context in context_dict["data"]]
179
+
180
+
181
+ def build_context_element(context):
182
+ # [{topic: ex, data: {}}, {..}, ..]
183
+ # Extract information from the context
184
+ ticker = context["ticker"]
185
+ sector = context["sector"]
186
+ business_summary = context["business_summary"]
187
+ name = context["short_name"]
188
+ stock_price = context["price_data"]
189
+ earning = context["earning_summary"]
190
+ beta = context["beta"]
191
+
192
+ # Build the context string
193
+ stock_candidate = f"Stock Candidate: {name}"
194
+ 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}"
195
+
196
+ context_list = [stock_candidate, stock_info]
197
+
198
+ # Combine all parts into a single string
199
+ return "\n".join(context_list)
200
+
201
+
202
+ def get_user_narrative_html(user_narrative):
203
+ return USER_NARRATIVE.replace("{user_narrative}", user_narrative).replace("\n", "<br>")
204
+
205
+
206
+ def get_user_narrative_from_raw(raw_narrative):
207
+ return get_user_narrative_html(markdown.markdown(raw_narrative.replace("\n", "<br>")))
208
+
209
+
210
+ def get_task_instruction_for_user(context):
211
+ ticker_name = context["short_name"]
212
+ user_narrative = context["user_narrative"]
213
+ user_narrative = user_narrative.replace("\n", "<br>")
214
+ html_user_narrative = markdown.markdown(user_narrative)
215
+ general_instruction = GENERAL_INSTRUCTION
216
+ round_instruction = f"""
217
+ <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;">
218
+ <!-- Stock Information (Bold label, Normal ticker name) -->
219
+ <h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
220
+ Round Info
221
+ </h2>
222
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
223
+ Stock
224
+ </div>
225
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
226
+ <span style="font-weight: bold;">
227
+ This Round's Stock:
228
+ </span>
229
+ {ticker_name}
230
+ </div>
231
+
232
+ <!-- User Narrative (Bold label, Normal narrative) -->
233
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
234
+ User Narrative
235
+ </div>
236
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
237
+ {html_user_narrative}
238
+ </div>
239
+ </div>"""
240
+
241
+ return general_instruction, round_instruction
242
+
243
+
244
+ def display_system_instruction_with_html(
245
+ system_instruction,
246
+ ):
247
+ html_system_instruction = f"""
248
+ <p style="text-align: left; margin-bottom: 10px;">
249
+ {system_instruction}
250
+ </p>
251
+ """
252
+ return html_system_instruction
253
+
254
+
255
+ def log_action(user_id, tab_name, action, details):
256
+ """
257
+ Log actions for each tab (stock).
258
+ """
259
+ log_file_dir = os.path.join(LOG_DIR, f"{user_id}")
260
+ if os.path.exists(log_file_dir) is False:
261
+ os.makedirs(log_file_dir)
262
+ log_file = os.path.join(log_file_dir, f"{tab_name}.txt")
263
+ with open(log_file, "a") as f:
264
+ f.write(f"Action: {action} | Details: {details}\n")
265
+
266
+
267
+ def add_user_profile_to_system_instruction(
268
+ user_id, system_instruction, user_preference_elicitation_data, summary, terminator
269
+ ):
270
+ exp_id = int(user_id.split("_")[-3])
271
+ # exp_id = 1 => No personalization
272
+ if exp_id == 1:
273
+ return system_instruction
274
+ if summary:
275
+ if user_preference_elicitation_data["summary_history"] == "":
276
+ # Format prompt
277
+ summarization_prompt = SUMMARIZATION_PROMPT + "\nPrevious Conversations: {}".format(
278
+ user_preference_elicitation_data["history"]
279
+ )
280
+ summarization_instruction = [{"role": "system", "content": summarization_prompt}]
281
+ if API_TYPE == "local":
282
+ summ, _ = generate_response_local_api(summarization_instruction, terminator, 512, API_URL)
283
+ elif API_TYPE == "together":
284
+ summ, _ = generate_response_together_api(summarization_instruction, 512, TOGETHER_CLIENT)
285
+ else:
286
+ summ, _ = generate_response_debugging(summarization_instruction)
287
+ user_preference_elicitation_data["summary_history"] = summ
288
+ # log_action(user_id, "Prompt", "Preference Elicitation Summarization", summ)
289
+ save_feedback(
290
+ user_id,
291
+ uuid_this_session,
292
+ "preference_elicitation_summarization",
293
+ {"summarization": summ},
294
+ feedback_file_summarization,
295
+ )
296
+ system_instruction += f"\nUser Profile collected in the previous conversations: {user_preference_elicitation_data['summary_history']}\n"
297
+ else:
298
+ system_instruction += (
299
+ f"\nUser Profile collected in the previous conversations: {user_preference_elicitation_data['history']}\n"
300
+ )
301
+ return system_instruction
302
+
303
+
304
+ def likert_evaluation(content):
305
+ return gr.Radio(
306
+ [1, 2, 3, 4, 5, 6, 7],
307
+ label=f"{content}",
308
+ show_label=True,
309
+ )
310
+
311
+
312
+ def reorder_list_based_on_user_in_narrative_id(user_in_narrative_id, target_list):
313
+ # user_in_narrative
314
+ 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]}
315
+ user_in_narrative_random = random_order[user_in_narrative_id]
316
+ return [target_list[i] for i in user_in_narrative_random]
317
+
318
+
319
+ def create_demo():
320
+ global context_info_list, terminator
321
+
322
+ def tab_creation_exploration_stage(order, comp, context):
323
+ english_order = ["1", "2", "3", "4", "5"]
324
+ with gr.Tab(f"{english_order[order]}-1:Discuss"):
325
+ general_instruction = gr.HTML(label="General Instruction")
326
+ with gr.Row():
327
+ with gr.Column():
328
+ with gr.Row():
329
+ round_instruction = gr.HTML(label="Round Instruction")
330
+ with gr.Column():
331
+ with gr.Row():
332
+ chatbot = gr.Chatbot(height=600)
333
+ with gr.Row():
334
+ start_conversation = gr.Button(value="Start Conversation")
335
+ with gr.Row():
336
+ msg = gr.Textbox(scale=1, label="User Input")
337
+ with gr.Row():
338
+ msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
339
+ continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
340
+ with gr.Row():
341
+ clear = gr.ClearButton([msg, chatbot])
342
+ with gr.Tab(f"{english_order[order]}-2:Eval"):
343
+ with gr.Row():
344
+ gr.HTML(value=EVALUATION_INSTRUCTION)
345
+ with gr.Row():
346
+ likelihood = gr.Radio(
347
+ [1, 2, 3, 4, 5, 6, 7],
348
+ label="I am likely to purchase the stock (1 = Strongly Disagree, 7 = Strongly Agree)",
349
+ show_label=True,
350
+ )
351
+ reason = gr.Textbox(
352
+ scale=1,
353
+ label="Reason for Your Choice (Explain Your Reasoning & Highlight Useful Parts of Conversation)",
354
+ lines=5,
355
+ )
356
+ with gr.Row():
357
+ confidence = gr.Radio(
358
+ [1, 2, 3, 4, 5, 6, 7],
359
+ label="I am confident in my decision (1 = Strongly Disagree, 7 = Strongly Agree)",
360
+ show_label=True,
361
+ )
362
+ familiarity = gr.Radio(
363
+ [1, 2, 3, 4, 5, 6, 7],
364
+ label="What was your level of familiarity with the candidate stock before the interaction? (1 = Not Familiar, 7 = Very Familiar)",
365
+ )
366
+ with gr.Row():
367
+ textbox = gr.HTML()
368
+ evaluation_send_button = gr.Button(value="Send: Evaluation")
369
+ return {
370
+ "comp": comp,
371
+ "system_instruction_context": context,
372
+ "start_conversation": start_conversation,
373
+ "msg_button": msg_button,
374
+ "continue_button": continue_button,
375
+ "chatbot": chatbot,
376
+ "msg": msg,
377
+ "reason": reason,
378
+ "likelihood": likelihood,
379
+ "confidence": confidence,
380
+ "familiarity": familiarity,
381
+ "evaluation_send_button": evaluation_send_button,
382
+ "general_instruction": general_instruction,
383
+ "round_instruction": round_instruction,
384
+ "textbox": textbox,
385
+ }
386
+
387
+ def tab_creation_preference_stage():
388
+ with gr.Row():
389
+ gr.HTML(value=PREFERENCE_ELICITATION_TASK, label="Preference Elicitation Task")
390
+ with gr.Row():
391
+ with gr.Column():
392
+ user_narrative = gr.HTML(label="User Narrative")
393
+ with gr.Column():
394
+ with gr.Row():
395
+ elicitation_chatbot = gr.Chatbot(height=600)
396
+ with gr.Row():
397
+ start_conversation = gr.Button(value="Start Conversation")
398
+ with gr.Row():
399
+ msg = gr.Textbox(scale=1, label="User Input")
400
+ with gr.Row():
401
+ msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
402
+ continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
403
+ return {
404
+ "start_conversation": start_conversation,
405
+ "msg_button": msg_button,
406
+ "continue_button": continue_button,
407
+ "msg": msg,
408
+ "elicitation_chatbot": elicitation_chatbot,
409
+ "user_narrative": user_narrative,
410
+ }
411
+
412
+ def tab_final_evaluation():
413
+ with gr.Row():
414
+ gr.HTML(value=FINAL_EVALUATION)
415
+ with gr.Row():
416
+ gr.HTML(value="<h3>Rank the individual stocks below according to your desire to invest in each one.</h3>")
417
+ with gr.Row():
418
+ ranking_first_comp = gr.Dropdown(choices=[1, 2, 3, 4])
419
+ ranking_second_comp = gr.Dropdown(choices=[1, 2, 3, 4])
420
+ ranking_third_comp = gr.Dropdown(choices=[1, 2, 3, 4])
421
+ ranking_fourth_comp = gr.Dropdown(choices=[1, 2, 3, 4])
422
+ with gr.Row():
423
+ gr.HTML(
424
+ 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>'
425
+ )
426
+ with gr.Row():
427
+ perceived_personalization = likert_evaluation("The advisor understands my needs")
428
+ emotional_trust = likert_evaluation("I feel content about relying on this advisor for my decisions")
429
+ with gr.Row():
430
+ trust_in_competence = likert_evaluation("The advisor has good knowledge of the stock")
431
+ intention_to_use = likert_evaluation(
432
+ "I am willing to use this advisor as an aid to help with my decision about which stock to purchase"
433
+ )
434
+
435
+ with gr.Row():
436
+ usefulness = likert_evaluation("The advisor gave me good suggestions")
437
+ overall_satisfaction = likert_evaluation("Overall, I am satisfied with the advisor")
438
+ with gr.Row():
439
+ providing_information = likert_evaluation("The advisor provides the financial knowledge needed")
440
+ with gr.Row():
441
+ textbox = gr.HTML()
442
+ submit_ranking = gr.Button(value="Submit Final Evaluation")
443
+ return {
444
+ "first": ranking_first_comp,
445
+ "second": ranking_second_comp,
446
+ "third": ranking_third_comp,
447
+ "fourth": ranking_fourth_comp,
448
+ "evaluators": {
449
+ "perceived_personalization": perceived_personalization,
450
+ "emotional_trust": emotional_trust,
451
+ "trust_in_competence": trust_in_competence,
452
+ "intention_to_use": intention_to_use,
453
+ "usefulness": usefulness,
454
+ "overall_satisfaction": overall_satisfaction,
455
+ "providing_information": providing_information,
456
+ },
457
+ "submit_ranking": submit_ranking,
458
+ "text_box": textbox,
459
+ }
460
+
461
+ def click_control_exploration_stage(
462
+ tabs, user_id, tab_session, user_preference_elicitation_session, system_description_without_context
463
+ ):
464
+ (
465
+ comp,
466
+ system_instruction_context,
467
+ start_conversation,
468
+ msg_button,
469
+ continue_button,
470
+ chatbot,
471
+ msg,
472
+ reason,
473
+ likelihood,
474
+ confidence,
475
+ familiarity,
476
+ evaluation_send_button,
477
+ textbox,
478
+ ) = (
479
+ tabs["comp"],
480
+ tabs["system_instruction_context"],
481
+ tabs["start_conversation"],
482
+ tabs["msg_button"],
483
+ tabs["continue_button"],
484
+ tabs["chatbot"],
485
+ tabs["msg"],
486
+ tabs["reason"],
487
+ tabs["likelihood"],
488
+ tabs["confidence"],
489
+ tabs["familiarity"],
490
+ tabs["evaluation_send_button"],
491
+ tabs["textbox"],
492
+ )
493
+ system_instruction = ""
494
+ start_conversation.click(
495
+ lambda user_id, tab_session, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond_start_conversation(
496
+ user_id,
497
+ tab_session,
498
+ history,
499
+ system_instruction,
500
+ comp,
501
+ user_preference_elicitation_data=user_preference_elicitation_session,
502
+ system_description_without_context=system_description_without_context,
503
+ system_instruction_context=system_instruction_context,
504
+ ),
505
+ [
506
+ user_id,
507
+ tab_session,
508
+ chatbot,
509
+ comp,
510
+ user_preference_elicitation_session,
511
+ system_description_without_context,
512
+ system_instruction_context,
513
+ ],
514
+ [tab_session, chatbot, start_conversation, msg_button, continue_button],
515
+ )
516
+ msg_button.click(
517
+ lambda user_id, tab_session, message, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond(
518
+ user_id,
519
+ tab_session,
520
+ message,
521
+ tab_session["history"],
522
+ system_instruction,
523
+ comp,
524
+ user_preference_elicitation_data=user_preference_elicitation_session,
525
+ system_description_without_context=system_description_without_context,
526
+ system_instruction_context=system_instruction_context,
527
+ ),
528
+ [
529
+ user_id,
530
+ tab_session,
531
+ msg,
532
+ chatbot,
533
+ comp,
534
+ user_preference_elicitation_session,
535
+ system_description_without_context,
536
+ system_instruction_context,
537
+ ],
538
+ [tab_session, msg, chatbot],
539
+ )
540
+ continue_button.click(
541
+ lambda user_id, tab_session, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond_continue(
542
+ user_id,
543
+ tab_session,
544
+ tab_session["history"],
545
+ system_instruction,
546
+ comp,
547
+ user_preference_elicitation_data=user_preference_elicitation_session,
548
+ system_description_without_context=system_description_without_context,
549
+ system_instruction_context=system_instruction_context,
550
+ ),
551
+ [
552
+ user_id,
553
+ tab_session,
554
+ chatbot,
555
+ comp,
556
+ user_preference_elicitation_session,
557
+ system_description_without_context,
558
+ system_instruction_context,
559
+ ],
560
+ [tab_session, chatbot],
561
+ )
562
+ evaluation_send_button.click(
563
+ lambda user_id, comp, tab_session, reason, likelihood, confidence, familiarity, evaluation_send_button, textbox: respond_evaluation(
564
+ user_id,
565
+ tab_session,
566
+ {
567
+ "reason": reason,
568
+ "likelihood": likelihood,
569
+ "confidence": confidence,
570
+ "familiarity": familiarity,
571
+ },
572
+ comp,
573
+ evaluation_send_button,
574
+ textbox,
575
+ ),
576
+ [
577
+ user_id,
578
+ comp,
579
+ tab_session,
580
+ reason,
581
+ likelihood,
582
+ confidence,
583
+ familiarity,
584
+ evaluation_send_button,
585
+ textbox,
586
+ ],
587
+ [tab_session, reason, likelihood, confidence, familiarity, evaluation_send_button, textbox],
588
+ )
589
+
590
+ def click_control_preference_stage(
591
+ tabs, user_id, user_preference_elicitation_session, system_description_user_elicitation
592
+ ):
593
+ (
594
+ start_conversation,
595
+ msg_button,
596
+ continue_button,
597
+ elicitation_chatbot,
598
+ msg,
599
+ ) = (
600
+ tabs["start_conversation"],
601
+ tabs["msg_button"],
602
+ tabs["continue_button"],
603
+ tabs["elicitation_chatbot"],
604
+ tabs["msg"],
605
+ )
606
+ # nonlocal user_id
607
+ start_conversation.click(
608
+ lambda user_id, user_preference_elicitation_data, history, system_description_user_elicitation: respond_start_conversation(
609
+ user_id,
610
+ user_preference_elicitation_data,
611
+ history,
612
+ system_description_user_elicitation,
613
+ user_elicitation=True,
614
+ ),
615
+ [user_id, user_preference_elicitation_session, elicitation_chatbot, system_description_user_elicitation],
616
+ [user_preference_elicitation_session, elicitation_chatbot, start_conversation, msg_button, continue_button],
617
+ )
618
+ msg_button.click(
619
+ lambda user_id, tab_data, message, history, system_description_user_elicitation: respond(
620
+ user_id,
621
+ tab_data,
622
+ message,
623
+ tab_data["history"],
624
+ system_description_user_elicitation,
625
+ user_elicitation=True,
626
+ ),
627
+ [
628
+ user_id,
629
+ user_preference_elicitation_session,
630
+ msg,
631
+ elicitation_chatbot,
632
+ system_description_user_elicitation,
633
+ ],
634
+ [user_preference_elicitation_session, msg, elicitation_chatbot],
635
+ )
636
+ continue_button.click(
637
+ lambda user_id, tab_data, history, system_description_user_elicitation: respond_continue(
638
+ user_id,
639
+ tab_data,
640
+ tab_data["history"],
641
+ system_description_user_elicitation,
642
+ user_elicitation=True,
643
+ ),
644
+ [user_id, user_preference_elicitation_session, elicitation_chatbot, system_description_user_elicitation],
645
+ [user_preference_elicitation_session, elicitation_chatbot],
646
+ )
647
+
648
+ def click_control_final_evaluation(tabs, user_id, first_comp, second_comp, third_comp, fourth_comp, evaluators):
649
+ (
650
+ ranking_first_comp,
651
+ ranking_second_comp,
652
+ ranking_third_comp,
653
+ ranking_fourth_comp,
654
+ ) = (
655
+ tabs["first"],
656
+ tabs["second"],
657
+ tabs["third"],
658
+ tabs["fourth"],
659
+ )
660
+ (
661
+ perceived_personalization,
662
+ emotional_trust,
663
+ trust_in_competence,
664
+ intention_to_use,
665
+ usefulness,
666
+ overall_satisfaction,
667
+ providing_information,
668
+ ) = (
669
+ evaluators["perceived_personalization"],
670
+ evaluators["emotional_trust"],
671
+ evaluators["trust_in_competence"],
672
+ evaluators["intention_to_use"],
673
+ evaluators["usefulness"],
674
+ evaluators["overall_satisfaction"],
675
+ evaluators["providing_information"],
676
+ )
677
+ result_textbox = tabs["text_box"]
678
+ submit_ranking = tabs["submit_ranking"]
679
+ submit_ranking.click(
680
+ 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(
681
+ user_id,
682
+ first_comp,
683
+ ranking_first_comp,
684
+ second_comp,
685
+ ranking_second_comp,
686
+ third_comp,
687
+ ranking_third_comp,
688
+ fourth_comp,
689
+ ranking_fourth_comp,
690
+ perceived_personalization,
691
+ emotional_trust,
692
+ trust_in_competence,
693
+ intention_to_use,
694
+ usefulness,
695
+ overall_satisfaction,
696
+ providing_information,
697
+ submit_ranking,
698
+ ),
699
+ # Input components (names and rankings)
700
+ [
701
+ user_id,
702
+ first_comp,
703
+ ranking_first_comp,
704
+ second_comp,
705
+ ranking_second_comp,
706
+ third_comp,
707
+ ranking_third_comp,
708
+ fourth_comp,
709
+ ranking_fourth_comp,
710
+ perceived_personalization,
711
+ emotional_trust,
712
+ trust_in_competence,
713
+ intention_to_use,
714
+ usefulness,
715
+ overall_satisfaction,
716
+ providing_information,
717
+ submit_ranking,
718
+ ],
719
+ # Output component(s) where you want the result to appear, e.g., result_textbox
720
+ [result_textbox, submit_ranking],
721
+ )
722
+
723
+ def respond(
724
+ user_id,
725
+ tab_data,
726
+ message,
727
+ history,
728
+ system_instruction,
729
+ tab_name=None,
730
+ user_elicitation=False,
731
+ user_preference_elicitation_data=None,
732
+ system_description_without_context=None,
733
+ system_instruction_context=None,
734
+ ):
735
+ """
736
+ Return:
737
+ msg
738
+ chat_history
739
+ retrieved_passage
740
+ rewritten_query
741
+
742
+ """
743
+ assert (
744
+ tab_name is not None or user_elicitation is True
745
+ ), "Tab name is required for the start of the conversation unless it is not preference elicitation."
746
+ # Add user profile to system instruction
747
+ if system_description_without_context is not None and system_instruction_context is not None:
748
+ system_instruction = system_description_without_context + "\n" + system_instruction_context
749
+ if not user_elicitation:
750
+ system_instruction = add_user_profile_to_system_instruction(
751
+ user_id,
752
+ system_instruction,
753
+ user_preference_elicitation_data,
754
+ summary=USER_PREFERENCE_SUMMARY,
755
+ terminator=terminator,
756
+ )
757
+ # From string to list [{"role":"user", "content": message}, ...]
758
+ history = gradio_to_huggingface_message(history)
759
+ # We can implement context window here as we need all the system interaction. We can cut some of the early interactions if needed.
760
+ history = conversation_window(history, CONV_WINDOW)
761
+ # Add system instruction to the history
762
+ history = format_context(system_instruction, history)
763
+ # Add user message to the history
764
+ history_with_user_utterance = format_user_message(message, history)
765
+ # Call API instead of locally handle it
766
+ if API_TYPE == "local":
767
+ outputs_text, history = generate_response_local_api(history_with_user_utterance, terminator, 128, API_URL)
768
+ elif API_TYPE == "together":
769
+ outputs_text, history = generate_response_together_api(history_with_user_utterance, 128, TOGETHER_CLIENT)
770
+ else:
771
+ outputs_text, history = generate_response_debugging(history_with_user_utterance)
772
+ # exclude system interaction and store the others in the history
773
+ history = huggingface_to_gradio_message(history)
774
+ if tab_name is not None:
775
+ # Log the user message and response
776
+ save_feedback(
777
+ user_id,
778
+ uuid_this_session,
779
+ "interaction",
780
+ {"type": tab_name, "role": "user", "content": message},
781
+ feedback_file_interaction,
782
+ )
783
+ save_feedback(
784
+ user_id,
785
+ uuid_this_session,
786
+ "interaction",
787
+ {"type": tab_name, "role": "assistant", "content": outputs_text},
788
+ feedback_file_interaction,
789
+ )
790
+ # log_action(user_id, tab_name, "User Message", message)
791
+ # log_action(user_id, tab_name, "Response", outputs_text)
792
+ # Store the updated history for this tab
793
+ tab_data["history"] = history
794
+ if user_elicitation:
795
+ save_feedback(
796
+ user_id,
797
+ uuid_this_session,
798
+ "Interaction",
799
+ {"type": "user_elicitation", "role": "user", "content": message},
800
+ feedback_file_interaction,
801
+ )
802
+ save_feedback(
803
+ user_id,
804
+ uuid_this_session,
805
+ "Interaction",
806
+ {"type": "user_elicitation", "role": "assistant", "content": outputs_text},
807
+ feedback_file_interaction,
808
+ )
809
+ # log_action(user_id, "User_Elicitation", "User Message", message)
810
+ # log_action(user_id, "User_Elicitation", "Response", outputs_text)
811
+ tab_data["history"] = history
812
+
813
+ return tab_data, "", history
814
+
815
+ def respond_start_conversation(
816
+ user_id,
817
+ tab_data,
818
+ history,
819
+ system_instruction,
820
+ tab_name=None,
821
+ user_elicitation=False,
822
+ user_preference_elicitation_data=None,
823
+ system_description_without_context=None,
824
+ system_instruction_context=None,
825
+ ):
826
+ assert (
827
+ tab_name is not None or user_elicitation is True
828
+ ), "Tab name is required for the start of the conversation unless it is not preference elicitation."
829
+ if system_description_without_context is not None and system_instruction_context is not None:
830
+ system_instruction = system_description_without_context + "\n" + system_instruction_context
831
+ if not user_elicitation:
832
+ system_instruction = add_user_profile_to_system_instruction(
833
+ user_id,
834
+ system_instruction,
835
+ user_preference_elicitation_data,
836
+ summary=USER_PREFERENCE_SUMMARY,
837
+ terminator=terminator,
838
+ )
839
+ history = gradio_to_huggingface_message(history)
840
+ history = format_context(system_instruction, history)
841
+ first_message = FIRST_MESSAGE
842
+ history_with_user_utterance = format_user_message(first_message, history)
843
+ max_length = 128 if user_elicitation else 256
844
+ if API_TYPE == "local":
845
+ outputs_text, history = generate_response_local_api(
846
+ history_with_user_utterance, terminator, max_length, API_URL
847
+ )
848
+ elif API_TYPE == "together":
849
+ outputs_text, history = generate_response_together_api(
850
+ history_with_user_utterance, max_length, TOGETHER_CLIENT
851
+ )
852
+ else:
853
+ outputs_text, history = generate_response_debugging(history_with_user_utterance)
854
+ # Format
855
+ history = huggingface_to_gradio_message(history)
856
+ if tab_name is not None:
857
+ # Log the user message and response
858
+ save_feedback(
859
+ user_id,
860
+ uuid_this_session,
861
+ "interaction",
862
+ {"type": tab_name, "role": "user", "content": first_message},
863
+ feedback_file_interaction,
864
+ )
865
+ save_feedback(
866
+ user_id,
867
+ uuid_this_session,
868
+ "interaction",
869
+ {"type": tab_name, "role": "assistant", "content": outputs_text},
870
+ feedback_file_interaction,
871
+ )
872
+ # log_action(user_id, tab_name, "User Message", first_message)
873
+ # log_action(user_id, tab_name, "Response", outputs_text)
874
+ # Store the updated history for this tab
875
+ tab_data["history"] = history
876
+ if user_elicitation:
877
+ save_feedback(
878
+ user_id,
879
+ uuid_this_session,
880
+ "interaction",
881
+ {"type": "user_elicitation", "role": "user", "content": first_message},
882
+ feedback_file_interaction,
883
+ )
884
+ save_feedback(
885
+ user_id,
886
+ uuid_this_session,
887
+ "Interaction",
888
+ {"type": "user_elicitation", "role": "assistant", "content": outputs_text},
889
+ feedback_file_interaction,
890
+ )
891
+ tab_data["history"] = history
892
+ return (
893
+ tab_data,
894
+ history,
895
+ gr.Button(value="Start Conversation", interactive=False),
896
+ gr.Button(value="Send This Message to Advisor", interactive=True),
897
+ gr.Button(value="Show More of the Advisor’s Answer", interactive=True),
898
+ )
899
+
900
+ def respond_continue(
901
+ user_id,
902
+ tab_data,
903
+ history,
904
+ system_instruction,
905
+ tab_name=None,
906
+ user_elicitation=False,
907
+ user_preference_elicitation_data=None,
908
+ system_description_without_context=None,
909
+ system_instruction_context=None,
910
+ ):
911
+ assert (
912
+ tab_name is not None or user_elicitation is True
913
+ ), "Tab name is required for the start of the conversation."
914
+ # Add user profile to system instruction
915
+ if system_description_without_context is not None and system_instruction_context is not None:
916
+ system_instruction = system_description_without_context + "\n" + system_instruction_context
917
+ if not user_elicitation:
918
+ system_instruction = add_user_profile_to_system_instruction(
919
+ user_id,
920
+ system_instruction,
921
+ user_preference_elicitation_data,
922
+ summary=USER_PREFERENCE_SUMMARY,
923
+ terminator=terminator,
924
+ )
925
+ message = "continue"
926
+ history = gradio_to_huggingface_message(history)
927
+ history = conversation_window(history, CONV_WINDOW)
928
+ history = format_context(system_instruction, history)
929
+ history_with_user_utterance = format_user_message(message, history)
930
+ if API_TYPE == "local":
931
+ outputs_text, history = generate_response_local_api(history_with_user_utterance, terminator, 128, API_URL)
932
+ elif API_TYPE == "together":
933
+ outputs_text, history = generate_response_together_api(history_with_user_utterance, 128, TOGETHER_CLIENT)
934
+ else:
935
+ outputs_text, history = generate_response_debugging(history_with_user_utterance)
936
+ history = huggingface_to_gradio_message(history)
937
+ if tab_name is not None:
938
+ save_feedback(
939
+ user_id,
940
+ uuid_this_session,
941
+ "interaction",
942
+ {
943
+ "type": tab_name,
944
+ "role": "user",
945
+ "content": message,
946
+ },
947
+ feedback_file_interaction,
948
+ )
949
+ save_feedback(
950
+ user_id,
951
+ uuid_this_session,
952
+ "interaction",
953
+ {"type": tab_name, "role": "assistant", "content": outputs_text},
954
+ feedback_file_interaction,
955
+ )
956
+
957
+ # Update history for this tab
958
+ tab_data["history"] = history
959
+ if user_elicitation:
960
+ save_feedback(
961
+ user_id,
962
+ uuid_this_session,
963
+ "interaction",
964
+ {"type": "user_elicitation", "role": "user", "content": message},
965
+ feedback_file_interaction,
966
+ )
967
+ save_feedback(
968
+ user_id,
969
+ uuid_this_session,
970
+ "interaction",
971
+ {"type": "user_elicitation", "role": "assistant", "content": outputs_text},
972
+ feedback_file_interaction,
973
+ )
974
+ tab_data["history"] = history
975
+ return tab_data, history
976
+
977
+ def respond_evaluation(user_id, tab_data, evals, tab_name, evaluation_send_button, textbox):
978
+
979
+ # dropdown, readon_button, multi-evaluator
980
+ if evals["likelihood"] is None or evals["confidence"] is None or evals["familiarity"] is None:
981
+ return (
982
+ tab_data,
983
+ evals["reason"],
984
+ evals["likelihood"],
985
+ evals["confidence"],
986
+ evals["familiarity"],
987
+ evaluation_send_button,
988
+ """<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
989
+ <strong>Please make sure that you answer all the questions.</strong>
990
+ </div>""",
991
+ )
992
+ else:
993
+ save_feedback(
994
+ user_id,
995
+ uuid_this_session,
996
+ "round_evaluation",
997
+ {**evals, "company": tab_name},
998
+ feedback_file_round_evaluation,
999
+ )
1000
+ # log_action(user_id, tab_name, "Round Evaluation", "Following")
1001
+ # for key, value in evals.items():
1002
+ # log_action(user_id, tab_name, key, value)
1003
+ # Store the reason for this tab
1004
+ tab_data["multi_evaluator"] = evals
1005
+ evaluation_send_button = gr.Button(value="Evaluation receirved", interactive=False)
1006
+ return (
1007
+ tab_data,
1008
+ evals["reason"],
1009
+ evals["likelihood"],
1010
+ evals["confidence"],
1011
+ evals["familiarity"],
1012
+ evaluation_send_button,
1013
+ """<div style="background-color: #d4edda; color: #155724; padding: 15px; border: 1px solid #c3e6cb; border-radius: 5px; margin-bottom: 20px;">
1014
+ <strong>Thank you for submitting your evaluation. You may proceed to the next tab.</strong>
1015
+ </div>""",
1016
+ )
1017
+
1018
+ def respond_final_ranking(
1019
+ user_id,
1020
+ first_comp,
1021
+ ranking_first_comp,
1022
+ second_comp,
1023
+ ranking_second_comp,
1024
+ third_comp,
1025
+ ranking_third_comp,
1026
+ fourth_comp,
1027
+ ranking_fourth_comp,
1028
+ perceived_personalization,
1029
+ emotional_trust,
1030
+ trust_in_competence,
1031
+ intention_to_use,
1032
+ usefulness,
1033
+ overall_satisfaction,
1034
+ providing_information,
1035
+ submit_ranking,
1036
+ ):
1037
+ # make sure that they are not the same
1038
+ ranking_list = [
1039
+ ranking_first_comp,
1040
+ ranking_second_comp,
1041
+ ranking_third_comp,
1042
+ ranking_fourth_comp,
1043
+ ]
1044
+ if len(set(ranking_list)) != len(ranking_list):
1045
+ return (
1046
+ """<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
1047
+ <strong>Please make sure that you are not ranking the same stock multiple times.</strong>
1048
+ </div>""",
1049
+ submit_ranking,
1050
+ )
1051
+ if any(
1052
+ var is None
1053
+ for var in [
1054
+ perceived_personalization,
1055
+ emotional_trust,
1056
+ trust_in_competence,
1057
+ intention_to_use,
1058
+ usefulness,
1059
+ overall_satisfaction,
1060
+ providing_information,
1061
+ ]
1062
+ ):
1063
+ return (
1064
+ """<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
1065
+ <strong>Please make sure that you answer all the statements.</strong>
1066
+ </div>""",
1067
+ submit_ranking,
1068
+ )
1069
+ else:
1070
+ save_feedback(
1071
+ user_id,
1072
+ uuid_this_session,
1073
+ "final_ranking",
1074
+ {
1075
+ "comp_order": [first_comp, second_comp, third_comp, fourth_comp],
1076
+ "ranking": ranking_list,
1077
+ },
1078
+ feedback_file_final_ranking,
1079
+ )
1080
+
1081
+ save_feedback(
1082
+ user_id,
1083
+ uuid_this_session,
1084
+ "final_ranking_survey",
1085
+ {
1086
+ "perceived_personalization": perceived_personalization,
1087
+ "emotional_trust": emotional_trust,
1088
+ "trust_in_competence": trust_in_competence,
1089
+ "intention_to_use": intention_to_use,
1090
+ "usefulness": usefulness,
1091
+ "overall_satisfaction": overall_satisfaction,
1092
+ "providing_information": providing_information,
1093
+ },
1094
+ feedback_file_final_survey,
1095
+ )
1096
+ submit_ranking = gr.Button(value="Final evaluaiotn received", interactive=False)
1097
+ return (
1098
+ """<div style="background-color: #d4edda; color: #155724; padding: 15px; border: 1px solid #c3e6cb; border-radius: 5px; margin-bottom: 20px;">
1099
+ <strong>Thank you for participating in the experiment. This concludes the session. You may now close the tab.</strong>
1100
+ </div>""",
1101
+ submit_ranking,
1102
+ )
1103
+
1104
+ def get_context(index, raw_context_list, stock_context_list):
1105
+ comp = raw_context_list[index]["short_name"]
1106
+ context = stock_context_list[index]
1107
+ general_instruction, round_instruction = get_task_instruction_for_user(raw_context_list[index])
1108
+ return comp, context, general_instruction, round_instruction
1109
+
1110
+ def set_user_id(request: gr.Request):
1111
+ # DEBUG
1112
+ user_id = "user_0_0_0"
1113
+ # user_id = request.username
1114
+ user_in_narrative_id = user_id.split("_")[-1]
1115
+ narrative_id = user_id.split("_")[-2]
1116
+ experiment_id = user_id.split("_")[-3]
1117
+ return user_id, user_in_narrative_id, narrative_id, experiment_id
1118
+
1119
+ def get_inst_without_context(experiment_id):
1120
+ # experiment_id = 1 => personalization
1121
+ # experiment_id = 2 => no personalization
1122
+ # experiment_id == 3 => ext personality
1123
+ # experiment_id == 4 => int personality
1124
+ if experiment_id == "0":
1125
+ return SYSTEM_INSTRUCTION_PERSONALIZATION
1126
+ elif experiment_id == "1":
1127
+ return SYSTEM_INSTRUCTION_NON_PERSONALIZATION
1128
+ elif experiment_id == "2":
1129
+ return SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_EXT)
1130
+ elif experiment_id == "3":
1131
+ return SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_INT)
1132
+
1133
+ def get_user_preference_elicitation(experiment_id):
1134
+ if experiment_id == "0" or experiment_id == "1":
1135
+ return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION
1136
+ elif experiment_id == "2":
1137
+ return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(personality=PERSONALITY_EXT)
1138
+ elif experiment_id == "3":
1139
+ return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(personality=PERSONALITY_INT)
1140
+
1141
+ def get_stock_related_context(narrative_id, user_in_narrative_id):
1142
+ raw_context_list = build_raw_context_list(context_info_list[int(narrative_id)])
1143
+ stock_context_list = build_context(context_info_list[int(narrative_id)])
1144
+ raw_context_list = reorder_list_based_on_user_in_narrative_id(user_in_narrative_id, raw_context_list)
1145
+ stock_context_list = reorder_list_based_on_user_in_narrative_id(user_in_narrative_id, stock_context_list)
1146
+ return raw_context_list, stock_context_list
1147
+
1148
+ def set_initial_values(request: gr.Request):
1149
+ # Set user specific information (Session State)
1150
+ user_id, user_in_narrative_id, narrative_id, experiment_id = set_user_id(request)
1151
+ # System instruction without prompt
1152
+ system_description_without_context = get_inst_without_context(experiment_id)
1153
+ # user_preference_elicitation
1154
+ system_description_user_elicitation = get_user_preference_elicitation(experiment_id)
1155
+ # Stock related context
1156
+ raw_context_list, stock_context_list = get_stock_related_context(narrative_id, user_in_narrative_id)
1157
+ # User Narrative
1158
+ user_narrative = get_user_narrative_from_raw(raw_context_list[0]["user_narrative"])
1159
+ # Tab Context
1160
+ first_comp, first_context, first_general_instruction, first_round_instruction = get_context(
1161
+ 0, raw_context_list, stock_context_list
1162
+ )
1163
+ second_comp, second_context, second_general_instruction, second_round_instruction = get_context(
1164
+ 1, raw_context_list, stock_context_list
1165
+ )
1166
+ third_comp, third_context, third_general_instruction, third_round_instruction = get_context(
1167
+ 2, raw_context_list, stock_context_list
1168
+ )
1169
+ fourth_comp, fourth_context, fourth_general_instruction, fourth_round_instruction = get_context(
1170
+ 3, raw_context_list, stock_context_list
1171
+ )
1172
+ # Final Evaluation
1173
+ ranking_first_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=first_comp)
1174
+ ranking_second_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=second_comp)
1175
+ ranking_third_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=third_comp)
1176
+ ranking_fourth_comp = gr.Dropdown(choices=[1, 2, 3, 4], label=fourth_comp)
1177
+
1178
+ return (
1179
+ user_id,
1180
+ user_in_narrative_id,
1181
+ narrative_id,
1182
+ experiment_id,
1183
+ system_description_without_context,
1184
+ system_description_user_elicitation,
1185
+ raw_context_list,
1186
+ stock_context_list,
1187
+ user_narrative,
1188
+ first_comp,
1189
+ first_context,
1190
+ first_general_instruction,
1191
+ first_round_instruction,
1192
+ second_comp,
1193
+ second_context,
1194
+ second_general_instruction,
1195
+ second_round_instruction,
1196
+ third_comp,
1197
+ third_context,
1198
+ third_general_instruction,
1199
+ third_round_instruction,
1200
+ fourth_comp,
1201
+ fourth_context,
1202
+ fourth_general_instruction,
1203
+ fourth_round_instruction,
1204
+ ranking_first_comp,
1205
+ ranking_second_comp,
1206
+ ranking_third_comp,
1207
+ ranking_fourth_comp,
1208
+ )
1209
+
1210
+ with gr.Blocks(title="RAG Chatbot Q&A", theme="Soft") as demo:
1211
+ # Set user specific information (Session State)
1212
+ user_id = gr.State()
1213
+ user_in_narrative_id = gr.State()
1214
+ narrative_id = gr.State()
1215
+ experiment_id = gr.State()
1216
+ system_description_without_context = gr.State()
1217
+ system_description_user_elicitation = gr.State()
1218
+ # Context data
1219
+ raw_context_list = gr.State()
1220
+ stock_context_list = gr.State()
1221
+ first_comp = gr.State()
1222
+ first_context = gr.State()
1223
+ second_comp = gr.State()
1224
+ second_context = gr.State()
1225
+ third_comp = gr.State()
1226
+ third_context = gr.State()
1227
+ fourth_comp = gr.State()
1228
+ fourth_context = gr.State()
1229
+ # Tab data
1230
+ if DEBUG:
1231
+ user_preference_elicitation_session = gr.State(
1232
+ value={
1233
+ "history": "",
1234
+ "summary_history": """User Profile collected in the previous conversations: Based on our previous conversation, here's a summary of your investment preferences:
1235
+
1236
+ # 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.
1237
+ # 2. **Value vs. Growth Stocks:** You prefer growth stocks, which have the potential for high returns but may be riskier.
1238
+ # 3. **Dividend vs. Non-Dividend Stocks:** You're open to both dividend and non-dividend growth stocks, focusing on reinvesting profits for future growth.
1239
+ # 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.""",
1240
+ }
1241
+ )
1242
+ else:
1243
+ user_preference_elicitation_session = gr.State(value={"history": "", "summary_history": ""})
1244
+ first_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
1245
+ second_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
1246
+ third_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
1247
+ fourth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
1248
+ # EXperiment Instruction
1249
+ with gr.Tab("Experiment Instruction") as instruction_tab:
1250
+ gr.HTML(value=INSTRUCTION_PAGE, label="Experiment Instruction")
1251
+ # User Preference Elicitation Tab
1252
+ with gr.Tab("Preference Elicitation Stage") as preference_elicitation_tab:
1253
+ user_preference_elicitation_tab = tab_creation_preference_stage()
1254
+ user_narrative = user_preference_elicitation_tab["user_narrative"]
1255
+ click_control_preference_stage(
1256
+ user_preference_elicitation_tab,
1257
+ user_id,
1258
+ user_preference_elicitation_session,
1259
+ system_description_user_elicitation,
1260
+ )
1261
+ with gr.Tab("Financial Decision Stage") as financial_decision:
1262
+ # Experiment Tag
1263
+ first_tab = tab_creation_exploration_stage(0, first_comp, first_context)
1264
+ first_general_instruction, first_round_instruction = (
1265
+ first_tab["general_instruction"],
1266
+ first_tab["round_instruction"],
1267
+ )
1268
+ click_control_exploration_stage(
1269
+ first_tab,
1270
+ user_id,
1271
+ first_comp_session,
1272
+ user_preference_elicitation_session,
1273
+ system_description_without_context,
1274
+ )
1275
+ second_tab = tab_creation_exploration_stage(1, second_comp, second_context)
1276
+ second_general_instruction, second_round_instruction = (
1277
+ second_tab["general_instruction"],
1278
+ second_tab["round_instruction"],
1279
+ )
1280
+ click_control_exploration_stage(
1281
+ second_tab,
1282
+ user_id,
1283
+ second_comp_session,
1284
+ user_preference_elicitation_session,
1285
+ system_description_without_context,
1286
+ )
1287
+ third_tab = tab_creation_exploration_stage(2, third_comp, third_context)
1288
+ third_general_instruction, third_round_instruction = (
1289
+ third_tab["general_instruction"],
1290
+ third_tab["round_instruction"],
1291
+ )
1292
+ click_control_exploration_stage(
1293
+ third_tab,
1294
+ user_id,
1295
+ third_comp_session,
1296
+ user_preference_elicitation_session,
1297
+ system_description_without_context,
1298
+ )
1299
+ fourth_tab = tab_creation_exploration_stage(3, fourth_comp, fourth_context)
1300
+ fourth_general_instruction, fourth_round_instruction = (
1301
+ fourth_tab["general_instruction"],
1302
+ fourth_tab["round_instruction"],
1303
+ )
1304
+ click_control_exploration_stage(
1305
+ fourth_tab,
1306
+ user_id,
1307
+ fourth_comp_session,
1308
+ user_preference_elicitation_session,
1309
+ system_description_without_context,
1310
+ )
1311
+ with gr.Tab("Final Evaluation Stage") as final_evaluation:
1312
+ final_evaluation_tab = tab_final_evaluation()
1313
+ (
1314
+ ranking_first_comp,
1315
+ ranking_second_comp,
1316
+ ranking_third_comp,
1317
+ ranking_fourth_comp,
1318
+ evaluators,
1319
+ ) = (
1320
+ final_evaluation_tab["first"],
1321
+ final_evaluation_tab["second"],
1322
+ final_evaluation_tab["third"],
1323
+ final_evaluation_tab["fourth"],
1324
+ final_evaluation_tab["evaluators"],
1325
+ )
1326
+ click_control_final_evaluation(
1327
+ final_evaluation_tab, user_id, first_comp, second_comp, third_comp, fourth_comp, evaluators
1328
+ )
1329
+
1330
+ demo.load(
1331
+ set_initial_values,
1332
+ inputs=None,
1333
+ outputs=[
1334
+ user_id,
1335
+ user_in_narrative_id,
1336
+ narrative_id,
1337
+ experiment_id,
1338
+ system_description_without_context,
1339
+ system_description_user_elicitation,
1340
+ raw_context_list,
1341
+ stock_context_list,
1342
+ user_narrative,
1343
+ first_comp,
1344
+ first_context,
1345
+ first_general_instruction,
1346
+ first_round_instruction,
1347
+ second_comp,
1348
+ second_context,
1349
+ second_general_instruction,
1350
+ second_round_instruction,
1351
+ third_comp,
1352
+ third_context,
1353
+ third_general_instruction,
1354
+ third_round_instruction,
1355
+ fourth_comp,
1356
+ fourth_context,
1357
+ fourth_general_instruction,
1358
+ fourth_round_instruction,
1359
+ ranking_first_comp,
1360
+ ranking_second_comp,
1361
+ ranking_third_comp,
1362
+ ranking_fourth_comp,
1363
+ ],
1364
+ )
1365
+ return demo
1366
+
1367
+
1368
+ if __name__ == "__main__":
1369
+ file_path = os.path.join(ROOT_FILE, "./data/single_stock_data/experiment_processed_data.jsonl")
1370
+ topics = [
1371
+ "healthcare_growth_defensive",
1372
+ "dividend_value_defensive",
1373
+ "nondividend_value_cyclical",
1374
+ ]
1375
+ context_info_list = get_context_list(file_path) # str to List of Dict
1376
+ # system instruction consist of Task, Personality, and Context
1377
+ """
1378
+ Personality
1379
+ ["extroverted", "introverted"]
1380
+ ["agreeable", "antagonistic"]
1381
+ ["conscientious", "unconscientious"]
1382
+ ["neurotic", "emotionally stable"]
1383
+ ["open to experience", "closed to experience"]]
1384
+ """
1385
+ # Global variables
1386
+ terminator = ["<eos>", "<unk>", "<sep>", "<pad>", "<cls>", "<mask>"]
1387
+ demo = create_demo()
1388
+ user_list, demo_list = load_username_and_pwd()
1389
+ demo.launch(
1390
+ share=False,
1391
+ # auth=user_list + demo_list + ["test", "test"],
1392
+ )
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
 
dum.txt ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ absl-py==1.3.0
2
+ accelerate==0.31.0
3
+ aiofiles==23.2.1
4
+ aiohappyeyeballs==2.4.3
5
+ aiohttp==3.10.8
6
+ aiosignal==1.2.0
7
+ alembic==1.8.1
8
+ annotated-types==0.6.0
9
+ anyio==3.6.2
10
+ appdirs==1.4.4
11
+ argon2-cffi==21.3.0
12
+ argon2-cffi-bindings==21.2.0
13
+ asttokens==2.0.5
14
+ astunparse==1.6.3
15
+ async-timeout==4.0.2
16
+ attrs==21.4.0
17
+ autopage==0.5.1
18
+ backcall==0.2.0
19
+ beautifulsoup4==4.11.1
20
+ black==22.8.0
21
+ bleach==6.0.0
22
+ blis==0.7.11
23
+ cachetools==5.2.0
24
+ catalogue==2.0.10
25
+ cbor==1.0.0
26
+ certifi==2022.6.15
27
+ cffi==1.15.1
28
+ charset-normalizer==2.1.0
29
+ chest==0.2.3
30
+ click==8.1.7
31
+ cliff==4.1.0
32
+ cloudpathlib==0.18.1
33
+ cloudpickle==2.2.1
34
+ cmaes==0.9.1
35
+ cmake==3.29.0.1
36
+ cmd2==2.4.2
37
+ colorama==0.4.4
38
+ coloredlogs==15.0.1
39
+ colorlog==4.7.2
40
+ comm==0.2.2
41
+ confection==0.1.5
42
+ cryptography==39.0.0
43
+ cwl-eval==1.0.12
44
+ cycler==0.11.0
45
+ cymem==2.0.8
46
+ Cython==3.0.10
47
+ datasets==2.3.2
48
+ debugpy==1.6.2
49
+ decorator==5.1.1
50
+ defusedxml==0.7.1
51
+ Deprecated==1.2.14
52
+ dill==0.3.5.1
53
+ distlib==0.3.6
54
+ distro==1.9.0
55
+ easydict==1.13
56
+ entrypoints==0.4
57
+ et-xmlfile==1.1.0
58
+ eval_type_backport==0.2.0
59
+ executing==0.8.3
60
+ faiss-cpu==1.8.0.post1
61
+ fastapi==0.112.1
62
+ fastjsonschema==2.16.2
63
+ ffmpy==0.4.0
64
+ filelock==3.16.1
65
+ flake8==5.0.4
66
+ flatbuffers==23.3.3
67
+ fonttools==4.34.4
68
+ frozendict==2.3.4
69
+ frozenlist==1.3.0
70
+ fsspec==2024.6.0
71
+ fugashi==1.1.2
72
+ gast==0.4.0
73
+ gdown==5.2.0
74
+ google-auth==2.15.0
75
+ google-auth-oauthlib==1.0.0
76
+ google-pasta==0.2.0
77
+ gradio==4.41.0
78
+ gradio_client==1.3.0
79
+ greenlet==2.0.1
80
+ grpcio==1.51.1
81
+ h11==0.14.0
82
+ h5py==3.8.0
83
+ HeapDict==1.0.1
84
+ html5lib==1.1
85
+ httpcore==1.0.2
86
+ httpx==0.26.0
87
+ huggingface-hub==0.24.2
88
+ humanfriendly==10.0
89
+ idna==3.3
90
+ ijson==3.3.0
91
+ implicit==0.6.2
92
+ importlib-metadata==4.13.0
93
+ importlib-resources==5.10.1
94
+ inscriptis==2.5.0
95
+ ipadic==1.0.0
96
+ ipdb==0.13.13
97
+ ipykernel==6.15.1
98
+ ipython==8.4.0
99
+ ipython-genutils==0.2.0
100
+ ipywidgets==8.1.3
101
+ ir-measures==0.3.3
102
+ ir_datasets==0.5.8
103
+ japanize-matplotlib==1.1.3
104
+ jax==0.4.8
105
+ jedi==0.18.1
106
+ Jinja2==3.1.2
107
+ joblib==1.1.0
108
+ jsonschema==4.17.3
109
+ jupyter==1.0.0
110
+ jupyter-client==7.3.4
111
+ jupyter-console==6.6.3
112
+ jupyter-core==4.11.1
113
+ jupyter-events==0.6.3
114
+ jupyter_server==2.5.0
115
+ jupyter_server_terminals==0.4.4
116
+ jupyterlab-pygments==0.2.2
117
+ jupyterlab_widgets==3.0.11
118
+ kaleido==0.2.1
119
+ keras==2.12.0
120
+ kiwisolver==1.4.4
121
+ krippendorff==0.6.0
122
+ langcodes==3.4.0
123
+ language_data==1.2.0
124
+ libclang==16.0.0
125
+ lightgbm==4.4.0
126
+ lit==18.1.2
127
+ llvmlite==0.39.1
128
+ lxml==5.3.0
129
+ lz4==4.3.3
130
+ Mako==1.2.4
131
+ marisa-trie==1.2.0
132
+ Markdown==3.4.1
133
+ markdown-it-py==3.0.0
134
+ MarkupSafe==2.1.1
135
+ matchpy==0.5.5
136
+ matplotlib==3.5.2
137
+ matplotlib-inline==0.1.3
138
+ mccabe==0.7.0
139
+ mdurl==0.1.2
140
+ mecab==0.996.3
141
+ mistune==2.0.5
142
+ ml-dtypes==0.1.0
143
+ ml-metrics==0.1.4
144
+ more-itertools==10.4.0
145
+ mpmath==1.3.0
146
+ msgpack==1.0.4
147
+ multidict==6.0.2
148
+ multiprocess==0.70.13
149
+ multiset==2.1.1
150
+ multitasking==0.0.11
151
+ murmurhash==1.0.10
152
+ mypy==0.971
153
+ mypy-extensions==0.4.3
154
+ nbclassic==0.5.3
155
+ nbclient==0.7.2
156
+ nbconvert==7.2.10
157
+ nbformat==5.7.3
158
+ nest-asyncio==1.5.5
159
+ networkx==2.8.5
160
+ nltk==3.8.1
161
+ nmslib==2.1.1
162
+ notebook==6.5.3
163
+ notebook_shim==0.2.2
164
+ nptyping==1.4.4
165
+ numba==0.56.4
166
+ numpy==1.24.4
167
+ nvidia-cublas-cu11==11.10.3.66
168
+ nvidia-cublas-cu12==12.1.3.1
169
+ nvidia-cuda-cupti-cu11==11.7.101
170
+ nvidia-cuda-cupti-cu12==12.1.105
171
+ nvidia-cuda-nvrtc-cu11==11.7.99
172
+ nvidia-cuda-nvrtc-cu12==12.1.105
173
+ nvidia-cuda-runtime-cu11==11.7.99
174
+ nvidia-cuda-runtime-cu12==12.1.105
175
+ nvidia-cudnn-cu11==8.5.0.96
176
+ nvidia-cudnn-cu12==8.9.2.26
177
+ nvidia-cufft-cu11==10.9.0.58
178
+ nvidia-cufft-cu12==11.0.2.54
179
+ nvidia-curand-cu11==10.2.10.91
180
+ nvidia-curand-cu12==10.3.2.106
181
+ nvidia-cusolver-cu11==11.4.0.1
182
+ nvidia-cusolver-cu12==11.4.5.107
183
+ nvidia-cusparse-cu11==11.7.4.91
184
+ nvidia-cusparse-cu12==12.1.0.106
185
+ nvidia-nccl-cu11==2.14.3
186
+ nvidia-nccl-cu12==2.18.1
187
+ nvidia-nvjitlink-cu12==12.4.127
188
+ nvidia-nvtx-cu11==11.7.91
189
+ nvidia-nvtx-cu12==12.1.105
190
+ oauthlib==3.2.2
191
+ onnxruntime==1.18.0
192
+ openai==1.12.0
193
+ openpyxl==3.0.10
194
+ opt-einsum==3.3.0
195
+ optuna==3.1.1
196
+ orjson==3.10.7
197
+ packaging==21.3
198
+ pandarallel==1.6.4
199
+ pandas==1.4.3
200
+ pandas-datareader==0.10.0
201
+ pandocfilters==1.5.0
202
+ parso==0.8.3
203
+ pathspec==0.10.1
204
+ patsy==0.5.3
205
+ pbr==5.11.0
206
+ peewee==3.17.6
207
+ pexpect==4.8.0
208
+ pickleshare==0.7.5
209
+ pillow==10.4.0
210
+ pkgutil_resolve_name==1.3.10
211
+ plac==1.3.5
212
+ platformdirs==2.5.2
213
+ plotly==5.13.0
214
+ preshed==3.0.9
215
+ prettytable==3.5.0
216
+ prometheus-client==0.16.0
217
+ prompt-toolkit==3.0.30
218
+ protobuf==3.20.0
219
+ psutil==5.9.1
220
+ ptyprocess==0.7.0
221
+ pure-eval==0.2.2
222
+ pyarrow==17.0.0
223
+ pyasn1==0.4.8
224
+ pyasn1-modules==0.2.8
225
+ pybind11==2.6.1
226
+ pycodestyle==2.9.1
227
+ pycparser==2.21
228
+ pydantic==2.9.2
229
+ pydantic_core==2.23.4
230
+ pydub==0.25.1
231
+ pyflakes==2.5.0
232
+ Pygments==2.18.0
233
+ pyjnius==1.6.1
234
+ pyknp==0.6.1
235
+ pyparsing==3.0.9
236
+ pyperclip==1.8.2
237
+ pyrsistent==0.19.3
238
+ pyserini==0.22.1
239
+ PySocks==1.7.1
240
+ pyterrier-t5 @ git+https://github.com/terrierteam/pyterrier_t5.git@679e3320b0f7c997de108bc44f66ef15fba72f08
241
+ python-dateutil==2.8.2
242
+ python-json-logger==2.0.7
243
+ python-multipart==0.0.9
244
+ python-terrier==0.10.1
245
+ pytrec-eval-terrier==0.5.6
246
+ pytz==2022.7
247
+ PyYAML==6.0
248
+ pyzmq==23.2.0
249
+ qtconsole==5.4.1
250
+ QtPy==2.3.0
251
+ ray==2.2.0
252
+ recbole==1.1.1
253
+ regex==2022.7.9
254
+ requests==2.32.3
255
+ requests-oauthlib==1.3.1
256
+ responses==0.18.0
257
+ rfc3339-validator==0.1.4
258
+ rfc3986-validator==0.1.1
259
+ rich==13.9.1
260
+ rsa==4.9
261
+ ruff==0.6.1
262
+ safetensors==0.4.3
263
+ scikit-learn==1.1.2
264
+ scipy==1.8.1
265
+ seaborn==0.12.1
266
+ semantic-version==2.10.0
267
+ Send2Trash==1.8.0
268
+ sentence-transformers==3.0.1
269
+ sentencepiece==0.1.96
270
+ shap==0.41.0
271
+ shellingham==1.5.4
272
+ six==1.16.0
273
+ slicer==0.0.7
274
+ smart-open==7.0.4
275
+ sniffio==1.3.0
276
+ soupsieve==2.3.2.post1
277
+ spacy==3.7.5
278
+ spacy-legacy==3.0.12
279
+ spacy-loggers==1.0.5
280
+ SQLAlchemy==1.4.45
281
+ srsly==2.4.8
282
+ stack-data==0.3.0
283
+ starlette==0.38.2
284
+ statsmodels==0.13.5
285
+ stevedore==4.1.1
286
+ sympy==1.12
287
+ TA-Lib==0.4.25
288
+ tabulate==0.9.0
289
+ tenacity==8.1.0
290
+ tensorboard==2.12.1
291
+ tensorboard-data-server==0.7.0
292
+ tensorboard-plugin-wit==1.8.1
293
+ tensorboardX==2.5.1
294
+ tensorflow==2.12.0
295
+ tensorflow-estimator==2.12.0
296
+ tensorflow-io-gcs-filesystem==0.32.0
297
+ termcolor==2.2.0
298
+ terminado==0.17.1
299
+ thinc==8.2.5
300
+ thop==0.1.1.post2209072238
301
+ threadpoolctl==3.1.0
302
+ tiktoken==0.6.0
303
+ tinycss2==1.2.1
304
+ together==1.3.0
305
+ tokenizers==0.19.1
306
+ tomli==2.0.1
307
+ tomlkit==0.12.0
308
+ torch==1.13.1
309
+ torch-cluster==1.6.0
310
+ torch-geometric==2.0.4
311
+ torch-scatter==2.0.9
312
+ torch-sparse==0.6.14
313
+ torch-spline-conv==1.2.1
314
+ torch-tb-profiler==0.4.0
315
+ torchaudio==0.13.1
316
+ torchinfo==1.7.1
317
+ torchsummary==1.5.1
318
+ torchvision==0.14.1
319
+ tornado==6.2
320
+ tqdm==4.66.5
321
+ traitlets==5.3.0
322
+ transformers==4.44.1
323
+ trec-car-tools==2.6
324
+ triton==2.1.0
325
+ typer==0.12.3
326
+ typing_extensions==4.9.0
327
+ typish==1.9.3
328
+ unidic==1.1.0
329
+ unidic-lite==1.0.8
330
+ unlzw3==0.2.2
331
+ urllib3==2.2.2
332
+ uvicorn==0.30.6
333
+ virtualenv==20.18.0
334
+ warc3-wet==0.2.5
335
+ warc3-wet-clueweb09==0.2.5
336
+ wasabi==0.9.1
337
+ wcwidth==0.2.5
338
+ weasel==0.4.1
339
+ webencodings==0.5.1
340
+ websocket-client==1.5.1
341
+ websockets==12.0
342
+ Werkzeug==2.2.2
343
+ wget==3.2
344
+ widgetsnbextension==4.0.11
345
+ wrapt==1.14.1
346
+ xlrd==2.0.1
347
+ xlwt==1.3.0
348
+ xxhash==3.0.0
349
+ yarl==1.13.1
350
+ yfinance==0.2.42
351
+ zipp==3.11.0
352
+ zlib-state==0.1.6
experiments/experiment_with_api_without_personalization.py ADDED
@@ -0,0 +1,665 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+ import os
4
+
5
+ ROOT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../")
6
+ sys.path.append(ROOT_FILE)
7
+ from components.induce_personality import construct_big_five_words
8
+
9
+
10
+ # need to import: gradio
11
+ def install(package, upgrade=False):
12
+ if upgrade:
13
+ subprocess.run(
14
+ [
15
+ sys.executable,
16
+ "-m",
17
+ "pip",
18
+ "install",
19
+ "--upgrade",
20
+ package,
21
+ ],
22
+ check=True,
23
+ )
24
+ else:
25
+ subprocess.run(
26
+ [
27
+ sys.executable,
28
+ "-m",
29
+ "pip",
30
+ "install",
31
+ package,
32
+ ],
33
+ check=True,
34
+ )
35
+
36
+
37
+ # install("ipdb")
38
+ # install("gradio")
39
+ # install("sentence-transformers")
40
+ # install("git+https://github.com/terrierteam/pyterrier_t5.git")
41
+ # install("protobuf")
42
+ # install("transformers", upgrade=True)
43
+ import random
44
+ import json
45
+ import gradio as gr
46
+ import random
47
+ import time
48
+ import ipdb
49
+ import markdown
50
+ import gradio as gr
51
+ import torch
52
+ from transformers import AutoModelForCausalLM, AutoTokenizer
53
+
54
+ from utils import login_to_huggingface, ACCESS
55
+ from components.rewrite_passages import rewrite_rag_context
56
+ from components.query_rewriting import rewrite_query
57
+ from components.chat_conversation import (
58
+ format_message_history,
59
+ format_user_message,
60
+ format_context,
61
+ gradio_to_huggingface_message,
62
+ huggingface_to_gradio_message,
63
+ get_system_instruction,
64
+ prepare_tokenizer,
65
+ format_rag_context,
66
+ conversation_window,
67
+ generate_response,
68
+ )
69
+ from components.constant import (
70
+ ACCESS,
71
+ QUERY_REWRITING,
72
+ RAG,
73
+ PERSONALITY,
74
+ PERSONALITY_LIST,
75
+ REWRITE_PASSAGES,
76
+ NUM_PASSAGES,
77
+ DEVICE,
78
+ RESPONSE_GENERATOR,
79
+ CONV_WINDOW,
80
+ API_URL,
81
+ TEMPLATE_PAYLOAD,
82
+ )
83
+ from components.induce_personality import (
84
+ build_personality_prompt,
85
+ )
86
+
87
+ # LOG_FILE = "log_file_bingzhi_information_seeking.txt"
88
+ LOG_DIR = os.path.join(ROOT_FILE, "log/seperate_preference_elicitation/others/")
89
+ if os.path.exists(LOG_DIR) is False:
90
+ os.makedirs(LOG_DIR)
91
+ STATIC_FILE = os.path.join(ROOT_FILE, "_static")
92
+
93
+ with open(os.path.join(STATIC_FILE, "html/instruction_page.html"), "r") as f:
94
+ INSTRUCTION_PAGE = f.read()
95
+ with open(os.path.join(STATIC_FILE, "html/evaluation_instruction.html"), "r") as f:
96
+ EVALUATION_INSTRUCTION = f.read()
97
+ with open(os.path.join(STATIC_FILE, "html/general_instruction.html"), "r") as f:
98
+ GENERAL_INSTRUCTION = f.read()
99
+ with open(os.path.join(STATIC_FILE, "html/user_narrative.html"), "r") as f:
100
+ USER_NARRATIVE = f.read()
101
+ with open(os.path.join(STATIC_FILE, "html/system_instruction_preference_elicitation.html"), "r") as f:
102
+ PREFERENCE_ELICITATION_TASK = f.read()
103
+ with open(os.path.join(STATIC_FILE, "html/final_evaluation.html"), "r") as f:
104
+ FINAL_EVALUATION = f.read()
105
+ with open(os.path.join(STATIC_FILE, "txt/system_instruction_with_user_persona.txt"), "r") as f:
106
+ SYSTEM_INSTRUCTION = f.read()
107
+ with open(os.path.join(STATIC_FILE, "txt/system_instruction_without_personalization.txt"), "r") as f:
108
+ SYSTEM_INSTRUCTION_WITHOUT_PERSONALIZATION = f.read()
109
+ with open(os.path.join(STATIC_FILE, "txt/system_instruction_preference_elicitation.txt"), "r") as f:
110
+ SYSTEM_INSTRUECTION_PREFERENCE_ELICITATION = f.read()
111
+ with open(os.path.join(STATIC_FILE, "txt/system_summarization_user_preference_elicitation.txt"), "r") as f:
112
+ SUMMARIZATION_PROMPT = f.read()
113
+ FIRST_MESSAGE = "Hey"
114
+ INFORMATION_SEEKING = True
115
+ USER_PREFERENCE_SUMMARY = True
116
+ DEBUG = False
117
+
118
+ # if DEBUG:
119
+ # CONV_WINDOW = 3
120
+
121
+
122
+ def get_context(synthetic_data_path):
123
+ # Load data from the synthetic data file
124
+ with open(synthetic_data_path, "r") as f:
125
+ data = [json.loads(line) for line in f]
126
+
127
+ return data
128
+
129
+
130
+ def add_ticker_prefix(ticker_list, context_list):
131
+ res = []
132
+ for ticker, context in zip(ticker_list, context_list):
133
+ res.append(f"{ticker}: {context}")
134
+ return res
135
+
136
+
137
+ def build_raw_context_list(context_dict):
138
+ return context_dict["data"]
139
+
140
+
141
+ def build_context(context_dict):
142
+ return [build_context_element(context) for context in context_dict["data"]]
143
+
144
+
145
+ def build_context_element(context):
146
+ # [{topic: ex, data: {}}, {..}, ..]
147
+ # Extract information from the context
148
+ ticker = context["ticker"]
149
+ sector = context["sector"]
150
+ business_summary = context["business_summary"]
151
+ name = context["short_name"]
152
+ stock_price = context["price_data"]
153
+ earning = context["earning_summary"]
154
+ beta = context["beta"]
155
+
156
+ # Build the context string
157
+ stock_candidate = f"Stock Candidate: {name}"
158
+ 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}"
159
+
160
+ context_list = [stock_candidate, stock_info]
161
+
162
+ # Combine all parts into a single string
163
+ return "\n".join(context_list)
164
+
165
+
166
+ def get_user_narrative_html(user_narrative):
167
+ return USER_NARRATIVE.replace("{user_narrative}", user_narrative).replace("\n", "<br>")
168
+
169
+
170
+ def get_task_instruction_for_user(context):
171
+ ticker_name = context["short_name"]
172
+ user_narrative = context["user_narrative"]
173
+ user_narrative = user_narrative.replace("\n", "<br>")
174
+ html_user_narrative = markdown.markdown(user_narrative)
175
+ general_instruction = GENERAL_INSTRUCTION
176
+ round_instruction = f"""
177
+ <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;">
178
+ <!-- Stock Information (Bold label, Normal ticker name) -->
179
+ <h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
180
+ Round Info
181
+ </h2>
182
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
183
+ Stock
184
+ </div>
185
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
186
+ <span style="font-weight: bold;">
187
+ This Round's Stock:
188
+ </span>
189
+ {ticker_name}
190
+ </div>
191
+
192
+ <!-- User Narrative (Bold label, Normal narrative) -->
193
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
194
+ User Narrative
195
+ </div>
196
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
197
+ {html_user_narrative}
198
+ </div>
199
+ </div>"""
200
+
201
+ return general_instruction, round_instruction
202
+
203
+
204
+ def display_system_instruction_with_html(
205
+ system_instruction,
206
+ ):
207
+ html_system_instruction = f"""
208
+ <p style="text-align: left; margin-bottom: 10px;">
209
+ {system_instruction}
210
+ </p>
211
+ """
212
+ return html_system_instruction
213
+
214
+
215
+ def log_action(tab_name, action, details):
216
+ """
217
+ Log actions for each tab (stock).
218
+ """
219
+ log_file = os.path.join(LOG_DIR, f"{tab_name}.txt")
220
+ with open(log_file, "a") as f:
221
+ f.write(f"Action: {action} | Details: {details}\n")
222
+
223
+
224
+ def create_demo(
225
+ terminator,
226
+ system_description_without_context,
227
+ stock_context_list,
228
+ raw_context_list,
229
+ ):
230
+ # Store the history here and use this as an input to each tab.
231
+ tab_data = {}
232
+
233
+ def tab_creation_exploration_stage(order):
234
+ comp, context, general_instruction, round_instruction = get_context(order)
235
+ system_instruction = system_description_without_context + "\n" + context
236
+ tab_data[comp] = {"history": [], "selection": "", "reason": ""}
237
+ english_order = ["1", "2", "3", "4", "5"]
238
+ # with gr.Tab(f"{english_order[order]}: {comp}") as tab:
239
+ with gr.Tab(f"{english_order[order]}-1:Discuss"):
240
+ gr.HTML(value=general_instruction, label="General Instruction")
241
+ with gr.Row():
242
+ with gr.Column():
243
+ with gr.Row():
244
+ gr.HTML(
245
+ value=round_instruction,
246
+ label="Round Instruction",
247
+ )
248
+ with gr.Column():
249
+ with gr.Row():
250
+ chatbot = gr.Chatbot(height=600)
251
+ with gr.Row():
252
+ start_conversation = gr.Button(value="Start Conversation")
253
+ with gr.Row():
254
+ msg = gr.Textbox(scale=1, label="User Input")
255
+ with gr.Row():
256
+ msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
257
+ continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
258
+ with gr.Row():
259
+ clear = gr.ClearButton([msg, chatbot])
260
+ if DEBUG:
261
+ with gr.Row():
262
+ display_prompt = gr.HTML(
263
+ value=display_system_instruction_with_html(system_instruction),
264
+ label="System Instruction",
265
+ )
266
+ with gr.Tab(f"{english_order[order]}-2:Eval"):
267
+ with gr.Row():
268
+ gr.HTML(value=EVALUATION_INSTRUCTION)
269
+ with gr.Row():
270
+ dropdown = gr.Dropdown(
271
+ label="Would you like to purchase the stock?",
272
+ choices=["Yes", "No"],
273
+ show_label=True,
274
+ )
275
+ reason = gr.Textbox(
276
+ scale=1,
277
+ label="Reason for Your Choice (Explain Your Reasoning & Highlight Useful Parts of Conversation)",
278
+ lines=5,
279
+ )
280
+ with gr.Row():
281
+ trust = gr.Slider(
282
+ label="Trust",
283
+ minimum=1,
284
+ maximum=100,
285
+ value=50,
286
+ info="How much do you trust the financial advisor? Answer from 1 to 100. A score of 100 means you have complete trust in the financial advisor, while a score of 1 means you have no trust at all.",
287
+ step=1,
288
+ )
289
+ satisfaction = gr.Slider(
290
+ label="Satisfaction",
291
+ minimum=1,
292
+ maximum=100,
293
+ value=50,
294
+ info="How satisfied are you with the financial advisor? Answer from 1 to 100. A score of 100 means you are completely satisfied, while a score of 1 means you are not satisfied at all.",
295
+ step=1,
296
+ )
297
+ with gr.Row():
298
+ knowledgeable = gr.Slider(
299
+ label="Knowledgeable",
300
+ minimum=1,
301
+ maximum=100,
302
+ value=50,
303
+ info="How knowledgeable do you feel after interacting with the financial advisor? Answer from 1 to 100. A score of 100 means you feel very knowledgeable, while a score of 1 means you feel not knowledgeable at all.",
304
+ step=1,
305
+ )
306
+ helpful = gr.Slider(
307
+ label="Helpful",
308
+ minimum=1,
309
+ maximum=100,
310
+ value=50,
311
+ info="How helpful do you find the financial advisor? Answer from 1 to 100. A score of 100 means you find the financial advisor very helpful, while a score of 1 means you find the financial advisor not helpful at all.",
312
+ step=1,
313
+ )
314
+ evaluation_send_button = gr.Button(value="Send: Evaluation")
315
+ return {
316
+ "comp": comp,
317
+ "system_instruction": system_instruction,
318
+ "start_conversation": start_conversation,
319
+ "msg_button": msg_button,
320
+ "continue_button": continue_button,
321
+ "chatbot": chatbot,
322
+ "msg": msg,
323
+ "dropdown": dropdown,
324
+ "reason": reason,
325
+ "trust": trust,
326
+ "satisfaction": satisfaction,
327
+ "knowledgeable": knowledgeable,
328
+ "helpful": helpful,
329
+ "evaluation_send_button": evaluation_send_button,
330
+ }
331
+
332
+ def tab_final_evaluation(first_comp, second_comp, third_comp, fourth_comp, fifth_comp):
333
+ with gr.Row():
334
+ gr.HTML(value=FINAL_EVALUATION)
335
+ with gr.Row():
336
+ ranking_first_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{first_comp}")
337
+ ranking_second_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{second_comp}")
338
+ ranking_third_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{third_comp}")
339
+ ranking_fourth_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{fourth_comp}")
340
+ ranking_fifth_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{fifth_comp}")
341
+ with gr.Row():
342
+ textbox = gr.HTML(
343
+ """<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
344
+ <strong>Please rank the stocks from 1 to 5, where 1 is the most preferred and 5 is the least preferred.</strong>
345
+ <br>
346
+ <strong>Make sure to assign different scores to different stocks.</strong>
347
+ </div>"""
348
+ )
349
+ submit_ranking = gr.Button(value="Submit Ranking")
350
+ return {
351
+ "first": {"comp": first_comp, "ranking_first_comp": ranking_first_comp},
352
+ "second": {"comp": second_comp, "ranking_second_comp": ranking_second_comp},
353
+ "third": {"comp": third_comp, "ranking_third_comp": ranking_third_comp},
354
+ "fourth": {"comp": fourth_comp, "ranking_fourth_comp": ranking_fourth_comp},
355
+ "fifth": {"comp": fifth_comp, "ranking_fifth_comp": ranking_fifth_comp},
356
+ "submit_ranking": submit_ranking,
357
+ "text_box": textbox,
358
+ }
359
+
360
+ def click_control_exploration_stage(tabs):
361
+ (
362
+ comp,
363
+ system_instruction,
364
+ start_conversation,
365
+ msg_button,
366
+ continue_button,
367
+ chatbot,
368
+ msg,
369
+ dropdown,
370
+ reason,
371
+ trust,
372
+ satisfaction,
373
+ knowledgeable,
374
+ helpful,
375
+ evaluation_send_button,
376
+ ) = (
377
+ tabs["comp"],
378
+ tabs["system_instruction"],
379
+ tabs["start_conversation"],
380
+ tabs["msg_button"],
381
+ tabs["continue_button"],
382
+ tabs["chatbot"],
383
+ tabs["msg"],
384
+ tabs["dropdown"],
385
+ tabs["reason"],
386
+ tabs["trust"],
387
+ tabs["satisfaction"],
388
+ tabs["knowledgeable"],
389
+ tabs["helpful"],
390
+ tabs["evaluation_send_button"],
391
+ )
392
+ start_conversation.click(
393
+ lambda history: respond_start_conversation(history, system_instruction, comp),
394
+ [chatbot],
395
+ [chatbot, start_conversation, msg_button, continue_button],
396
+ )
397
+ msg_button.click(
398
+ lambda message, history: respond(message, tab_data[comp]["history"], system_instruction, comp),
399
+ [msg, chatbot],
400
+ [msg, chatbot],
401
+ )
402
+ continue_button.click(
403
+ lambda history: respond_continue(tab_data[comp]["history"], system_instruction, comp),
404
+ [chatbot],
405
+ [chatbot],
406
+ )
407
+ evaluation_send_button.click(
408
+ lambda dropdown, reason, trust, satisfaction, knowledgeable, helpful: respond_evaluation(
409
+ {
410
+ "selection": dropdown,
411
+ "reason": reason,
412
+ "trust": trust,
413
+ "satisfaction": satisfaction,
414
+ "knowledgeable": knowledgeable,
415
+ "helpful": helpful,
416
+ },
417
+ comp,
418
+ ),
419
+ [dropdown, reason, trust, satisfaction, knowledgeable, helpful],
420
+ [dropdown, reason, trust, satisfaction, knowledgeable, helpful],
421
+ )
422
+
423
+ def click_control_final_evaluation(tabs):
424
+ first_comp, ranking_first_comp = tabs["first"]["comp"], tabs["first"]["ranking_first_comp"]
425
+ second_comp, ranking_second_comp = tabs["second"]["comp"], tabs["second"]["ranking_second_comp"]
426
+ third_comp, ranking_third_comp = tabs["third"]["comp"], tabs["third"]["ranking_third_comp"]
427
+ fourth_comp, ranking_fourth_comp = tabs["fourth"]["comp"], tabs["fourth"]["ranking_fourth_comp"]
428
+ fifth_comp, ranking_fifth_comp = tabs["fifth"]["comp"], tabs["fifth"]["ranking_fifth_comp"]
429
+ result_textbox = tabs["text_box"]
430
+ submit_ranking = tabs["submit_ranking"]
431
+ submit_ranking.click(
432
+ lambda ranking_first_comp, ranking_second_comp, ranking_third_comp, ranking_fourth_comp, ranking_fifth_comp: respond_final_ranking(
433
+ first_comp,
434
+ ranking_first_comp,
435
+ second_comp,
436
+ ranking_second_comp,
437
+ third_comp,
438
+ ranking_third_comp,
439
+ fourth_comp,
440
+ ranking_fourth_comp,
441
+ fifth_comp,
442
+ ranking_fifth_comp,
443
+ ),
444
+ # Input components (names and rankings)
445
+ [
446
+ ranking_first_comp,
447
+ ranking_second_comp,
448
+ ranking_third_comp,
449
+ ranking_fourth_comp,
450
+ ranking_fifth_comp,
451
+ ],
452
+ # Output component(s) where you want the result to appear, e.g., result_textbox
453
+ [result_textbox],
454
+ )
455
+
456
+ def respond(message, history, system_instruction, tab_name=None):
457
+ """
458
+ Return:
459
+ msg
460
+ chat_history
461
+ retrieved_passage
462
+ rewritten_query
463
+
464
+ """
465
+ assert (
466
+ tab_name is not None
467
+ ), "Tab name is required for the start of the conversation unless it is not preference elicitation."
468
+ # Formatting Input
469
+ print(f"User Message: {message} in Tab: {tab_name}")
470
+ # From string to list [{"role":"user", "content": message}, ...]
471
+ history = gradio_to_huggingface_message(history)
472
+ # We can implement context window here as we need all the system interaction. We can cut some of the early interactions if needed.
473
+ history = conversation_window(history, CONV_WINDOW)
474
+ print(f"History Length: {len(history)}")
475
+ print(f"History: {history}")
476
+ # Add system instruction to the history
477
+ history = format_context(system_instruction, history)
478
+ # Add user message to the history
479
+ history_with_user_utterance = format_user_message(message, history)
480
+ # Call API instead of locally handle it
481
+ outputs_text, history = generate_response(history_with_user_utterance, terminator, 128, API_URL)
482
+ # exclude system interaction and store the others in the history
483
+ history = huggingface_to_gradio_message(history)
484
+ if tab_name is not None:
485
+ print(f"Tab: {tab_name}\nSystem Output: {outputs_text}")
486
+
487
+ # Log the user message and response
488
+ log_action(tab_name, "User Message", message)
489
+ log_action(tab_name, "Response", outputs_text)
490
+ # Store the updated history for this tab
491
+ tab_data[tab_name]["history"] = history
492
+
493
+ return "", history
494
+
495
+ def respond_start_conversation(history, system_instruction, tab_name=None):
496
+ assert (
497
+ tab_name is not None
498
+ ), "Tab name is required for the start of the conversation unless it is not preference elicitation."
499
+ print(f"Tab: {tab_name}\nSystem Instruction:{system_instruction}")
500
+ history = gradio_to_huggingface_message(history)
501
+ history = format_context(system_instruction, history)
502
+ first_message = FIRST_MESSAGE
503
+ history_with_user_utterance = format_user_message(first_message, history)
504
+ outputs_text, history = generate_response(history_with_user_utterance, terminator, 128, API_URL)
505
+ # Format
506
+ history = huggingface_to_gradio_message(history)
507
+ if tab_name is not None:
508
+ print(f"Tab: {tab_name}\nHistory: {history}")
509
+
510
+ # Log the user message and response
511
+ log_action(tab_name, "User Message", first_message)
512
+ log_action(tab_name, "Response", outputs_text)
513
+ # Store the updated history for this tab
514
+ tab_data[tab_name]["history"] = history
515
+
516
+ return (
517
+ history,
518
+ gr.Button(value="Start Conversation", interactive=False),
519
+ gr.Button(value="Send This Message to Advisor", interactive=True),
520
+ gr.Button(value="Show More of the Advisor’s Answer", interactive=True),
521
+ )
522
+
523
+ def respond_continue(history, system_instruction, tab_name=None):
524
+ assert tab_name is not None, "Tab name is required for the start of the conversation."
525
+ # print(f"Tab: {tab_name}\nSystem Instruction:{system_instruction}")
526
+ message = "continue"
527
+ history = gradio_to_huggingface_message(history)
528
+ history = conversation_window(history, CONV_WINDOW)
529
+ history = format_context(system_instruction, history)
530
+ history_with_user_utterance = format_user_message(message, history)
531
+ outputs_text, history = generate_response(history_with_user_utterance, terminator, 128, API_URL)
532
+ history = huggingface_to_gradio_message(history)
533
+ if tab_name is not None:
534
+ log_action(tab_name, "Show More of the Advisor’s Answer", "User continued the conversation")
535
+ log_action(tab_name, "Response", outputs_text)
536
+
537
+ # Update history for this tab
538
+ tab_data[tab_name]["history"] = history
539
+ return history
540
+
541
+ def respond_evaluation(evals, tab_name):
542
+
543
+ # dropdown, readon_button, multi-evaluator
544
+ log_action(tab_name, "Round Evaluation", "Following")
545
+ for key, value in evals.items():
546
+ log_action(tab_name, key, value)
547
+ # Store the reason for this tab
548
+ tab_data[tab_name]["multi_evaluator"] = evals
549
+ return (
550
+ evals["selection"],
551
+ evals["reason"],
552
+ evals["trust"],
553
+ evals["satisfaction"],
554
+ evals["knowledgeable"],
555
+ evals["helpful"],
556
+ )
557
+
558
+ def respond_final_ranking(
559
+ first_comp,
560
+ ranking_first_comp,
561
+ second_comp,
562
+ ranking_second_comp,
563
+ third_comp,
564
+ ranking_third_comp,
565
+ fourth_comp,
566
+ ranking_fourth_comp,
567
+ fifth_comp,
568
+ ranking_fifth_comp,
569
+ ):
570
+ # make sure that they are not the same
571
+ ranking_list = [
572
+ ranking_first_comp,
573
+ ranking_second_comp,
574
+ ranking_third_comp,
575
+ ranking_fourth_comp,
576
+ ranking_fifth_comp,
577
+ ]
578
+ if len(set(ranking_list)) != len(ranking_list):
579
+ return """<div style="background-color: #fff3cd; color: #856404; padding: 15px; border: 1px solid #ffeeba; border-radius: 5px; margin-bottom: 20px;">
580
+ <strong>Please make sure that you are not ranking the same stock multiple times.</strong>
581
+ </div>"""
582
+ else:
583
+ log_action("Final_Ranking", first_comp, ranking_first_comp)
584
+ log_action("Final_Ranking", second_comp, ranking_second_comp)
585
+ log_action("Final_Ranking", third_comp, ranking_third_comp)
586
+ log_action("Final_Ranking", fourth_comp, ranking_fourth_comp)
587
+ log_action("Final_Ranking", fifth_comp, ranking_fifth_comp)
588
+ return """<div style="background-color: #d4edda; color: #155724; padding: 15px; border: 1px solid #c3e6cb; border-radius: 5px; margin-bottom: 20px;">
589
+ <strong>Thank you for participating in the experiment. This concludes the session. You may now close the tab.</strong>
590
+ </div>"""
591
+
592
+ def get_context(index):
593
+ comp = raw_context_list[index]["short_name"]
594
+ context = stock_context_list[index]
595
+ general_instruction, round_instruction = get_task_instruction_for_user(raw_context_list[index])
596
+ return comp, context, general_instruction, round_instruction
597
+
598
+ with gr.Blocks(title="RAG Chatbot Q&A", theme="Soft") as demo:
599
+ first_comp, first_context, first_general_instruction, first_round_instruction = get_context(0)
600
+ second_comp, second_context, second_general_instruction, second_round_instruction = get_context(1)
601
+ third_comp, third_context, third_general_instruction, third_round_instruction = get_context(2)
602
+ fourth_comp, fourth_context, forth_general_instruction, forth_round_instruction = get_context(3)
603
+ fifth_comp, fifth_context, fifth_general_instruction, fifth_round_instruction = get_context(4)
604
+ user_narrative = markdown.markdown(raw_context_list[0]["user_narrative"].replace("\n", "<br>"))
605
+
606
+ # # initialize tab data
607
+ for comp in [first_comp, second_comp, third_comp, fourth_comp, fifth_comp]:
608
+ tab_data[comp] = {"history": [], "selection": "", "reason": ""}
609
+
610
+ # EXperiment Instruction
611
+ with gr.Tab("Experiment Instruction") as instruction_tab:
612
+ gr.HTML(value=INSTRUCTION_PAGE, label="Experiment Instruction")
613
+ # Financial decision making stage
614
+ with gr.Tab("Financial Decision Stage"):
615
+ # Experiment Tag
616
+ first_tab = tab_creation_exploration_stage(0)
617
+ click_control_exploration_stage(first_tab)
618
+ second_tab = tab_creation_exploration_stage(1)
619
+ click_control_exploration_stage(second_tab)
620
+ third_tab = tab_creation_exploration_stage(2)
621
+ click_control_exploration_stage(third_tab)
622
+ fourth_tab = tab_creation_exploration_stage(3)
623
+ click_control_exploration_stage(fourth_tab)
624
+ fifth_tab = tab_creation_exploration_stage(4)
625
+ click_control_exploration_stage(fifth_tab)
626
+ with gr.Tab("Final Evaluation Stage") as final_evaluation:
627
+ final_evaluation_tab = tab_final_evaluation(first_comp, second_comp, third_comp, fourth_comp, fifth_comp)
628
+ click_control_final_evaluation(final_evaluation_tab)
629
+
630
+ return demo
631
+
632
+
633
+ if __name__ == "__main__":
634
+ login_to_huggingface(ACCESS)
635
+
636
+ file_path = os.path.join(ROOT_FILE, "./data/single_stock_data/single_stock_demo.jsonl")
637
+ context_info = get_context(file_path) # str to List of Dict
638
+ # For Demo Usage, just use the first dict
639
+ context_info = context_info[0]
640
+ stock_context_list = build_context(context_info) # List of str
641
+ raw_context_list = build_raw_context_list(context_info) # List of str
642
+ # system instruction consist of Task, Personality, and Context
643
+ """
644
+ Personality
645
+ ["extroverted", "introverted"]
646
+ ["agreeable", "antagonistic"]
647
+ ["conscientious", "unconscientious"]
648
+ ["neurotic", "emotionally stable"]
649
+ ["open to experience", "closed to experience"]]
650
+ """
651
+
652
+ personality = [
653
+ "extroverted",
654
+ "agreeable",
655
+ "conscientious",
656
+ "emotionally stable",
657
+ "open to experience",
658
+ ]
659
+
660
+ personality_prompt = build_personality_prompt(personality)
661
+ system_instruction_without_context = SYSTEM_INSTRUCTION_WITHOUT_PERSONALIZATION + "\n" + personality_prompt + "\n"
662
+ tokenizer = AutoTokenizer.from_pretrained(RESPONSE_GENERATOR)
663
+ tokenizer, terminator = prepare_tokenizer(tokenizer)
664
+ demo = create_demo(terminator, system_instruction_without_context, stock_context_list, raw_context_list)
665
+ demo.launch(share=True)
experiments/personality_simulation.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import ipdb
3
+ import itertools
4
+ import torch
5
+ from transformers import AutoModelForCausalLM, AutoTokenizer
6
+ from tqdm import tqdm
7
+ import json
8
+
9
+ from utils import login_to_huggingface, ACCESS
10
+ from components.rag_components import rag, retrieve_passage, response_generation
11
+ from components.rewrite_passages import rewrite_rag_context
12
+ from components.query_rewriting import rewrite_query
13
+ from components.chat_conversation import format_message_history, format_user_message, format_context, gradio_to_huggingface_message, huggingface_to_gradio_message, get_system_instruction, prepare_tokenizer, format_rag_context
14
+ from components.constant import ACCESS, QUERY_REWRITING, RAG, DEVICE, RESPONSE_GENERATOR, NUM_PASSAGES
15
+ from components.prompt import SYSTEM_INSTRUCTION, RAG_INSTRUCTION, PERSONALITY_INSTRUCTION
16
+ from components.induce_personality import construct_big_five_words
17
+
18
+
19
+ def get_conversation_hitory(persona_type, user_predefined_message, tokenizer, model, terminator):
20
+ # Output: conversation history {"role": "user", "content": "message"}
21
+ assert len(user_predefined_message) >= 1, "User message should be at least one"
22
+ system_instruction = get_system_instruction(rag=RAG, personality_list=persona_type)
23
+ messages = [{"role": "system", "content": system_instruction}]
24
+ for user_message in user_predefined_message:
25
+ if QUERY_REWRITING:
26
+ str_history = format_message_history(user_message, messages)
27
+ resolved_query = rewrite_query(user_message, str_history, model, tokenizer, terminator, device=DEVICE)
28
+ else:
29
+ resolved_query = user_message
30
+ messages = format_user_message(resolved_query, messages)
31
+ # TODO implement rag function as this will be important later
32
+ _, messages = response_generation(messages, model, tokenizer, device=DEVICE, terminators=terminator)
33
+ return messages
34
+
35
+
36
+ def store_conversation_to_text(filename, conversation):
37
+ with open(filename, "w") as file:
38
+ for turn in conversation:
39
+ file.write(f"{turn['role']}: {turn['content']}\n")
40
+ file.write("\n") # Add a newline at the end of the conversation
41
+
42
+
43
+ if __name__ == "__main__":
44
+ output_par_dir = "./output/personality_output"
45
+ personality_types = [["extroverted", "introverted"], ["agreeable", "antagonistic"], ["conscientious", "unconscientious"], ["neurotic", "emotionally stable"], ["open to experience", "closed to experience"]]
46
+ # load case
47
+ with open("user_predefined_queries.json", "r") as file:
48
+ user_q = json.load(file)
49
+ tokenizer = AutoTokenizer.from_pretrained(RESPONSE_GENERATOR)
50
+ tokenizer, terminator = prepare_tokenizer(tokenizer)
51
+ model = AutoModelForCausalLM.from_pretrained(RESPONSE_GENERATOR, torch_dtype=torch.float16, pad_token_id=tokenizer.eos_token_id).to(DEVICE)
52
+ for case_name, user_predefined_message in user_q.items():
53
+ for persona_type in tqdm(itertools.product(*personality_types)):
54
+ conv_hist = get_conversation_hitory(persona_type, user_predefined_message, tokenizer, model, terminator)
55
+ save_file_name = "_".join(persona_type) + ".txt"
56
+ output_dir = os.path.join(output_par_dir, case_name)
57
+ if not os.path.exists(output_dir):
58
+ os.makedirs(output_dir, exist_ok=True)
59
+ save_file_path = os.path.join(output_dir, save_file_name)
60
+ store_conversation_to_text(save_file_path, conv_hist)
experiments/separate_preference_elicitation_and_interaction.py ADDED
@@ -0,0 +1,851 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+ import os
4
+
5
+ ROOT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../")
6
+ sys.path.append(ROOT_FILE)
7
+ from components.induce_personality import construct_big_five_words
8
+
9
+
10
+ # need to import: gradio
11
+ def install(package, upgrade=False):
12
+ if upgrade:
13
+ subprocess.run(
14
+ [
15
+ sys.executable,
16
+ "-m",
17
+ "pip",
18
+ "install",
19
+ "--upgrade",
20
+ package,
21
+ ],
22
+ check=True,
23
+ )
24
+ else:
25
+ subprocess.run(
26
+ [
27
+ sys.executable,
28
+ "-m",
29
+ "pip",
30
+ "install",
31
+ package,
32
+ ],
33
+ check=True,
34
+ )
35
+
36
+
37
+ # install("ipdb")
38
+ # install("gradio")
39
+ # install("sentence-transformers")
40
+ # install("git+https://github.com/terrierteam/pyterrier_t5.git")
41
+ # install("protobuf")
42
+ # install("transformers", upgrade=True)
43
+ import random
44
+ import json
45
+ import gradio as gr
46
+ import random
47
+ import time
48
+ import ipdb
49
+ import markdown
50
+ import gradio as gr
51
+ import torch
52
+ from transformers import AutoModelForCausalLM, AutoTokenizer
53
+
54
+ from utils import login_to_huggingface, ACCESS
55
+ from components.rag_components import (
56
+ rag,
57
+ retrieve_passage,
58
+ response_generation,
59
+ )
60
+ from components.rewrite_passages import rewrite_rag_context
61
+ from components.query_rewriting import rewrite_query
62
+ from components.chat_conversation import (
63
+ format_message_history,
64
+ format_user_message,
65
+ format_context,
66
+ gradio_to_huggingface_message,
67
+ huggingface_to_gradio_message,
68
+ get_system_instruction,
69
+ prepare_tokenizer,
70
+ format_rag_context,
71
+ conversation_window,
72
+ )
73
+ from components.constant import (
74
+ ACCESS,
75
+ QUERY_REWRITING,
76
+ RAG,
77
+ PERSONALITY,
78
+ PERSONALITY_LIST,
79
+ REWRITE_PASSAGES,
80
+ NUM_PASSAGES,
81
+ DEVICE,
82
+ RESPONSE_GENERATOR,
83
+ CONV_WINDOW,
84
+ )
85
+ from components.induce_personality import (
86
+ build_personality_prompt,
87
+ )
88
+
89
+ # LOG_FILE = "log_file_bingzhi_information_seeking.txt"
90
+ LOG_DIR = os.path.join(ROOT_FILE, "log/seperate_preference_elicitation/others/")
91
+ if os.path.exists(LOG_DIR) is False:
92
+ os.makedirs(LOG_DIR)
93
+ STATIC_FILE = os.path.join(ROOT_FILE, "_static")
94
+
95
+ with open(os.path.join(STATIC_FILE, "html/instruction_page.html"), "r") as f:
96
+ INSTRUCTION_PAGE = f.read()
97
+ with open(os.path.join(STATIC_FILE, "html/evaluation_instruction.html"), "r") as f:
98
+ EVALUATION_INSTRUCTION = f.read()
99
+ with open(os.path.join(STATIC_FILE, "html/general_instruction.html"), "r") as f:
100
+ GENERAL_INSTRUCTION = f.read()
101
+ with open(os.path.join(STATIC_FILE, "html/user_narrative.html"), "r") as f:
102
+ USER_NARRATIVE = f.read()
103
+ with open(os.path.join(STATIC_FILE, "html/system_instruction_preference_elicitation.html"), "r") as f:
104
+ PREFERENCE_ELICITATION_TASK = f.read()
105
+ with open(os.path.join(STATIC_FILE, "html/final_evaluation.html"), "r") as f:
106
+ FINAL_EVALUATION = f.read()
107
+ with open(os.path.join(STATIC_FILE, "txt/system_instruction_with_user_persona.txt"), "r") as f:
108
+ SYSTEM_INSTRUCTION = f.read()
109
+ with open(os.path.join(STATIC_FILE, "txt/system_instruction_preference_elicitation.txt"), "r") as f:
110
+ SYSTEM_INSTRUECTION_PREFERENCE_ELICITATION = f.read()
111
+ with open(os.path.join(STATIC_FILE, "txt/system_summarization_user_preference_elicitation.txt"), "r") as f:
112
+ SUMMARIZATION_PROMPT = f.read()
113
+ FIRST_MESSAGE = "Hey"
114
+ INFORMATION_SEEKING = True
115
+ USER_PREFERENCE_SUMMARY = True
116
+ DEBUG = True
117
+ # if DEBUG:
118
+ # CONV_WINDOW = 3
119
+
120
+
121
+ def get_context(synthetic_data_path):
122
+ # Load data from the synthetic data file
123
+ with open(synthetic_data_path, "r") as f:
124
+ data = [json.loads(line) for line in f]
125
+
126
+ return data
127
+
128
+
129
+ def add_ticker_prefix(ticker_list, context_list):
130
+ res = []
131
+ for ticker, context in zip(ticker_list, context_list):
132
+ res.append(f"{ticker}: {context}")
133
+ return res
134
+
135
+
136
+ def build_raw_context_list(context_dict):
137
+ return context_dict["data"]
138
+
139
+
140
+ def build_context(context_dict):
141
+ return [build_context_element(context) for context in context_dict["data"]]
142
+
143
+
144
+ def build_context_element(context):
145
+ # [{topic: ex, data: {}}, {..}, ..]
146
+ # Extract information from the context
147
+ ticker = context["ticker"]
148
+ sector = context["sector"]
149
+ business_summary = context["business_summary"]
150
+ name = context["short_name"]
151
+ stock_price = context["price_data"]
152
+ earning = context["earning_summary"]
153
+ beta = context["beta"]
154
+
155
+ # Build the context string
156
+ stock_candidate = f"Stock Candidate: {name}"
157
+ 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}"
158
+
159
+ context_list = [stock_candidate, stock_info]
160
+
161
+ # Combine all parts into a single string
162
+ return "\n".join(context_list)
163
+
164
+
165
+ def get_user_narrative_html(user_narrative):
166
+ return USER_NARRATIVE.replace("{user_narrative}", user_narrative).replace("\n", "<br>")
167
+
168
+
169
+ def get_task_instruction_for_user(context):
170
+ ticker_name = context["short_name"]
171
+ user_narrative = context["user_narrative"]
172
+ user_narrative = user_narrative.replace("\n", "<br>")
173
+ html_user_narrative = markdown.markdown(user_narrative)
174
+ general_instruction = GENERAL_INSTRUCTION
175
+ round_instruction = f"""
176
+ <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;">
177
+ <!-- Stock Information (Bold label, Normal ticker name) -->
178
+ <h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
179
+ Round Info
180
+ </h2>
181
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
182
+ Stock
183
+ </div>
184
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
185
+ <span style="font-weight: bold;">
186
+ This Round's Stock:
187
+ </span>
188
+ {ticker_name}
189
+ </div>
190
+
191
+ <!-- User Narrative (Bold label, Normal narrative) -->
192
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
193
+ User Narrative
194
+ </div>
195
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
196
+ {html_user_narrative}
197
+ </div>
198
+ </div>"""
199
+
200
+ return general_instruction, round_instruction
201
+
202
+
203
+ def display_system_instruction_with_html(
204
+ system_instruction,
205
+ ):
206
+ html_system_instruction = f"""
207
+ <p style="text-align: left; margin-bottom: 10px;">
208
+ {system_instruction}
209
+ </p>
210
+ """
211
+ return html_system_instruction
212
+
213
+
214
+ def log_action(tab_name, action, details):
215
+ """
216
+ Log actions for each tab (stock).
217
+ """
218
+ log_file = os.path.join(LOG_DIR, f"{tab_name}.txt")
219
+ with open(log_file, "a") as f:
220
+ f.write(f"Action: {action} | Details: {details}\n")
221
+
222
+
223
+ def add_user_profile_to_system_instruction(
224
+ system_instruction, user_preference_elicitation_data, summary, model, terminator
225
+ ):
226
+ if summary:
227
+ if user_preference_elicitation_data["summary_history"] == "":
228
+ # Format prompt
229
+ summarization_prompt = SUMMARIZATION_PROMPT + "\nPrevious Conversations: {}".format(
230
+ user_preference_elicitation_data["history"]
231
+ )
232
+ summarization_instruction = [{"role": "system", "content": summarization_prompt}]
233
+ summ, _ = response_generation(
234
+ summarization_instruction,
235
+ model,
236
+ tokenizer,
237
+ max_tokens=512,
238
+ device=DEVICE,
239
+ terminators=terminator,
240
+ )
241
+ user_preference_elicitation_data["summary_history"] = summ
242
+ log_action("Prompt", "Preference Elicitation Summarization", summ)
243
+ print(f"Preference Summary:{summ}")
244
+ system_instruction += f"\nPrevious Conversations with the Customer about the User Profile: {user_preference_elicitation_data['summary_history']}\n"
245
+ else:
246
+ system_instruction += f"\nPrevious Conversations with the Customer about the User Profile: {user_preference_elicitation_data['history']}\n"
247
+ return system_instruction
248
+
249
+
250
+ def create_demo(
251
+ model,
252
+ tokenizer,
253
+ terminator,
254
+ system_description_without_context,
255
+ stock_context_list,
256
+ raw_context_list,
257
+ ):
258
+ # Store the history here and use this as an input to each tab.
259
+ tab_data = {}
260
+ user_preference_elicitation_data = {"history": "", "summary_history": ""}
261
+
262
+ if DEBUG:
263
+ user_preference_elicitation_data[
264
+ "summary_history"
265
+ ] = """Previous Conversations with the Customer about the User Profile: Based on our previous conversation, here's a summary of your investment preferences:
266
+
267
+ 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.
268
+ 2. **Value vs. Growth Stocks:** You prefer growth stocks, which have the potential for high returns but may be riskier.
269
+ 3. **Dividend vs. Non-Dividend Stocks:** You're open to both dividend and non-dividend growth stocks, focusing on reinvesting profits for future growth.
270
+ 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."""
271
+
272
+ def tab_creation_exploration_stage(order):
273
+ comp, context, general_instruction, round_instruction = get_context(order)
274
+ system_instruction = system_description_without_context + "\n" + context
275
+ tab_data[comp] = {"history": [], "selection": "", "reason": ""}
276
+ english_order = ["1", "2", "3", "4", "5"]
277
+ # with gr.Tab(f"{english_order[order]}: {comp}") as tab:
278
+ with gr.Tab(f"{english_order[order]}-1:Discuss"):
279
+ gr.HTML(value=general_instruction, label="General Instruction")
280
+ with gr.Row():
281
+ with gr.Column():
282
+ with gr.Row():
283
+ gr.HTML(
284
+ value=round_instruction,
285
+ label="Round Instruction",
286
+ )
287
+ with gr.Column():
288
+ with gr.Row():
289
+ chatbot = gr.Chatbot(height=600)
290
+ with gr.Row():
291
+ start_conversation = gr.Button(value="Start Conversation")
292
+ with gr.Row():
293
+ msg = gr.Textbox(scale=1, label="User Input")
294
+ with gr.Row():
295
+ msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
296
+ continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
297
+ with gr.Row():
298
+ clear = gr.ClearButton([msg, chatbot])
299
+ if DEBUG:
300
+ with gr.Row():
301
+ display_prompt = gr.HTML(
302
+ value=display_system_instruction_with_html(system_instruction),
303
+ label="System Instruction",
304
+ )
305
+ with gr.Tab(f"{english_order[order]}-2:Eval"):
306
+ with gr.Row():
307
+ gr.HTML(value=EVALUATION_INSTRUCTION)
308
+ with gr.Row():
309
+ dropdown = gr.Dropdown(
310
+ label="Would you like to purchase the stock?",
311
+ choices=["Yes", "No"],
312
+ show_label=True,
313
+ )
314
+ reason = gr.Textbox(
315
+ scale=1,
316
+ label="Reason for Your Choice (Explain Your Reasoning & Highlight Useful Parts of Conversation)",
317
+ lines=5,
318
+ )
319
+ with gr.Row():
320
+ trust = gr.Slider(
321
+ label="Trust",
322
+ minimum=1,
323
+ maximum=100,
324
+ value=50,
325
+ info="How much do you trust the financial advisor? Answer from 1 to 100. A score of 100 means you have complete trust in the financial advisor, while a score of 1 means you have no trust at all.",
326
+ step=1,
327
+ )
328
+ satisfaction = gr.Slider(
329
+ label="Satisfaction",
330
+ minimum=1,
331
+ maximum=100,
332
+ value=50,
333
+ info="How satisfied are you with the financial advisor? Answer from 1 to 100. A score of 100 means you are completely satisfied, while a score of 1 means you are not satisfied at all.",
334
+ step=1,
335
+ )
336
+ with gr.Row():
337
+ knowledgeable = gr.Slider(
338
+ label="Knowledgeable",
339
+ minimum=1,
340
+ maximum=100,
341
+ value=50,
342
+ info="How knowledgeable do you feel after interacting with the financial advisor? Answer from 1 to 100. A score of 100 means you feel very knowledgeable, while a score of 1 means you feel not knowledgeable at all.",
343
+ step=1,
344
+ )
345
+ helpful = gr.Slider(
346
+ label="Helpful",
347
+ minimum=1,
348
+ maximum=100,
349
+ value=50,
350
+ info="How helpful do you find the financial advisor? Answer from 1 to 100. A score of 100 means you find the financial advisor very helpful, while a score of 1 means you find the financial advisor not helpful at all.",
351
+ step=1,
352
+ )
353
+ evaluation_send_button = gr.Button(value="Send: Evaluation")
354
+ return {
355
+ "comp": comp,
356
+ "system_instruction": system_instruction,
357
+ "start_conversation": start_conversation,
358
+ "msg_button": msg_button,
359
+ "continue_button": continue_button,
360
+ "chatbot": chatbot,
361
+ "msg": msg,
362
+ "dropdown": dropdown,
363
+ "reason": reason,
364
+ "trust": trust,
365
+ "satisfaction": satisfaction,
366
+ "knowledgeable": knowledgeable,
367
+ "helpful": helpful,
368
+ "evaluation_send_button": evaluation_send_button,
369
+ }
370
+
371
+ def tab_creation_preference_stage():
372
+ with gr.Row():
373
+ gr.HTML(value=PREFERENCE_ELICITATION_TASK, label="Preference Elicitation Task")
374
+ with gr.Row():
375
+ with gr.Column():
376
+ whole_user_narrative = get_user_narrative_html(user_narrative)
377
+ gr.HTML(value=whole_user_narrative, label="User Narrative")
378
+ with gr.Column():
379
+ with gr.Row():
380
+ elicitation_chatbot = gr.Chatbot(height=600)
381
+ with gr.Row():
382
+ start_conversation = gr.Button(value="Start Conversation")
383
+ with gr.Row():
384
+ msg = gr.Textbox(scale=1, label="User Input")
385
+ with gr.Row():
386
+ msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
387
+ continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
388
+ return {
389
+ "start_conversation": start_conversation,
390
+ "msg_button": msg_button,
391
+ "continue_button": continue_button,
392
+ "msg": msg,
393
+ "elicitation_chatbot": elicitation_chatbot,
394
+ }
395
+
396
+ def tab_final_evaluation(first_comp, second_comp, third_comp, fourth_comp, fifth_comp):
397
+ with gr.Row():
398
+ gr.HTML(value=FINAL_EVALUATION)
399
+ with gr.Row():
400
+ ranking_first_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{first_comp}")
401
+ ranking_second_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{second_comp}")
402
+ ranking_third_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{third_comp}")
403
+ ranking_fourth_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{fourth_comp}")
404
+ ranking_fifth_comp = gr.Dropdown(choices=[1, 2, 3, 4, 5], label=f"{fifth_comp}")
405
+ with gr.Row():
406
+ textbox = gr.HTML(
407
+ """<div style="background-color: #f8d7da; color: #721c24; padding: 15px; border: 1px solid #f5c6cb; border-radius: 5px; margin-bottom: 20px;">
408
+ <strong>Please rank the stocks from 1 to 5, where 1 is the most preferred and 5 is the least preferred.</strong>
409
+ <br>
410
+ <strong>Make sure to assign different scores to different stocks.</strong>
411
+ </div>"""
412
+ )
413
+ submit_ranking = gr.Button(value="Submit Ranking")
414
+ return {
415
+ "first": {"comp": first_comp, "ranking_first_comp": ranking_first_comp},
416
+ "second": {"comp": second_comp, "ranking_second_comp": ranking_second_comp},
417
+ "third": {"comp": third_comp, "ranking_third_comp": ranking_third_comp},
418
+ "fourth": {"comp": fourth_comp, "ranking_fourth_comp": ranking_fourth_comp},
419
+ "fifth": {"comp": fifth_comp, "ranking_fifth_comp": ranking_fifth_comp},
420
+ "submit_ranking": submit_ranking,
421
+ "text_box": textbox,
422
+ }
423
+
424
+ def click_control_exploration_stage(tabs):
425
+ (
426
+ comp,
427
+ system_instruction,
428
+ start_conversation,
429
+ msg_button,
430
+ continue_button,
431
+ chatbot,
432
+ msg,
433
+ dropdown,
434
+ reason,
435
+ trust,
436
+ satisfaction,
437
+ knowledgeable,
438
+ helpful,
439
+ evaluation_send_button,
440
+ ) = (
441
+ tabs["comp"],
442
+ tabs["system_instruction"],
443
+ tabs["start_conversation"],
444
+ tabs["msg_button"],
445
+ tabs["continue_button"],
446
+ tabs["chatbot"],
447
+ tabs["msg"],
448
+ tabs["dropdown"],
449
+ tabs["reason"],
450
+ tabs["trust"],
451
+ tabs["satisfaction"],
452
+ tabs["knowledgeable"],
453
+ tabs["helpful"],
454
+ tabs["evaluation_send_button"],
455
+ )
456
+ start_conversation.click(
457
+ lambda history: respond_start_conversation(history, system_instruction, comp),
458
+ [chatbot],
459
+ [chatbot, start_conversation, msg_button, continue_button],
460
+ )
461
+ msg_button.click(
462
+ lambda message, history: respond(message, tab_data[comp]["history"], system_instruction, comp),
463
+ [msg, chatbot],
464
+ [msg, chatbot],
465
+ )
466
+ continue_button.click(
467
+ lambda history: respond_continue(tab_data[comp]["history"], system_instruction, comp),
468
+ [chatbot],
469
+ [chatbot],
470
+ )
471
+ evaluation_send_button.click(
472
+ lambda dropdown, reason, trust, satisfaction, knowledgeable, helpful: respond_evaluation(
473
+ {
474
+ "selection": dropdown,
475
+ "reason": reason,
476
+ "trust": trust,
477
+ "satisfaction": satisfaction,
478
+ "knowledgeable": knowledgeable,
479
+ "helpful": helpful,
480
+ },
481
+ comp,
482
+ ),
483
+ [dropdown, reason, trust, satisfaction, knowledgeable, helpful],
484
+ [dropdown, reason, trust, satisfaction, knowledgeable, helpful],
485
+ )
486
+
487
+ def click_control_preference_stage(tabs):
488
+ (
489
+ start_conversation,
490
+ msg_button,
491
+ continue_button,
492
+ elicitation_chatbot,
493
+ msg,
494
+ ) = (
495
+ tabs["start_conversation"],
496
+ tabs["msg_button"],
497
+ tabs["continue_button"],
498
+ tabs["elicitation_chatbot"],
499
+ tabs["msg"],
500
+ )
501
+ start_conversation.click(
502
+ lambda history: respond_start_conversation(
503
+ history, SYSTEM_INSTRUECTION_PREFERENCE_ELICITATION, user_elicitation=True
504
+ ),
505
+ [elicitation_chatbot],
506
+ [elicitation_chatbot, start_conversation, msg_button, continue_button],
507
+ )
508
+ msg_button.click(
509
+ lambda message, history: respond(
510
+ message,
511
+ user_preference_elicitation_data["history"],
512
+ SYSTEM_INSTRUECTION_PREFERENCE_ELICITATION,
513
+ user_elicitation=True,
514
+ ),
515
+ [msg, elicitation_chatbot],
516
+ [msg, elicitation_chatbot],
517
+ )
518
+ continue_button.click(
519
+ lambda history: respond_continue(
520
+ user_preference_elicitation_data["history"],
521
+ SYSTEM_INSTRUECTION_PREFERENCE_ELICITATION,
522
+ user_elicitation=True,
523
+ ),
524
+ [elicitation_chatbot],
525
+ [elicitation_chatbot],
526
+ )
527
+
528
+ def click_control_final_evaluation(tabs):
529
+ first_comp, ranking_first_comp = tabs["first"]["comp"], tabs["first"]["ranking_first_comp"]
530
+ second_comp, ranking_second_comp = tabs["second"]["comp"], tabs["second"]["ranking_second_comp"]
531
+ third_comp, ranking_third_comp = tabs["third"]["comp"], tabs["third"]["ranking_third_comp"]
532
+ fourth_comp, ranking_fourth_comp = tabs["fourth"]["comp"], tabs["fourth"]["ranking_fourth_comp"]
533
+ fifth_comp, ranking_fifth_comp = tabs["fifth"]["comp"], tabs["fifth"]["ranking_fifth_comp"]
534
+ result_textbox = tabs["text_box"]
535
+ submit_ranking = tabs["submit_ranking"]
536
+ submit_ranking.click(
537
+ lambda ranking_first_comp, ranking_second_comp, ranking_third_comp, ranking_fourth_comp, ranking_fifth_comp: respond_final_ranking(
538
+ first_comp,
539
+ ranking_first_comp,
540
+ second_comp,
541
+ ranking_second_comp,
542
+ third_comp,
543
+ ranking_third_comp,
544
+ fourth_comp,
545
+ ranking_fourth_comp,
546
+ fifth_comp,
547
+ ranking_fifth_comp,
548
+ ),
549
+ # Input components (names and rankings)
550
+ [
551
+ ranking_first_comp,
552
+ ranking_second_comp,
553
+ ranking_third_comp,
554
+ ranking_fourth_comp,
555
+ ranking_fifth_comp,
556
+ ],
557
+ # Output component(s) where you want the result to appear, e.g., result_textbox
558
+ [result_textbox],
559
+ )
560
+
561
+ def respond(message, history, system_instruction, tab_name=None, user_elicitation=False):
562
+ """
563
+ Return:
564
+ msg
565
+ chat_history
566
+ retrieved_passage
567
+ rewritten_query
568
+
569
+ """
570
+ assert (
571
+ tab_name is not None or user_elicitation is True
572
+ ), "Tab name is required for the start of the conversation unless it is not preference elicitation."
573
+ # Add user profile to system instruction
574
+ if not user_elicitation:
575
+ system_instruction = add_user_profile_to_system_instruction(
576
+ system_instruction,
577
+ user_preference_elicitation_data,
578
+ summary=USER_PREFERENCE_SUMMARY,
579
+ model=model,
580
+ terminator=terminator,
581
+ )
582
+ # print(f"Tab: {tab_name}\nSystem Instruction:{system_instruction}")
583
+ # Formatting Input
584
+ print(f"User Message: {message} in Tab: {tab_name}")
585
+ # From string to list [{"role":"user", "content": message}, ...]
586
+ history = gradio_to_huggingface_message(history)
587
+ # We can implement context window here as we need all the system interaction. We can cut some of the early interactions if needed.
588
+ history = conversation_window(history, CONV_WINDOW)
589
+ print(f"History Length: {len(history)}")
590
+ print(f"History: {history}")
591
+ # Add system instruction to the history
592
+ history = format_context(system_instruction, history)
593
+ # Add user message to the history
594
+ history_with_user_utterance = format_user_message(message, history)
595
+
596
+ outputs_text, history = response_generation(
597
+ history_with_user_utterance,
598
+ model,
599
+ tokenizer,
600
+ max_tokens=128,
601
+ device=DEVICE,
602
+ terminators=terminator,
603
+ )
604
+ # exclude system interaction and store the others in the history
605
+ history = huggingface_to_gradio_message(history)
606
+ if tab_name is not None:
607
+ print(f"Tab: {tab_name}\nSystem Output: {outputs_text}")
608
+
609
+ # Log the user message and response
610
+ log_action(tab_name, "User Message", message)
611
+ log_action(tab_name, "Response", outputs_text)
612
+ # Store the updated history for this tab
613
+ tab_data[tab_name]["history"] = history
614
+ if user_elicitation:
615
+ print(f"User Elicitation\nSystem Output: {outputs_text}")
616
+ log_action("User_Elicitation", "User Message", message)
617
+ log_action("User_Elicitation", "Response", outputs_text)
618
+ user_preference_elicitation_data["history"] = history
619
+
620
+ return "", history
621
+
622
+ def respond_start_conversation(history, system_instruction, tab_name=None, user_elicitation=False):
623
+ assert (
624
+ tab_name is not None or user_elicitation is True
625
+ ), "Tab name is required for the start of the conversation unless it is not preference elicitation."
626
+ if not user_elicitation:
627
+ system_instruction = add_user_profile_to_system_instruction(
628
+ system_instruction,
629
+ user_preference_elicitation_data,
630
+ summary=USER_PREFERENCE_SUMMARY,
631
+ model=model,
632
+ terminator=terminator,
633
+ )
634
+ print(f"Tab: {tab_name}\nSystem Instruction:{system_instruction}")
635
+ history = gradio_to_huggingface_message(history)
636
+ history = format_context(system_instruction, history)
637
+ first_message = FIRST_MESSAGE
638
+ history_with_user_utterance = format_user_message(first_message, history)
639
+
640
+ outputs_text, history = response_generation(
641
+ history_with_user_utterance,
642
+ model,
643
+ tokenizer,
644
+ max_tokens=128,
645
+ device=DEVICE,
646
+ terminators=terminator,
647
+ )
648
+ # Format
649
+ history = huggingface_to_gradio_message(history)
650
+ if tab_name is not None:
651
+ print(f"Tab: {tab_name}\nHistory: {history}")
652
+
653
+ # Log the user message and response
654
+ log_action(tab_name, "User Message", first_message)
655
+ log_action(tab_name, "Response", outputs_text)
656
+ # Store the updated history for this tab
657
+ tab_data[tab_name]["history"] = history
658
+ if user_elicitation:
659
+ print(f"User Elicitation\nHistory: {history}")
660
+ log_action("User_Elicitation", "User Message", first_message)
661
+ log_action("User_Elicitation", "Response", outputs_text)
662
+ user_preference_elicitation_data["history"] = history
663
+
664
+ return (
665
+ history,
666
+ gr.Button(value="Start Conversation", interactive=False),
667
+ gr.Button(value="Send This Message to Advisor", interactive=True),
668
+ gr.Button(value="Show More of the Advisor’s Answer", interactive=True),
669
+ )
670
+
671
+ def respond_continue(history, system_instruction, tab_name=None, user_elicitation=False):
672
+ assert (
673
+ tab_name is not None or user_elicitation is True
674
+ ), "Tab name is required for the start of the conversation."
675
+ # Add user profile to system instruction
676
+ if not user_elicitation:
677
+ system_instruction = add_user_profile_to_system_instruction(
678
+ system_instruction,
679
+ user_preference_elicitation_data,
680
+ summary=USER_PREFERENCE_SUMMARY,
681
+ model=model,
682
+ terminator=terminator,
683
+ )
684
+ # print(f"Tab: {tab_name}\nSystem Instruction:{system_instruction}")
685
+ message = "continue"
686
+ history = gradio_to_huggingface_message(history)
687
+ history = conversation_window(history, CONV_WINDOW)
688
+ history = format_context(system_instruction, history)
689
+ history_with_user_utterance = format_user_message(message, history)
690
+
691
+ outputs_text, history = response_generation(
692
+ history_with_user_utterance,
693
+ model,
694
+ tokenizer,
695
+ max_tokens=128,
696
+ device=DEVICE,
697
+ terminators=terminator,
698
+ )
699
+ history = huggingface_to_gradio_message(history)
700
+ if tab_name is not None:
701
+ log_action(tab_name, "Show More of the Advisor’s Answer", "User continued the conversation")
702
+ log_action(tab_name, "Response", outputs_text)
703
+
704
+ # Update history for this tab
705
+ tab_data[tab_name]["history"] = history
706
+ if user_elicitation:
707
+ print(f"User Elicitation\nSystem Output: {outputs_text}")
708
+ log_action("User_Elicitation", "Response", outputs_text)
709
+ user_preference_elicitation_data["history"] = history
710
+
711
+ return history
712
+
713
+ def respond_evaluation(evals, tab_name):
714
+
715
+ # dropdown, readon_button, multi-evaluator
716
+ log_action(tab_name, "Round Evaluation", "Following")
717
+ for key, value in evals.items():
718
+ log_action(tab_name, key, value)
719
+ # Store the reason for this tab
720
+ tab_data[tab_name]["multi_evaluator"] = evals
721
+ return (
722
+ evals["selection"],
723
+ evals["reason"],
724
+ evals["trust"],
725
+ evals["satisfaction"],
726
+ evals["knowledgeable"],
727
+ evals["helpful"],
728
+ )
729
+
730
+ def respond_final_ranking(
731
+ first_comp,
732
+ ranking_first_comp,
733
+ second_comp,
734
+ ranking_second_comp,
735
+ third_comp,
736
+ ranking_third_comp,
737
+ fourth_comp,
738
+ ranking_fourth_comp,
739
+ fifth_comp,
740
+ ranking_fifth_comp,
741
+ ):
742
+ # make sure that they are not the same
743
+ ranking_list = [
744
+ ranking_first_comp,
745
+ ranking_second_comp,
746
+ ranking_third_comp,
747
+ ranking_fourth_comp,
748
+ ranking_fifth_comp,
749
+ ]
750
+ if len(set(ranking_list)) != len(ranking_list):
751
+ return """<div style="background-color: #fff3cd; color: #856404; padding: 15px; border: 1px solid #ffeeba; border-radius: 5px; margin-bottom: 20px;">
752
+ <strong>Please make sure that you are not ranking the same stock multiple times.</strong>
753
+ </div>"""
754
+ else:
755
+ log_action("Final_Ranking", first_comp, ranking_first_comp)
756
+ log_action("Final_Ranking", second_comp, ranking_second_comp)
757
+ log_action("Final_Ranking", third_comp, ranking_third_comp)
758
+ log_action("Final_Ranking", fourth_comp, ranking_fourth_comp)
759
+ log_action("Final_Ranking", fifth_comp, ranking_fifth_comp)
760
+ return """<div style="background-color: #d4edda; color: #155724; padding: 15px; border: 1px solid #c3e6cb; border-radius: 5px; margin-bottom: 20px;">
761
+ <strong>Thank you for participating in the experiment. This concludes the session. You may now close the tab.</strong>
762
+ </div>"""
763
+
764
+ def get_context(index):
765
+ comp = raw_context_list[index]["short_name"]
766
+ context = stock_context_list[index]
767
+ general_instruction, round_instruction = get_task_instruction_for_user(raw_context_list[index])
768
+ return comp, context, general_instruction, round_instruction
769
+
770
+ with gr.Blocks(title="RAG Chatbot Q&A", theme="Soft") as demo:
771
+ first_comp, first_context, first_general_instruction, first_round_instruction = get_context(0)
772
+ second_comp, second_context, second_general_instruction, second_round_instruction = get_context(1)
773
+ third_comp, third_context, third_general_instruction, third_round_instruction = get_context(2)
774
+ fourth_comp, fourth_context, forth_general_instruction, forth_round_instruction = get_context(3)
775
+ fifth_comp, fifth_context, fifth_general_instruction, fifth_round_instruction = get_context(4)
776
+ user_narrative = markdown.markdown(raw_context_list[0]["user_narrative"].replace("\n", "<br>"))
777
+
778
+ # # initialize tab data
779
+ for comp in [first_comp, second_comp, third_comp, fourth_comp, fifth_comp]:
780
+ tab_data[comp] = {"history": [], "selection": "", "reason": ""}
781
+
782
+ # EXperiment Instruction
783
+ with gr.Tab("Experiment Instruction") as instruction_tab:
784
+ gr.HTML(value=INSTRUCTION_PAGE, label="Experiment Instruction")
785
+ # User Preference Elicitation Tab
786
+ with gr.Tab("Preference Elicitation Stage") as preference_elicitation_tab:
787
+ user_preference_elicitation_tab = tab_creation_preference_stage()
788
+ click_control_preference_stage(user_preference_elicitation_tab)
789
+ with gr.Tab("Financial Decision Stage"):
790
+ # Experiment Tag
791
+ first_tab = tab_creation_exploration_stage(0)
792
+ click_control_exploration_stage(first_tab)
793
+ second_tab = tab_creation_exploration_stage(1)
794
+ click_control_exploration_stage(second_tab)
795
+ third_tab = tab_creation_exploration_stage(2)
796
+ click_control_exploration_stage(third_tab)
797
+ fourth_tab = tab_creation_exploration_stage(3)
798
+ click_control_exploration_stage(fourth_tab)
799
+ fifth_tab = tab_creation_exploration_stage(4)
800
+ click_control_exploration_stage(fifth_tab)
801
+ with gr.Tab("Final Evaluation Stage") as final_evaluation:
802
+ final_evaluation_tab = tab_final_evaluation(first_comp, second_comp, third_comp, fourth_comp, fifth_comp)
803
+ click_control_final_evaluation(final_evaluation_tab)
804
+
805
+ return demo
806
+
807
+
808
+ if __name__ == "__main__":
809
+ login_to_huggingface(ACCESS)
810
+
811
+ file_path = os.path.join(ROOT_FILE, "./data/single_stock_data/single_stock_demo.jsonl")
812
+ context_info = get_context(file_path) # str to List of Dict
813
+ # For Demo Usage, just use the first dict
814
+ context_info = context_info[0]
815
+ stock_context_list = build_context(context_info) # List of str
816
+ raw_context_list = build_raw_context_list(context_info) # List of str
817
+ # system instruction consist of Task, Personality, and Context
818
+ """
819
+ Personality
820
+ ["extroverted", "introverted"]
821
+ ["agreeable", "antagonistic"]
822
+ ["conscientious", "unconscientious"]
823
+ ["neurotic", "emotionally stable"]
824
+ ["open to experience", "closed to experience"]]
825
+ """
826
+
827
+ personality = [
828
+ "extroverted",
829
+ "agreeable",
830
+ "conscientious",
831
+ "emotionally stable",
832
+ "open to experience",
833
+ ]
834
+
835
+ personality_prompt = build_personality_prompt(personality)
836
+ system_instruction_without_context = SYSTEM_INSTRUCTION + "\n" + personality_prompt + "\n"
837
+ # if DEBUG:
838
+ # tokenizer, terminator, model = "", "", ""
839
+ # else:
840
+ tokenizer = AutoTokenizer.from_pretrained(RESPONSE_GENERATOR)
841
+ tokenizer, terminator = prepare_tokenizer(tokenizer)
842
+ p
843
+ model = AutoModelForCausalLM.from_pretrained(
844
+ RESPONSE_GENERATOR,
845
+ torch_dtype=torch.float16,
846
+ pad_token_id=tokenizer.eos_token_id,
847
+ ).to(DEVICE)
848
+ demo = create_demo(
849
+ model, tokenizer, terminator, system_instruction_without_context, stock_context_list, raw_context_list
850
+ )
851
+ demo.launch(share=True)
experiments/single_stock_experiment.py ADDED
@@ -0,0 +1,574 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+ import os
4
+ from components.induce_personality import (
5
+ construct_big_five_words,
6
+ )
7
+
8
+
9
+ # need to import: gradio
10
+ def install(package, upgrade=False):
11
+ if upgrade:
12
+ subprocess.run(
13
+ [
14
+ sys.executable,
15
+ "-m",
16
+ "pip",
17
+ "install",
18
+ "--upgrade",
19
+ package,
20
+ ],
21
+ check=True,
22
+ )
23
+ else:
24
+ subprocess.run(
25
+ [
26
+ sys.executable,
27
+ "-m",
28
+ "pip",
29
+ "install",
30
+ package,
31
+ ],
32
+ check=True,
33
+ )
34
+
35
+
36
+ # install("ipdb")
37
+ # install("gradio")
38
+ # install("sentence-transformers")
39
+ # install("git+https://github.com/terrierteam/pyterrier_t5.git")
40
+ # install("protobuf")
41
+ # install("transformers", upgrade=True)
42
+ import random
43
+ import json
44
+ import gradio as gr
45
+ import random
46
+ import time
47
+ import ipdb
48
+ import markdown
49
+ import gradio as gr
50
+ import torch
51
+ from transformers import AutoModelForCausalLM, AutoTokenizer
52
+
53
+ from utils import login_to_huggingface, ACCESS
54
+ from components.rag_components import (
55
+ rag,
56
+ retrieve_passage,
57
+ response_generation,
58
+ )
59
+ from components.rewrite_passages import rewrite_rag_context
60
+ from components.query_rewriting import rewrite_query
61
+ from components.chat_conversation import (
62
+ format_message_history,
63
+ format_user_message,
64
+ format_context,
65
+ gradio_to_huggingface_message,
66
+ huggingface_to_gradio_message,
67
+ get_system_instruction,
68
+ prepare_tokenizer,
69
+ format_rag_context,
70
+ )
71
+ from components.constant import (
72
+ ACCESS,
73
+ QUERY_REWRITING,
74
+ RAG,
75
+ PERSONALITY,
76
+ PERSONALITY_LIST,
77
+ REWRITE_PASSAGES,
78
+ NUM_PASSAGES,
79
+ DEVICE,
80
+ RESPONSE_GENERATOR,
81
+ )
82
+ from components.induce_personality import (
83
+ build_personality_prompt,
84
+ )
85
+
86
+ # LOG_FILE = "log_file_bingzhi_information_seeking.txt"
87
+ ROOT_FILE = os.path.dirname(os.path.abspath(__file__))
88
+ LOG_DIR = os.path.join(ROOT_FILE, "log/single_stock_experiment/othres/")
89
+ if os.path.exists(LOG_DIR) is False:
90
+ os.makedirs(LOG_DIR)
91
+ STATIC_FILE = os.path.join("_static")
92
+
93
+ with open(os.path.join(STATIC_FILE, "html/instruction_page.html"), "r") as f:
94
+ INSTRUCTION_PAGE = f.read()
95
+ with open(os.path.join(STATIC_FILE, "html/evaluation_instruction.html"), "r") as f:
96
+ EVALUATION_INSTRUCTION = f.read()
97
+ with open(os.path.join(STATIC_FILE, "txt/general_instruction_task.txt"), "r") as f:
98
+ GENERAL_INSTRUCTION_TASK = f.read()
99
+ with open(os.path.join(STATIC_FILE, "txt/general_instruction_button.txt"), "r") as f:
100
+ GENERAL_INSTRUCTION_BUTTON = f.read()
101
+ with open(os.path.join(STATIC_FILE, "txt/system_instruction.txt"), "r") as f:
102
+ SYSTEM_INSTRUCTION = f.read()
103
+ FIRST_MESSAGE = "Hey"
104
+ INFORMATION_SEEKING = True
105
+ DEBUG = False
106
+
107
+
108
+ def get_context(synthetic_data_path):
109
+ # Load data from the synthetic data file
110
+ with open(synthetic_data_path, "r") as f:
111
+ data = [json.loads(line) for line in f]
112
+
113
+ return data
114
+
115
+
116
+ def add_ticker_prefix(ticker_list, context_list):
117
+ res = []
118
+ for ticker, context in zip(ticker_list, context_list):
119
+ res.append(f"{ticker}: {context}")
120
+ return res
121
+
122
+
123
+ def build_raw_context_list(context_dict):
124
+ return context_dict["data"]
125
+
126
+
127
+ def build_context(context_dict):
128
+ return [build_context_element(context) for context in context_dict["data"]]
129
+
130
+
131
+ def build_context_element(context):
132
+ # [{topic: ex, data: {}}, {..}, ..]
133
+ # Extract information from the context
134
+ ticker = context["ticker"]
135
+ sector = context["sector"]
136
+ business_summary = context["business_summary"]
137
+ name = context["short_name"]
138
+ stock_price = context["price_data"]
139
+ earning = context["earning_summary"]
140
+ beta = context["beta"]
141
+
142
+ # Build the context string
143
+ stock_candidate = f"Stock Candidate: {name}"
144
+ 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}"
145
+
146
+ context_list = [stock_candidate, stock_info]
147
+
148
+ # Combine all parts into a single string
149
+ return "\n".join(context_list)
150
+
151
+
152
+ def get_task_instruction_for_user(context):
153
+ ticker_name = context["short_name"]
154
+ user_narrative = context["user_narrative"]
155
+ user_narrative = user_narrative.replace("\n", "<br>")
156
+ html_user_narrative = markdown.markdown(user_narrative)
157
+
158
+ general_instruction = f"""<!-- Grouped Container for Task Instruction and Stock Information -->
159
+ <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;">
160
+ <!-- Heading -->
161
+ <h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
162
+ General Instruction
163
+ </h2>
164
+
165
+ <!-- User Instruction -->
166
+ <p style="text-align: left; font-size: 16px; color: #34495e; margin-bottom: 20px;">
167
+ {GENERAL_INSTRUCTION_TASK}
168
+ {GENERAL_INSTRUCTION_BUTTON}
169
+ </p>
170
+ </div>"""
171
+ round_instruction = f"""
172
+ <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;">
173
+ <!-- Stock Information (Bold label, Normal ticker name) -->
174
+ <h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
175
+ Round Info
176
+ </h2>
177
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
178
+ Stock
179
+ </div>
180
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
181
+ <span style="font-weight: bold;">
182
+ This Round's Stock:
183
+ </span>
184
+ {ticker_name}
185
+ </div>
186
+
187
+ <!-- User Narrative (Bold label, Normal narrative) -->
188
+ <div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
189
+ User Narrative
190
+ </div>
191
+ <div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
192
+ {html_user_narrative}
193
+ </div>
194
+ </div>"""
195
+
196
+ return general_instruction, round_instruction
197
+
198
+
199
+ def display_system_instruction_with_html(
200
+ system_instruction,
201
+ ):
202
+ html_system_instruction = f"""
203
+ <p style="text-align: left; margin-bottom: 10px;">
204
+ {system_instruction}
205
+ </p>
206
+ """
207
+ return html_system_instruction
208
+
209
+
210
+ def create_demo(
211
+ model,
212
+ tokenizer,
213
+ terminator,
214
+ system_description_without_context,
215
+ stock_context_list,
216
+ raw_context_list,
217
+ ):
218
+ # Store the history here and use this as an input to each tab.
219
+ tab_data = {}
220
+ tab_gradio = {}
221
+
222
+ def tab_creation(order):
223
+ comp, contex, general_instruction, round_instruction = get_context(order)
224
+ system_instruction = system_description_without_context + "\n" + contex
225
+ tab_data[comp] = {"history": [], "selection": "", "reason": ""}
226
+ english_order = ["First", "Second", "Third", "Fourth", "Fifth"]
227
+ with gr.Tab(f"{english_order[order]}: {comp}") as tab:
228
+ with gr.Tab("Interaction with a Financial Advisor"):
229
+ gr.HTML(value=general_instruction, label="General Instruction")
230
+ with gr.Row():
231
+ with gr.Column():
232
+ with gr.Row():
233
+ gr.HTML(
234
+ value=round_instruction,
235
+ label="Round Instruction",
236
+ )
237
+ with gr.Column():
238
+ with gr.Row():
239
+ chatbot = gr.Chatbot(height=600)
240
+ with gr.Row():
241
+ start_conversation = gr.Button(value="Start Conversation")
242
+ with gr.Row():
243
+ msg = gr.Textbox(scale=1, label="Input: User Input")
244
+ with gr.Row():
245
+ msg_button = gr.Button(value="Send: User Input", interactive=False)
246
+ continue_button = gr.Button(value="Continue", interactive=False)
247
+ with gr.Row():
248
+ clear = gr.ClearButton([msg, chatbot])
249
+ # if DEBUG:
250
+ with gr.Row():
251
+ display_prompt = gr.HTML(
252
+ value=display_system_instruction_with_html(system_instruction),
253
+ label="System Instruction",
254
+ )
255
+ with gr.Tab("Evaluation"):
256
+ with gr.Row():
257
+ gr.HTML(value=EVALUATION_INSTRUCTION)
258
+ with gr.Row():
259
+ dropdown = gr.Dropdown(
260
+ label="Decision Making",
261
+ choices=["Purchase", "Not Purchase"],
262
+ show_label=True,
263
+ )
264
+ reason = gr.Textbox(scale=1, label="The reason of your choice")
265
+ with gr.Row():
266
+ trust = gr.Slider(
267
+ label="Trust",
268
+ minimum=1,
269
+ maximum=100,
270
+ value=50,
271
+ info="How much do you trust the financial advisor? Answer from 1 to 100.",
272
+ step=1,
273
+ )
274
+ satisfaction = gr.Slider(
275
+ label="Satisfaction",
276
+ minimum=1,
277
+ maximum=100,
278
+ value=50,
279
+ info="How satisfied are you with the financial advisor? Answer from 1 to 100.",
280
+ step=1,
281
+ )
282
+ with gr.Row():
283
+ knowledgeable = gr.Slider(
284
+ label="Knowledgeable",
285
+ minimum=1,
286
+ maximum=100,
287
+ value=50,
288
+ info="How knowledgeable do you feel after interacting with the financial advisor? Answer from 1 to 100.",
289
+ step=1,
290
+ )
291
+ helpful = gr.Slider(
292
+ label="Helpful",
293
+ minimum=1,
294
+ maximum=100,
295
+ value=50,
296
+ info="How helpful do you find the financial advisor? Answer from 1 to 100.",
297
+ step=1,
298
+ )
299
+ evaluation_send_button = gr.Button(value="Send: Evaluation")
300
+ return {
301
+ "comp": comp,
302
+ "system_instruction": system_instruction,
303
+ "start_conversation": start_conversation,
304
+ "msg_button": msg_button,
305
+ "continue_button": continue_button,
306
+ "chatbot": chatbot,
307
+ "msg": msg,
308
+ "dropdown": dropdown,
309
+ "reason": reason,
310
+ "trust": trust,
311
+ "satisfaction": satisfaction,
312
+ "knowledgeable": knowledgeable,
313
+ "helpful": helpful,
314
+ "evaluation_send_button": evaluation_send_button,
315
+ }
316
+
317
+ def click_control(tabs):
318
+ (
319
+ comp,
320
+ system_instruction,
321
+ start_conversation,
322
+ msg_button,
323
+ continue_button,
324
+ chatbot,
325
+ msg,
326
+ dropdown,
327
+ reason,
328
+ trust,
329
+ satisfaction,
330
+ knowledgeable,
331
+ helpful,
332
+ evaluation_send_button,
333
+ ) = (
334
+ tabs["comp"],
335
+ tabs["system_instruction"],
336
+ tabs["start_conversation"],
337
+ tabs["msg_button"],
338
+ tabs["continue_button"],
339
+ tabs["chatbot"],
340
+ tabs["msg"],
341
+ tabs["dropdown"],
342
+ tabs["reason"],
343
+ tabs["trust"],
344
+ tabs["satisfaction"],
345
+ tabs["knowledgeable"],
346
+ tabs["helpful"],
347
+ tabs["evaluation_send_button"],
348
+ )
349
+ start_conversation.click(
350
+ lambda history: respond_start_conversation(history, system_instruction, comp),
351
+ [chatbot],
352
+ [chatbot, start_conversation, msg_button, continue_button],
353
+ )
354
+ msg_button.click(
355
+ lambda message, history: respond(message, tab_data[comp]["history"], system_instruction, comp),
356
+ [msg, chatbot],
357
+ [msg, chatbot],
358
+ )
359
+ continue_button.click(
360
+ lambda history: respond_continue(tab_data[comp]["history"], system_instruction, comp),
361
+ [chatbot],
362
+ [chatbot],
363
+ )
364
+ evaluation_send_button.click(
365
+ lambda dropdown, reason, trust, satisfaction, knowledgeable, helpful: respond_evaluation(
366
+ {
367
+ "selection": dropdown,
368
+ "reason": reason,
369
+ "trust": trust,
370
+ "satisfaction": satisfaction,
371
+ "knowledgeable": knowledgeable,
372
+ "helpful": helpful,
373
+ },
374
+ comp,
375
+ ),
376
+ [dropdown, reason, trust, satisfaction, knowledgeable, helpful],
377
+ [dropdown, reason, trust, satisfaction, knowledgeable, helpful],
378
+ )
379
+
380
+ def log_action(tab_name, action, details):
381
+ """
382
+ Log actions for each tab (stock).
383
+ """
384
+ log_file = os.path.join(LOG_DIR, f"{tab_name}.txt")
385
+ with open(log_file, "a") as f:
386
+ f.write(f"Action: {action} | Details: {details}\n")
387
+
388
+ def respond(message, history, system_instruction, tab_name):
389
+ """
390
+ Return:
391
+ msg
392
+ chat_history
393
+ retrieved_passage
394
+ rewritten_query
395
+
396
+ """
397
+ # Formatting Input
398
+ print(f"User Message: {message} in Tab: {tab_name}")
399
+ history = gradio_to_huggingface_message(history)
400
+ history = format_context(system_instruction, history)
401
+ history_with_user_utterance = format_user_message(message, history)
402
+
403
+ outputs_text, history = response_generation(
404
+ history_with_user_utterance,
405
+ model,
406
+ tokenizer,
407
+ max_tokens=128,
408
+ device=DEVICE,
409
+ terminators=terminator,
410
+ )
411
+ # Format
412
+ history = huggingface_to_gradio_message(history)
413
+ print(f"Tab: {tab_name}\nHistory: {history}")
414
+
415
+ # Log the user message and response
416
+ log_action(tab_name, "User Message", message)
417
+ log_action(tab_name, "Response", outputs_text)
418
+ # Store the updated history for this tab
419
+ tab_data[tab_name]["history"] = history
420
+
421
+ return "", history
422
+
423
+ def respond_start_conversation(history, system_instruction, tab_name):
424
+ history = gradio_to_huggingface_message(history)
425
+ history = format_context(system_instruction, history)
426
+ first_message = FIRST_MESSAGE
427
+ history_with_user_utterance = format_user_message(first_message, history)
428
+
429
+ outputs_text, history = response_generation(
430
+ history_with_user_utterance,
431
+ model,
432
+ tokenizer,
433
+ max_tokens=128,
434
+ device=DEVICE,
435
+ terminators=terminator,
436
+ )
437
+ # Format
438
+ history = huggingface_to_gradio_message(history)
439
+ print(f"Tab: {tab_name}\nHistory: {history}")
440
+
441
+ # Log the user message and response
442
+ log_action(tab_name, "User Message", first_message)
443
+ log_action(tab_name, "Response", outputs_text)
444
+ # Store the updated history for this tab
445
+ tab_data[tab_name]["history"] = history
446
+
447
+ return (
448
+ history,
449
+ gr.Button(value="Start Conversation", interactive=False),
450
+ gr.Button(value="Send: User Input", interactive=True),
451
+ gr.Button(value="Continue", interactive=True),
452
+ )
453
+
454
+ def respond_continue(history, system_instruction, tab_name):
455
+ message = "continue"
456
+ history = gradio_to_huggingface_message(history)
457
+ history = format_context(system_instruction, history)
458
+ history_with_user_utterance = format_user_message(message, history)
459
+
460
+ outputs_text, history = response_generation(
461
+ history_with_user_utterance,
462
+ model,
463
+ tokenizer,
464
+ max_tokens=128,
465
+ device=DEVICE,
466
+ terminators=terminator,
467
+ )
468
+ history = huggingface_to_gradio_message(history)
469
+ log_action(tab_name, "Continue", "User continued the conversation")
470
+ log_action(tab_name, "Response", outputs_text)
471
+
472
+ # Update history for this tab
473
+ tab_data[tab_name]["history"] = history
474
+
475
+ return history
476
+
477
+ def respond_evaluation(evals, tab_name):
478
+
479
+ # dropdown, readon_button, multi-evaluator
480
+ log_action(tab_name, "Round Evaluation", "Following")
481
+ for key, value in evals.items():
482
+ log_action(tab_name, key, value)
483
+ # Store the reason for this tab
484
+ tab_data[tab_name]["multi_evaluator"] = evals
485
+ return (
486
+ evals["selection"],
487
+ evals["reason"],
488
+ evals["trust"],
489
+ evals["satisfaction"],
490
+ evals["knowledgeable"],
491
+ evals["helpful"],
492
+ )
493
+
494
+ def get_context(index):
495
+ comp = raw_context_list[index]["short_name"]
496
+ context = stock_context_list[index]
497
+ general_instruction, round_instruction = get_task_instruction_for_user(raw_context_list[index])
498
+ return comp, context, general_instruction, round_instruction
499
+
500
+ with gr.Blocks(title="RAG Chatbot Q&A", theme="Soft") as demo:
501
+ first_comp, first_context, first_general_instruction, first_round_instruction = get_context(0)
502
+ second_comp, second_context, second_general_instruction, second_round_instruction = get_context(1)
503
+ third_comp, third_context, third_general_instruction, third_round_instruction = get_context(2)
504
+ fourth_comp, fourth_context, forth_general_instruction, forth_round_instruction = get_context(3)
505
+ fifth_comp, fifth_context, fifth_general_instruction, fifth_round_instruction = get_context(4)
506
+ first_system_instruction = system_description_without_context + "\n" + first_context
507
+ second_system_instruction = system_description_without_context + "\n" + second_context
508
+ third_system_instruction = system_description_without_context + "\n" + third_context
509
+ fourth_system_instruction = system_description_without_context + "\n" + fourth_context
510
+ fifth_system_instruction = system_description_without_context + "\n" + fifth_context
511
+ # # initialize tab data
512
+ for comp in [first_comp, second_comp, third_comp, fourth_comp, fifth_comp]:
513
+ tab_data[comp] = {"history": [], "selection": "", "reason": ""}
514
+
515
+ # EXperiment Instruction
516
+ with gr.Tab("Experiment Instruction") as instruction_tab:
517
+ gr.HTML(value=INSTRUCTION_PAGE, label="Experiment Instruction")
518
+ # Experiment Tag
519
+ first_tab = tab_creation(0)
520
+ click_control(first_tab)
521
+ second_tab = tab_creation(1)
522
+ click_control(second_tab)
523
+ third_tab = tab_creation(2)
524
+ click_control(third_tab)
525
+ fourth_tab = tab_creation(3)
526
+ click_control(fourth_tab)
527
+ fifth_tab = tab_creation(4)
528
+ click_control(fifth_tab)
529
+ return demo
530
+
531
+
532
+ if __name__ == "__main__":
533
+ login_to_huggingface(ACCESS)
534
+
535
+ file_path = os.path.join(ROOT_FILE, "./data/single_stock_data/single_stock_demo.jsonl")
536
+ context_info = get_context(file_path) # str to List of Dict
537
+ # For Demo Usage, just use the first dict
538
+ context_info = context_info[0]
539
+ stock_context_list = build_context(context_info) # List of str
540
+ raw_context_list = build_raw_context_list(context_info) # List of str
541
+ # system instruction consist of Task, Personality, and Context
542
+ """
543
+ Personality
544
+ ["extroverted", "introverted"]
545
+ ["agreeable", "antagonistic"]
546
+ ["conscientious", "unconscientious"]
547
+ ["neurotic", "emotionally stable"]
548
+ ["open to experience", "closed to experience"]]
549
+ """
550
+
551
+ personality = [
552
+ "extroverted",
553
+ "agreeable",
554
+ "conscientious",
555
+ "emotionally stable",
556
+ "open to experience",
557
+ ]
558
+
559
+ personality_prompt = build_personality_prompt(personality)
560
+ system_instruction_without_context = SYSTEM_INSTRUCTION + "\n" + personality_prompt + "\n"
561
+ if DEBUG:
562
+ tokenizer, terminator, model = "", "", ""
563
+ else:
564
+ tokenizer = AutoTokenizer.from_pretrained(RESPONSE_GENERATOR)
565
+ tokenizer, terminator = prepare_tokenizer(tokenizer)
566
+ model = AutoModelForCausalLM.from_pretrained(
567
+ RESPONSE_GENERATOR,
568
+ torch_dtype=torch.float16,
569
+ pad_token_id=tokenizer.eos_token_id,
570
+ ).to(DEVICE)
571
+ demo = create_demo(
572
+ model, tokenizer, terminator, system_instruction_without_context, stock_context_list, raw_context_list
573
+ )
574
+ demo.launch(share=True)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ transformers==4.44.1
2
+ together==1.3.0
3
+ markdown==3.4.1
user_feedback/interaction_3a48b93b-0de7-4e2a-b779-8f1f0c27af24_first.json ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ {"user_id": "demo_3_0_0", "uuid": "3a48b93b-0de7-4e2a-b779-8f1f0c27af24", "timestamp": "2024-10-23 17:14:02", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_3_0_0", "uuid": "3a48b93b-0de7-4e2a-b779-8f1f0c27af24", "timestamp": "2024-10-23 17:14:02", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "What brings you here today? Are you looking to start investing or reassess your current portfolio?"}}
user_feedback/interaction_462c2c52-b14f-44f1-8030-6f06d5a7d925_first.json ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ {"user_id": "demo_3_0_0", "uuid": "462c2c52-b14f-44f1-8030-6f06d5a7d925", "timestamp": "2024-10-23 17:15:17", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_3_0_0", "uuid": "462c2c52-b14f-44f1-8030-6f06d5a7d925", "timestamp": "2024-10-23 17:15:17", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "What brings you here today? Are you looking to start investing or reassess your current portfolio?"}}
user_feedback/interaction_7017b92d-6932-4d3a-b189-1267c2386995_first.json ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ {"user_id": "demo_0_0_0", "uuid": "7017b92d-6932-4d3a-b189-1267c2386995", "timestamp": "2024-10-23 17:19:10", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_0_0_0", "uuid": "7017b92d-6932-4d3a-b189-1267c2386995", "timestamp": "2024-10-23 17:19:10", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Welcome to our financial planning session. I'm excited to help you create a personalized investment strategy. To get started, let's talk about your preferred industry for investment. Are you interested in investing in a specific sector, such as technology, healthcare, finance, energy, consumer goods, or something else?"}}
user_feedback/interaction_7e25ac2e-3849-4817-9ae3-e883bca2fb10_first.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {"user_id": "demo_3_0_0", "uuid": "7e25ac2e-3849-4817-9ae3-e883bca2fb10", "timestamp": "2024-10-23 17:05:19", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_3_0_0", "uuid": "7e25ac2e-3849-4817-9ae3-e883bca2fb10", "timestamp": "2024-10-23 17:05:19", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "What can I help you with today? You're looking to discuss your investment options, I assume?"}}
3
+ {"user_id": "demo_3_0_0", "uuid": "7e25ac2e-3849-4817-9ae3-e883bca2fb10", "timestamp": "2024-10-23 17:05:32", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "yes"}}
4
+ {"user_id": "demo_3_0_0", "uuid": "7e25ac2e-3849-4817-9ae3-e883bca2fb10", "timestamp": "2024-10-23 17:05:32", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Let's start with the basics. What type of industry or sector are you interested in investing in? Are you drawn to technology, healthcare, finance, or something else?"}}
user_feedback/interaction_8611c342-840f-4529-b9ff-d1dabb754ded_first.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {"user_id": "demo_2_2_0", "uuid": "8611c342-840f-4529-b9ff-d1dabb754ded", "timestamp": "2024-10-23 17:00:59", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_2_2_0", "uuid": "8611c342-840f-4529-b9ff-d1dabb754ded", "timestamp": "2024-10-23 17:00:59", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "It's great to meet you! I'm thrilled to help you with your investment goals. Let's get started. To begin, I'd love to know, what industries interest you the most? Are you drawn to technology, healthcare, finance, or perhaps something else?"}}
3
+ {"user_id": "demo_2_2_0", "uuid": "8611c342-840f-4529-b9ff-d1dabb754ded", "timestamp": "2024-10-23 17:03:47", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "I am interested in healthcare "}}
4
+ {"user_id": "demo_2_2_0", "uuid": "8611c342-840f-4529-b9ff-d1dabb754ded", "timestamp": "2024-10-23 17:03:47", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Healthcare is a fantastic sector with a lot of growth potential. It's also a sector that tends to be less volatile, which can be appealing to some investors. What specifically within healthcare interests you the most? Are you drawn to pharmaceuticals, medical devices, or perhaps healthcare services?"}}
5
+ {"user_id": "demo_2_2_0", "uuid": "8611c342-840f-4529-b9ff-d1dabb754ded", "timestamp": "2024-10-23 17:04:27", "type": "interaction", "value": {"type": "Bank of America Corporation", "role": "user", "content": "Hey"}}
6
+ {"user_id": "demo_2_2_0", "uuid": "8611c342-840f-4529-b9ff-d1dabb754ded", "timestamp": "2024-10-23 17:04:27", "type": "interaction", "value": {"type": "Bank of America Corporation", "role": "assistant", "content": "I'm so glad you're here! I've got some exciting information to share with you about a potential investment opportunity. Today, we're going to explore Bank of America Corporation, a well-established player in the financial services industry. As a customer who's interested in various sectors, I think you'll find this one fascinating.\n\nBank of America operates in four main segments: Consumer Banking, Global Wealth & Investment Management, Global Banking, and Global Markets. They offer a wide range of products and services, from banking and lending to investment and wealth management. What I think you'll appreciate is that their Consumer Banking segment focuses on serving individual consumers, which aligns with your interest in various sectors.\n\nHowever, I do want to mention that Bank of America operates in the financial services industry, which can be quite volatile. Their beta, a measure of risk, is 1.338, indicating that their stock price can be more sensitive to market fluctuations. What would you like to know more about this potential investment opportunity?"}}
user_feedback/interaction_8e1566fb-6de9-46da-a3de-c6a580fb5b83_first.json ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ {"user_id": "demo_3_0_0", "uuid": "8e1566fb-6de9-46da-a3de-c6a580fb5b83", "timestamp": "2024-10-23 17:15:46", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_3_0_0", "uuid": "8e1566fb-6de9-46da-a3de-c6a580fb5b83", "timestamp": "2024-10-23 17:15:46", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "What can I help you with today? You're looking to discuss your investment strategy, I assume?"}}
user_feedback/interaction_abfb0425-8dff-4b63-91d0-372276758a8f_first.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {"user_id": "demo_1_1_0", "uuid": "abfb0425-8dff-4b63-91d0-372276758a8f", "timestamp": "2024-10-23 17:20:21", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_1_1_0", "uuid": "abfb0425-8dff-4b63-91d0-372276758a8f", "timestamp": "2024-10-23 17:20:21", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Welcome to our financial planning session. I'm here to help you make informed investment decisions. To get started, let's discuss your preferred industry for investment. Are you interested in investing in a specific sector, such as technology, healthcare, finance, energy, consumer goods, or something else?"}}
3
+ {"user_id": "demo_1_1_0", "uuid": "abfb0425-8dff-4b63-91d0-372276758a8f", "timestamp": "2024-10-23 17:20:55", "type": "interaction", "value": {"type": "Walmart Inc.", "role": "user", "content": "Hey"}}
4
+ {"user_id": "demo_1_1_0", "uuid": "abfb0425-8dff-4b63-91d0-372276758a8f", "timestamp": "2024-10-23 17:20:55", "type": "interaction", "value": {"type": "Walmart Inc.", "role": "assistant", "content": "Welcome to our financial advisory session. I'm here to help you explore the details of a specific stock, Walmart Inc. (WMT). Before we dive in, I'd like to give you a brief overview of the company. Walmart is a multinational retail corporation that operates a wide range of stores, including supercenters, supermarkets, and e-commerce platforms. They offer a vast array of products, from groceries and electronics to clothing and home goods. They also provide various services, such as pharmacy, optical, and financial services.\n\nNow, what would you like to know more about Walmart Inc.? Would you like to explore their financial performance, business operations, or something else?"}}
user_feedback/interaction_b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea_first.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:16:41", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:16:41", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "What can I help you with today? We're going to discuss your investment preferences. Let's start with the industry. Are you interested in investing in a specific sector, such as technology, healthcare, finance, or something else?"}}
3
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:16:55", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "I am interested in healthcare"}}
4
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:16:55", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Healthcare is a stable industry with a strong demand for services. What aspect of healthcare are you most interested in? Pharmaceuticals, medical devices, hospitals, or perhaps biotechnology?"}}
5
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:06", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "I do not have preference on that"}}
6
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:06", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "So you're open to various sub-sectors within healthcare. That's a broad and diverse field. Next, let's discuss the type of stocks you're interested in. Are you looking for value stocks, which are often undervalued and have the potential for long-term growth, or growth stocks, which are expected to experience rapid expansion?"}}
7
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:28", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "What are the differences?"}}
8
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:28", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Value stocks are typically undervalued by the market, meaning their price is lower than their intrinsic value. They often have a history of stable earnings and a strong financial foundation. Growth stocks, on the other hand, are expected to experience rapid expansion in revenue and earnings, but may be more volatile. They often have a higher growth potential, but also come with higher risks. Think of it like buying a house: value stocks are like a stable, established home, while growth stocks are like a new, rapidly expanding development."}}
9
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:36", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "I like growth stock"}}
10
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:36", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Growth stocks can be more exciting, but also come with higher risks. They often require a higher tolerance for volatility. Next, let's discuss dividends. Are you interested in investing in stocks that pay dividends, providing a regular income stream, or non-dividend stocks, which focus on capital appreciation?"}}
11
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:47", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Any recommendations for that"}}
12
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:17:47", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "I'm not here to recommend specific stocks yet. This conversation is about your preferences. We'll discuss specific stocks in the next session. For now, I just need to understand your preference. Do you want dividend-paying stocks for regular income or non-dividend stocks for potential long-term growth?"}}
13
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:18:00", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "I want dividend stock"}}
14
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:18:00", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Dividend stocks can provide a steady income stream. However, keep in mind that they often come with lower growth potential compared to non-dividend stocks. Next, let's discuss the type of stocks that are less affected by economic downturns. Are you interested in cyclical stocks, which are closely tied to the overall economy and can be more volatile, or non-cyclical stocks, which are less affected by economic fluctuations?"}}
15
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:18:09", "type": "Interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Probably non-cyclical one"}}
16
+ {"user_id": "demo_3_0_0", "uuid": "b8b1504f-a952-4c9c-b6b1-febdb3ffd6ea", "timestamp": "2024-10-23 17:18:09", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Non-cyclical stocks tend to be more stable and less affected by economic downturns. They often provide a steady income stream and can be a good fit for investors seeking lower volatility. I think we've covered the main points. Thank you for the conversation, please move on to the next section."}}
user_feedback/interaction_d34ca619-e30a-4267-9538-cc8f99aff079.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {"user_id": "demo_3_2_4", "uuid": "d34ca619-e30a-4267-9538-cc8f99aff079", "timestamp": "2024-10-23 12:02:59", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_3_2_4", "uuid": "d34ca619-e30a-4267-9538-cc8f99aff079", "timestamp": "2024-10-23 12:02:59", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "Welcome to our financial planning session. I'm here to help you understand your investment preferences. Let's start with the first topic: preferred industries. Are you interested in investing in a specific industry, such as technology, healthcare, finance, or something else?"}}
3
+ {"user_id": "demo_3_2_4", "uuid": "d34ca619-e30a-4267-9538-cc8f99aff079", "timestamp": "2024-10-23 12:03:07", "type": "interaction", "value": {"type": "Apple Inc.", "role": "user", "content": "Hey"}}
4
+ {"user_id": "demo_3_2_4", "uuid": "d34ca619-e30a-4267-9538-cc8f99aff079", "timestamp": "2024-10-23 12:03:07", "type": "interaction", "value": {"type": "Apple Inc.", "role": "assistant", "content": "Apple Inc. is a technology company that designs and manufactures a wide range of products, including iPhones, Mac computers, and wearables. They also offer various services, such as Apple Music and Apple Pay. Given your profile, I notice that you don't have any specific industry preferences, which makes Apple a good fit in that regard. However, as a technology company, Apple is considered a growth stock, and its beta is 1.239, indicating a relatively high level of volatility. This might be a concern for some investors. What would you like to know more about Apple's performance and prospects?"}}
user_feedback/interaction_e7f30c05-4668-4b35-a706-ba27b7c0a0a9_first.json ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ {"user_id": "demo_2_2_0", "uuid": "e7f30c05-4668-4b35-a706-ba27b7c0a0a9", "timestamp": "2024-10-23 17:13:16", "type": "interaction", "value": {"type": "user_elicitation", "role": "user", "content": "Hey"}}
2
+ {"user_id": "demo_2_2_0", "uuid": "e7f30c05-4668-4b35-a706-ba27b7c0a0a9", "timestamp": "2024-10-23 17:13:16", "type": "Interaction", "value": {"type": "user_elicitation", "role": "assistant", "content": "It's great to meet you! I'm excited to help you with your investment goals. Let's get started. What kind of industry or sector are you most interested in investing in? Are you drawn to technology, healthcare, finance, or something else?"}}
user_feedback/summarization_8611c342-840f-4529-b9ff-d1dabb754ded_first.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"user_id": "demo_2_2_0", "uuid": "8611c342-840f-4529-b9ff-d1dabb754ded", "timestamp": "2024-10-23 17:04:25", "type": "preference_elicitation_summarization", "value": {"summarization": "Based on the previous conversation, here's a summary of the customer's investment preferences:\n\n1. **Preferred Industries:** Healthcare\n2. **Value vs. Growth Stocks:** Not discussed\n3. **Dividend vs. Non-Dividend Stocks:** Not discussed\n4. **Cyclical vs. Non-Cyclical Stocks:** Not discussed"}}
user_feedback/summarization_d34ca619-e30a-4267-9538-cc8f99aff079.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"user_id": "demo_3_2_4", "uuid": "d34ca619-e30a-4267-9538-cc8f99aff079", "timestamp": "2024-10-23 12:03:05", "type": "preference_elicitation_summarization", "value": {"summarization": "Unfortunately, I don't have any information about a previous conversation with a customer. However, I can provide a summary based on the given conversation snippet.\n\nPreferred Industries: The customer has not expressed a preference for a specific industry.\n\nValue vs. Growth Stocks: Not discussed.\n\nDividend vs. Non-Dividend Stocks: Not discussed.\n\nCyclical vs. Non-Cyclical Stocks: Not discussed."}}