FinPersona_ECIR / app.py
TTsamurai's picture
delete the authorization limit and make it public during SIGIR 2025
efee783 verified
raw
history blame
55.8 kB
import sys
import os
from datetime import datetime
import json
import uuid
from pathlib import Path
from huggingface_hub import CommitScheduler, login
from datasets import load_dataset
import gradio as gr
import markdown
from together import Together
ROOT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "./")
sys.path.append(ROOT_FILE)
from components.induce_personality import construct_big_five_words
from components.chat_conversation import (
format_user_message,
format_context,
gradio_to_huggingface_message,
huggingface_to_gradio_message,
conversation_window,
generate_response_local_api,
generate_response_together_api,
generate_response_debugging,
)
from components.constant import (
CONV_WINDOW,
API_URL,
)
LOG_DIR = os.path.join(ROOT_FILE, "log/api/")
if os.path.exists(LOG_DIR) is False:
os.makedirs(LOG_DIR)
# Load Static Files
STATIC_FILE = os.path.join(ROOT_FILE, "_static")
LOG_DIR = os.path.join(ROOT_FILE, "log/test_session/")
INSTRUCTION_PAGE_FILE = os.path.join(STATIC_FILE, "html/instruction_page.html")
USER_NARRATIVE_FILE = os.path.join(STATIC_FILE, "html/user_narrative.html")
PREFERENCE_ELICITATION_TASK_FILE = os.path.join(STATIC_FILE, "html/system_instruction_preference_elicitation.html")
EVALUATION_INSTRUCTION_FILE = os.path.join(STATIC_FILE, "html/evaluation_instruction.html")
GENERAL_INSTRUCTION_FILE = os.path.join(STATIC_FILE, "html/general_instruction.html")
FINAL_EVALUATION_FILE = os.path.join(STATIC_FILE, "html/final_evaluation.html")
SYSTEM_INSTRUCTION_PERSONALIZATION_FILE = os.path.join(STATIC_FILE, "txt/system_instruction_personalization.txt")
SYSTEM_INSTRUCTION_NON_PERSONALIZATION_FILE = os.path.join(
STATIC_FILE, "txt/system_instruction_non_personalization.txt"
)
SYSTEM_INSTRUCTION_PERSONALITY_FILE = os.path.join(STATIC_FILE, "txt/system_instruction_personality.txt")
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_FILE = os.path.join(
STATIC_FILE, "txt/system_instruction_preference_elicitation.txt"
)
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY_FILE = os.path.join(
STATIC_FILE, "txt/system_instruction_preference_elicitation_personality.txt"
)
SUMMARIZATION_PROMPT_FILE = os.path.join(STATIC_FILE, "txt/system_summarization_user_preference_elicitation.txt")
PERSONALITY_EXT_FILE = os.path.join(STATIC_FILE, "txt/personality_ext.txt")
PERSONALITY_INT_FILE = os.path.join(STATIC_FILE, "txt/personality_int.txt")
PERSONALITY_MISADVISOR_FILE = os.path.join(STATIC_FILE, "txt/personality_misadvisor.txt")
uuid_this_session = str(uuid.uuid4())
system_order = "first"
feedback_dir = Path("user_feedback_debug/")
feedback_file_interaction = feedback_dir / f"interaction_{uuid_this_session}_{system_order}.json"
feedback_file_summarization = feedback_dir / f"summarization_{uuid_this_session}_{system_order}.json"
feedback_file_round_evaluation = feedback_dir / f"round_evaluation_{uuid_this_session}_{system_order}.json"
feedback_file_final_ranking = feedback_dir / f"final_ranking_{uuid_this_session}_{system_order}.json"
feedback_file_final_survey = feedback_dir / f"final_survey_{uuid_this_session}_{system_order}.json"
feedback_folder = feedback_file_interaction.parent
feedback_folder.mkdir(parents=True, exist_ok=True) # Ensure the directory exists
# scheduler = CommitScheduler(
# repo_id=os.getenv("LOGGING_FILE"),
# repo_type="dataset",
# folder_path=feedback_folder,
# path_in_repo="data",
# token=os.getenv("HUGGINGFACE_HUB_TOKEN"),
# every=1,
# )
# Function to save user feedback
# def save_feedback(user_id: str, uuid: str, type: str, value, feedback_file) -> None:
# """
# Append input/outputs and user feedback to a JSON Lines file using a thread lock to avoid concurrent writes from different users.
# """
# timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# with scheduler.lock:
# with feedback_file.open("a") as f:
# f.write(
# json.dumps({"user_id": user_id, "uuid": uuid, "timestamp": timestamp, "type": type, "value": value})
# )
# f.write("\n")
# Load the required static content from files
def load_static_content(file_path):
with open(file_path, "r") as f:
return f.read()
def ensure_directory_exists(directory_path):
"""Ensures the given directory exists; creates it if it does not."""
if not os.path.exists(directory_path):
os.makedirs(directory_path)
INSTRUCTION_PAGE = load_static_content(INSTRUCTION_PAGE_FILE)
EVALUATION_INSTRUCTION = load_static_content(EVALUATION_INSTRUCTION_FILE)
GENERAL_INSTRUCTION = load_static_content(GENERAL_INSTRUCTION_FILE)
USER_NARRATIVE = load_static_content(USER_NARRATIVE_FILE)
PREFERENCE_ELICITATION_TASK = load_static_content(PREFERENCE_ELICITATION_TASK_FILE)
FINAL_EVALUATION = load_static_content(FINAL_EVALUATION_FILE)
SYSTEM_INSTRUCTION_PERSONALIZATION = load_static_content(SYSTEM_INSTRUCTION_PERSONALIZATION_FILE)
SYSTEM_INSTRUCTION_NON_PERSONALIZATION = load_static_content(SYSTEM_INSTRUCTION_NON_PERSONALIZATION_FILE)
SYSTEM_INSTRUCTION_PERSONALITY = load_static_content(SYSTEM_INSTRUCTION_PERSONALITY_FILE)
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION = load_static_content(SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_FILE)
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY = load_static_content(
SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY_FILE
)
SUMMARIZATION_PROMPT = load_static_content(SUMMARIZATION_PROMPT_FILE)
PERSONALITY_EXT = load_static_content(PERSONALITY_EXT_FILE)
PERSONALITY_INT = load_static_content(PERSONALITY_INT_FILE)
PERSONALITY_MISADVISOR = load_static_content(PERSONALITY_MISADVISOR_FILE)
# Other constants
FIRST_MESSAGE = "Hey"
USER_PREFERENCE_SUMMARY = True
DEBUG = False
API_TYPE = "together"
assert API_TYPE in ["together", "local", "debug"], "The API should be either 'together' or 'local'"
if API_TYPE == "together":
TOGETHER_CLIENT = Together(api_key=os.getenv("TOGETHER_API_KEY"))
def generate_username_pwd_list(data):
user_list = []
demo_list = []
for index, row in data.iterrows():
user_list.append((row["user"], str(row["pwd"])))
demo_list.append((row["demo"], str(row["pwd"])))
return user_list, demo_list
def load_username_and_pwd():
login(token=os.environ["HUGGINGFACE_HUB_TOKEN"])
dataset = load_dataset(os.getenv("USER_PWD_FILE"))
df = dataset["train"].to_pandas()
user_list, demo_list = generate_username_pwd_list(df)
return user_list, demo_list
def get_context_list(synthetic_data_path):
# Load data from the synthetic data file
with open(synthetic_data_path, "r") as f:
data = [json.loads(line) for line in f]
return data
def add_ticker_prefix(ticker_list, context_list):
res = []
for ticker, context in zip(ticker_list, context_list):
res.append(f"{ticker}: {context}")
return res
def build_raw_context_list(context_dict):
return context_dict["data"]
def build_context(context_dict):
return [build_context_element(context) for context in context_dict["data"]]
def build_context_element(context):
# [{topic: ex, data: {}}, {..}, ..]
# Extract information from the context
ticker = context["ticker"]
sector = context["sector"]
business_summary = context["business_summary"]
name = context["short_name"]
print(name)
stock_price = context["price_data"]
earning = context["earning_summary"]
beta = context["beta"]
# Build the context string
stock_candidate = f"Stock Candidate: {name}"
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}"
context_list = [stock_candidate, stock_info]
# Combine all parts into a single string
return "\n".join(context_list)
def get_user_narrative_html(user_narrative):
return USER_NARRATIVE.replace("{user_narrative}", user_narrative).replace("\n", "<br>")
def get_user_narrative_from_raw(raw_narrative):
return get_user_narrative_html(markdown.markdown(raw_narrative.replace("\n", "<br>")))
def get_task_instruction_for_user(context):
ticker_name = context["short_name"]
user_narrative = context["user_narrative"]
user_narrative = user_narrative.replace("\n", "<br>")
html_user_narrative = markdown.markdown(user_narrative)
general_instruction = GENERAL_INSTRUCTION
round_instruction = f"""
<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;">
<!-- Stock Information (Bold label, Normal ticker name) -->
<h2 style="color: #2c3e50; text-align: center; margin-bottom: 20px; font-size: 20px; font-weight: 600;">
Round Info
</h2>
<div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
Stock
</div>
<div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
<span style="font-weight: bold;">
This Round's Stock:
</span>
{ticker_name}
</div>
<!-- User Narrative (Bold label, Normal narrative) -->
<div style="text-align: left; font-size: 20px; font-weight: bold; margin-bottom: 20px;">
User Narrative
</div>
<div style="text-align: left; font-weight: normal; font-size: 16px; margin-bottom: 20px;">
{html_user_narrative}
</div>
</div>"""
return general_instruction, round_instruction
def display_system_instruction_with_html(
system_instruction,
):
html_system_instruction = f"""
<p style="text-align: left; margin-bottom: 10px;">
{system_instruction}
</p>
"""
return html_system_instruction
def log_action(user_id, tab_name, action, details):
"""
Log actions for each tab (stock).
"""
log_file_dir = os.path.join(LOG_DIR, f"{user_id}")
if os.path.exists(log_file_dir) is False:
os.makedirs(log_file_dir)
log_file = os.path.join(log_file_dir, f"{tab_name}.txt")
with open(log_file, "a") as f:
f.write(f"Action: {action} | Details: {details}\n")
def add_user_profile_to_system_instruction(
user_id, system_instruction, user_preference_elicitation_data, summary, terminator
):
exp_id = int(user_id.split("_")[-3])
# exp_id = 1 => No personalization
if exp_id == 1:
return system_instruction
if summary:
if user_preference_elicitation_data["summary_history"] == "":
# Format prompt
summarization_prompt = SUMMARIZATION_PROMPT + "\nPrevious Conversations: {}".format(
user_preference_elicitation_data["history"]
)
summarization_instruction = [{"role": "system", "content": summarization_prompt}]
if API_TYPE == "local":
summ, _ = generate_response_local_api(summarization_instruction, terminator, 512, API_URL)
elif API_TYPE == "together":
summ, _ = generate_response_together_api(summarization_instruction, 512, TOGETHER_CLIENT)
else:
summ, _ = generate_response_debugging(summarization_instruction)
user_preference_elicitation_data["summary_history"] = summ
# # log_action(user_id, "Prompt", "Preference Elicitation Summarization", summ)
# save_feedback(
# user_id,
# uuid_this_session,
# "preference_elicitation_summarization",
# {"summarization": summ},
# feedback_file_summarization,
# )
system_instruction += f"\nUser Profile collected in the previous conversations: {user_preference_elicitation_data['summary_history']}\n"
else:
system_instruction += (
f"\nUser Profile collected in the previous conversations: {user_preference_elicitation_data['history']}\n"
)
return system_instruction
def likert_evaluation(content):
return gr.Radio(
[1, 2, 3, 4, 5, 6, 7],
label=f"{content}",
show_label=True,
)
def create_demo():
global context_info_list, terminator
def tab_creation_exploration_stage(order, comp, context):
comp_list = [
"Eli Lilly and Company",
"Johnson & Johnson",
"Philip Morris International Inc",
"Exxon Mobil Corporation",
"Amazon.com, Inc.",
"JP Morgan Chase & Co.",
"Coca-Cola Company",
"Walmart Inc.",
"Apple Inc.",
"Procter & Gamble Company",
"Tesla, Inc.",
"Bank of America Corporation",
]
with gr.Tab(comp_list[order], id=comp):
general_instruction = gr.HTML(label="General Instruction")
with gr.Row():
# with gr.Column():
# with gr.Row():
# round_instruction = gr.HTML(label="Round Instruction")
with gr.Column():
with gr.Row():
chatbot = gr.Chatbot(height=600)
with gr.Row():
start_conversation = gr.Button(value="Start Conversation")
with gr.Row():
msg = gr.Textbox(scale=2, lines=3, label="User Input", container=False)
msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
with gr.Row():
clear = gr.ClearButton([msg, chatbot])
return {
"comp": comp,
"system_instruction_context": context,
"start_conversation": start_conversation,
"msg_button": msg_button,
"continue_button": continue_button,
"chatbot": chatbot,
"msg": msg,
"general_instruction": general_instruction,
# "round_instruction": round_instruction,
}
def tab_creation_preference_stage():
# Custom CSS to reduce padding and margin of the textbox
with gr.Row():
gr.HTML(value=PREFERENCE_ELICITATION_TASK, label="Preference Elicitation Task")
with gr.Row():
# with gr.Column():
# user_narrative = gr.HTML(label="User Narrative")
with gr.Column():
with gr.Row():
elicitation_chatbot = gr.Chatbot(height=600)
with gr.Row():
start_conversation = gr.Button(value="Start Conversation")
with gr.Row():
msg = gr.Textbox(scale=2, lines=3, label="User Input", container=False)
msg_button = gr.Button(value="Send This Message to Advisor", interactive=False)
continue_button = gr.Button(value="Show More of the Advisor’s Answer", interactive=False)
return {
"start_conversation": start_conversation,
"msg_button": msg_button,
"continue_button": continue_button,
"msg": msg,
"elicitation_chatbot": elicitation_chatbot,
# "user_narrative": user_narrative,
}
def tab_personality_injection():
gr.Markdown("## Choose Your Advisor Personality")
# A radio button to choose between Optimist and Pragmatis
personality_choice = gr.Radio(
choices=[
"Optimist (Friendly, Daring, Confident)",
"Pragmatist (Disciplined, Cautious, Practical)",
"Misadvisor (Just for fun! Unreliable, Messy, Sarcastic - don't take it seriously!)",
],
value="Optimist",
label="Select a Personality",
interactive=True,
)
# An HTML element to display personality details/description
personality_description = gr.HTML(value="", label="Personality Details")
# A button that, when clicked, confirms the selection
personality_submit = gr.Button("Apply Personality")
# Return a dict with the UI components for later use
return {
"personality_choice": personality_choice,
"personality_description": personality_description,
"personality_submit": personality_submit,
}
def click_control_personality_injection_stage(
tabs, system_description_without_context, system_description_user_elicitation
):
def respond_personality(personality_choice):
if personality_choice == "Optimist (Friendly, Daring, Confident)":
new_sys_desc_no_ctx = SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_EXT)
new_sys_desc_user_elicitation = SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(
personality=PERSONALITY_EXT
)
message = "Optimist advisor personality is successfully applied."
elif personality_choice == "Pragmatist (Disciplined, Cautious, Practical)":
new_sys_desc_no_ctx = SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_INT)
new_sys_desc_user_elicitation = SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(
personality=PERSONALITY_INT
)
message = "Pragmatist personality is successfully applied."
elif (
personality_choice
== "Misadvisor (Just for fun! Unreliable, Messy, Sarcastic - don't take it seriously!)"
):
new_sys_desc_no_ctx = SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_MISADVISOR)
new_sys_desc_user_elicitation = SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(
personality=PERSONALITY_MISADVISOR
)
message = "Misadvisor personality is successfully applied."
else:
new_sys_desc_no_ctx = SYSTEM_INSTRUCTION_PERSONALITY.format(personality="None")
new_sys_desc_user_elicitation = SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(
personality="None"
)
message = "No personality is applied."
return new_sys_desc_no_ctx, new_sys_desc_user_elicitation, message
# Only pass the personality_choice as input
tabs["personality_submit"].click(
fn=respond_personality,
inputs=[tabs["personality_choice"]],
outputs=[
system_description_without_context,
system_description_user_elicitation,
tabs["personality_description"],
],
)
def click_control_exploration_stage(
tabs, user_id, tab_session, user_preference_elicitation_session, system_description_without_context
):
(
comp,
system_instruction_context,
start_conversation,
msg_button,
continue_button,
chatbot,
msg,
) = (
tabs["comp"],
tabs["system_instruction_context"],
tabs["start_conversation"],
tabs["msg_button"],
tabs["continue_button"],
tabs["chatbot"],
tabs["msg"],
)
system_instruction = ""
start_conversation.click(
lambda user_id, tab_session, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond_start_conversation(
user_id,
tab_session,
history,
system_instruction,
comp,
user_preference_elicitation_data=user_preference_elicitation_session,
system_description_without_context=system_description_without_context,
system_instruction_context=system_instruction_context,
),
[
user_id,
tab_session,
chatbot,
comp,
user_preference_elicitation_session,
system_description_without_context,
system_instruction_context,
],
[tab_session, chatbot, start_conversation, msg_button, continue_button],
)
msg_button.click(
lambda user_id, tab_session, message, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond(
user_id,
tab_session,
message,
tab_session["history"],
system_instruction,
comp,
user_preference_elicitation_data=user_preference_elicitation_session,
system_description_without_context=system_description_without_context,
system_instruction_context=system_instruction_context,
),
[
user_id,
tab_session,
msg,
chatbot,
comp,
user_preference_elicitation_session,
system_description_without_context,
system_instruction_context,
],
[tab_session, msg, chatbot],
)
continue_button.click(
lambda user_id, tab_session, history, comp, user_preference_elicitation_session, system_description_without_context, system_instruction_context: respond_continue(
user_id,
tab_session,
tab_session["history"],
system_instruction,
comp,
user_preference_elicitation_data=user_preference_elicitation_session,
system_description_without_context=system_description_without_context,
system_instruction_context=system_instruction_context,
),
[
user_id,
tab_session,
chatbot,
comp,
user_preference_elicitation_session,
system_description_without_context,
system_instruction_context,
],
[tab_session, chatbot],
)
def click_control_preference_stage(
tabs, user_id, user_preference_elicitation_session, system_description_user_elicitation
):
(
start_conversation,
msg_button,
continue_button,
elicitation_chatbot,
msg,
) = (
tabs["start_conversation"],
tabs["msg_button"],
tabs["continue_button"],
tabs["elicitation_chatbot"],
tabs["msg"],
)
# nonlocal user_id
start_conversation.click(
lambda user_id, user_preference_elicitation_data, history, system_description_user_elicitation: respond_start_conversation(
user_id,
user_preference_elicitation_data,
history,
system_description_user_elicitation,
user_elicitation=True,
),
[user_id, user_preference_elicitation_session, elicitation_chatbot, system_description_user_elicitation],
[user_preference_elicitation_session, elicitation_chatbot, start_conversation, msg_button, continue_button],
)
msg_button.click(
lambda user_id, tab_data, message, history, system_description_user_elicitation: respond(
user_id,
tab_data,
message,
tab_data["history"],
system_description_user_elicitation,
user_elicitation=True,
),
[
user_id,
user_preference_elicitation_session,
msg,
elicitation_chatbot,
system_description_user_elicitation,
],
[user_preference_elicitation_session, msg, elicitation_chatbot],
)
continue_button.click(
lambda user_id, tab_data, history, system_description_user_elicitation: respond_continue(
user_id,
tab_data,
tab_data["history"],
system_description_user_elicitation,
user_elicitation=True,
),
[user_id, user_preference_elicitation_session, elicitation_chatbot, system_description_user_elicitation],
[user_preference_elicitation_session, elicitation_chatbot],
)
def respond(
user_id,
tab_data,
message,
history,
system_instruction,
tab_name=None,
user_elicitation=False,
user_preference_elicitation_data=None,
system_description_without_context=None,
system_instruction_context=None,
):
"""
Return:
msg
chat_history
retrieved_passage
rewritten_query
"""
assert (
tab_name is not None or user_elicitation is True
), "Tab name is required for the start of the conversation unless it is not preference elicitation."
# Add user profile to system instruction
if system_description_without_context is not None and system_instruction_context is not None:
system_instruction = system_description_without_context + "\n" + system_instruction_context
if not user_elicitation:
system_instruction = add_user_profile_to_system_instruction(
user_id,
system_instruction,
user_preference_elicitation_data,
summary=USER_PREFERENCE_SUMMARY,
terminator=terminator,
)
# From string to list [{"role":"user", "content": message}, ...]
history = gradio_to_huggingface_message(history)
# We can implement context window here as we need all the system interaction. We can cut some of the early interactions if needed.
history = conversation_window(history, CONV_WINDOW)
# Add system instruction to the history
history = format_context(system_instruction, history)
# Add user message to the history
history_with_user_utterance = format_user_message(message, history)
# Call API instead of locally handle it
if API_TYPE == "local":
outputs_text, history = generate_response_local_api(history_with_user_utterance, terminator, 128, API_URL)
elif API_TYPE == "together":
outputs_text, history = generate_response_together_api(history_with_user_utterance, 128, TOGETHER_CLIENT)
else:
outputs_text, history = generate_response_debugging(history_with_user_utterance)
# exclude system interaction and store the others in the history
history = huggingface_to_gradio_message(history)
if tab_name is not None:
# Log the user message and response
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": tab_name, "role": "user", "content": message},
# feedback_file_interaction,
# )
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": tab_name, "role": "assistant", "content": outputs_text},
# feedback_file_interaction,
# )
# log_action(user_id, tab_name, "User Message", message)
# log_action(user_id, tab_name, "Response", outputs_text)
# Store the updated history for this tab
tab_data["history"] = history
if user_elicitation:
# save_feedback(
# user_id,
# uuid_this_session,
# "Interaction",
# {"type": "user_elicitation", "role": "user", "content": message},
# feedback_file_interaction,
# )
# save_feedback(
# user_id,
# uuid_this_session,
# "Interaction",
# {"type": "user_elicitation", "role": "assistant", "content": outputs_text},
# feedback_file_interaction,
# )
# log_action(user_id, "User_Elicitation", "User Message", message)
# log_action(user_id, "User_Elicitation", "Response", outputs_text)
tab_data["history"] = history
return tab_data, "", history
def respond_start_conversation(
user_id,
tab_data,
history,
system_instruction,
tab_name=None,
user_elicitation=False,
user_preference_elicitation_data=None,
system_description_without_context=None,
system_instruction_context=None,
):
assert (
tab_name is not None or user_elicitation is True
), "Tab name is required for the start of the conversation unless it is not preference elicitation."
if system_description_without_context is not None and system_instruction_context is not None:
system_instruction = system_description_without_context + "\n" + system_instruction_context
if not user_elicitation:
system_instruction = add_user_profile_to_system_instruction(
user_id,
system_instruction,
user_preference_elicitation_data,
summary=USER_PREFERENCE_SUMMARY,
terminator=terminator,
)
history = gradio_to_huggingface_message(history)
history = format_context(system_instruction, history)
first_message = FIRST_MESSAGE
history_with_user_utterance = format_user_message(first_message, history)
max_length = 128 if user_elicitation else 256
if API_TYPE == "local":
outputs_text, history = generate_response_local_api(
history_with_user_utterance, terminator, max_length, API_URL
)
elif API_TYPE == "together":
outputs_text, history = generate_response_together_api(
history_with_user_utterance, max_length, TOGETHER_CLIENT
)
else:
outputs_text, history = generate_response_debugging(history_with_user_utterance)
# Format
history = huggingface_to_gradio_message(history)
if tab_name is not None:
# Log the user message and response
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": tab_name, "role": "user", "content": first_message},
# feedback_file_interaction,
# )
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": tab_name, "role": "assistant", "content": outputs_text},
# feedback_file_interaction,
# )
tab_data["history"] = history
if user_elicitation:
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": "user_elicitation", "role": "user", "content": first_message},
# feedback_file_interaction,
# )
# save_feedback(
# user_id,
# uuid_this_session,
# "Interaction",
# {"type": "user_elicitation", "role": "assistant", "content": outputs_text},
# feedback_file_interaction,
# )
tab_data["history"] = history
return (
tab_data,
history,
gr.Button(value="Start Conversation", interactive=False),
gr.Button(value="Send This Message to Advisor", interactive=True),
gr.Button(value="Show More of the Advisor’s Answer", interactive=True),
)
def respond_continue(
user_id,
tab_data,
history,
system_instruction,
tab_name=None,
user_elicitation=False,
user_preference_elicitation_data=None,
system_description_without_context=None,
system_instruction_context=None,
):
assert (
tab_name is not None or user_elicitation is True
), "Tab name is required for the start of the conversation."
# Add user profile to system instruction
if system_description_without_context is not None and system_instruction_context is not None:
system_instruction = system_description_without_context + "\n" + system_instruction_context
if not user_elicitation:
system_instruction = add_user_profile_to_system_instruction(
user_id,
system_instruction,
user_preference_elicitation_data,
summary=USER_PREFERENCE_SUMMARY,
terminator=terminator,
)
message = "continue"
history = gradio_to_huggingface_message(history)
history = conversation_window(history, CONV_WINDOW)
history = format_context(system_instruction, history)
history_with_user_utterance = format_user_message(message, history)
if API_TYPE == "local":
outputs_text, history = generate_response_local_api(history_with_user_utterance, terminator, 128, API_URL)
elif API_TYPE == "together":
outputs_text, history = generate_response_together_api(history_with_user_utterance, 128, TOGETHER_CLIENT)
else:
outputs_text, history = generate_response_debugging(history_with_user_utterance)
history = huggingface_to_gradio_message(history)
if tab_name is not None:
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {
# "type": tab_name,
# "role": "user",
# "content": message,
# },
# feedback_file_interaction,
# )
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": tab_name, "role": "assistant", "content": outputs_text},
# feedback_file_interaction,
# )
# Update history for this tab
tab_data["history"] = history
if user_elicitation:
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": "user_elicitation", "role": "user", "content": message},
# feedback_file_interaction,
# )
# save_feedback(
# user_id,
# uuid_this_session,
# "interaction",
# {"type": "user_elicitation", "role": "assistant", "content": outputs_text},
# feedback_file_interaction,
# )
tab_data["history"] = history
return tab_data, history
def get_context(index, raw_context_list, stock_context_list):
comp = raw_context_list[index]["short_name"]
context = stock_context_list[index]
general_instruction, round_instruction = get_task_instruction_for_user(raw_context_list[index])
return comp, context, general_instruction, round_instruction
def set_user_id(request: gr.Request):
# DEBUG
user_id = "user_2_0_0"
# user_id = request.username
user_in_narrative_id = user_id.split("_")[-1]
narrative_id = user_id.split("_")[-2]
experiment_id = user_id.split("_")[-3]
return user_id, user_in_narrative_id, narrative_id, experiment_id
def get_inst_without_context(experiment_id):
# experiment_id = 1 => personalization
# experiment_id = 2 => no personalization
# experiment_id == 3 => ext personality
# experiment_id == 4 => int personality
if experiment_id == "0":
return SYSTEM_INSTRUCTION_PERSONALIZATION
elif experiment_id == "1":
return SYSTEM_INSTRUCTION_NON_PERSONALIZATION
elif experiment_id == "2":
return SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_EXT)
elif experiment_id == "3":
return SYSTEM_INSTRUCTION_PERSONALITY.format(personality=PERSONALITY_INT)
def get_user_preference_elicitation(experiment_id):
if experiment_id == "0" or experiment_id == "1":
return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION
elif experiment_id == "2":
return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(personality=PERSONALITY_EXT)
elif experiment_id == "3":
return SYSTEM_INSTRUCTION_PREFERENCE_ELICITATION_PERSONALITY.format(personality=PERSONALITY_INT)
def get_stock_related_context(narrative_id, user_in_narrative_id):
raw_context_list = build_raw_context_list(context_info_list[int(narrative_id)])
stock_context_list = build_context(context_info_list[int(narrative_id)])
return raw_context_list, stock_context_list
def set_initial_values(request: gr.Request):
# Set user specific information (Session State)
user_id, user_in_narrative_id, narrative_id, experiment_id = set_user_id(request)
user_id = "user_2_0_0"
user_in_narrative_id = "0"
experiment_id = "2"
system_description_without_context = get_inst_without_context(experiment_id)
system_description_user_elicitation = get_user_preference_elicitation(experiment_id)
first_raw_context_list, first_stock_context_list = get_stock_related_context(0, user_in_narrative_id)
second_raw_context_list, second_stock_context_list = get_stock_related_context(1, user_in_narrative_id)
third_raw_context_list, third_stock_context_list = get_stock_related_context(2, user_in_narrative_id)
raw_context_list = first_raw_context_list + second_raw_context_list + third_raw_context_list
stock_context_list = first_stock_context_list + second_stock_context_list + third_stock_context_list
# Tab Context
first_comp, first_context, first_general_instruction, first_round_instruction = get_context(
0, raw_context_list, stock_context_list
)
second_comp, second_context, second_general_instruction, second_round_instruction = get_context(
1, raw_context_list, stock_context_list
)
third_comp, third_context, third_general_instruction, third_round_instruction = get_context(
2, raw_context_list, stock_context_list
)
fourth_comp, fourth_context, fourth_general_instruction, fourth_round_instruction = get_context(
3, raw_context_list, stock_context_list
)
fifth_comp, fifth_context, fifth_general_instruction, fifth_round_instruction = get_context(
4, raw_context_list, stock_context_list
)
sixth_comp, sixth_context, sixth_general_instruction, sixth_round_instruction = get_context(
5, raw_context_list, stock_context_list
)
seventh_comp, seventh_context, seventh_general_instruction, seventh_round_instruction = get_context(
6, raw_context_list, stock_context_list
)
eighth_comp, eighth_context, eighth_general_instruction, eighth_round_instruction = get_context(
7, raw_context_list, stock_context_list
)
ninth_comp, ninth_context, ninth_general_instruction, ninth_round_instruction = get_context(
8, raw_context_list, stock_context_list
)
tenth_comp, tenth_context, tenth_general_instruction, tenth_round_instruction = get_context(
9, raw_context_list, stock_context_list
)
eleventh_comp, eleventh_context, eleventh_general_instruction, eleventh_round_instruction = get_context(
10, raw_context_list, stock_context_list
)
twelfth_comp, twelfth_context, twelfth_general_instruction, twelfth_round_instruction = get_context(
11, raw_context_list, stock_context_list
)
return (
user_id,
user_in_narrative_id,
narrative_id,
experiment_id,
system_description_without_context,
system_description_user_elicitation,
raw_context_list,
stock_context_list,
# user_narrative,
first_comp,
first_context,
first_general_instruction,
# first_round_instruction,
second_comp,
second_context,
second_general_instruction,
# second_round_instruction,
third_comp,
third_context,
third_general_instruction,
# third_round_instruction,
fourth_comp,
fourth_context,
fourth_general_instruction,
# fourth_round_instruction,
fifth_comp,
fifth_context,
fifth_general_instruction,
# fifth_round_instruction,
sixth_comp,
sixth_context,
sixth_general_instruction,
# sixth_round_instruction,
seventh_comp,
seventh_context,
seventh_general_instruction,
# seventh_round_instruction,
eighth_comp,
eighth_context,
eighth_general_instruction,
# eighth_round_instruction,
ninth_comp,
ninth_context,
ninth_general_instruction,
# ninth_round_instruction,
tenth_comp,
tenth_context,
tenth_general_instruction,
# tenth_round_instruction,
eleventh_comp,
eleventh_context,
eleventh_general_instruction,
# eleventh_round_instruction,
twelfth_comp,
twelfth_context,
twelfth_general_instruction,
# twelfth_round_instruction,
)
with gr.Blocks(title="RAG Chatbot Q&A", theme="Soft") as demo:
# Set user specific information (Session State)
user_id = gr.State()
user_in_narrative_id = gr.State()
narrative_id = gr.State()
experiment_id = gr.State()
system_description_without_context = gr.State()
system_description_user_elicitation = gr.State()
# Context data
raw_context_list = gr.State()
stock_context_list = gr.State()
first_comp = gr.State()
first_context = gr.State()
second_comp = gr.State()
second_context = gr.State()
third_comp = gr.State()
third_context = gr.State()
fourth_comp = gr.State()
fourth_context = gr.State()
fifth_comp = gr.State()
fifth_context = gr.State()
sixth_comp = gr.State()
sixth_context = gr.State()
seventh_comp = gr.State()
seventh_context = gr.State()
eighth_comp = gr.State()
eighth_context = gr.State()
ninth_comp = gr.State()
ninth_context = gr.State()
tenth_comp = gr.State()
tenth_context = gr.State()
eleventh_comp = gr.State()
eleventh_context = gr.State()
twelfth_comp = gr.State()
twelfth_context = gr.State()
# Tab data
if DEBUG:
user_preference_elicitation_session = gr.State(
value={
"history": "",
"summary_history": """User Profile collected in the previous conversations: Based on our previous conversation, here's a summary of your investment preferences:
# 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.
# 2. **Value vs. Growth Stocks:** You prefer growth stocks, which have the potential for high returns but may be riskier.
# 3. **Dividend vs. Non-Dividend Stocks:** You're open to both dividend and non-dividend growth stocks, focusing on reinvesting profits for future growth.
# 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.""",
}
)
else:
user_preference_elicitation_session = gr.State(value={"history": "", "summary_history": ""})
first_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
second_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
third_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
fourth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
fifth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
sixth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
seventh_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
eighth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
ninth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
tenth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
eleventh_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
twelfth_comp_session = gr.State(value={"history": [], "selection": "", "reason": ""})
# Demonstration Instruction
with gr.Tab("Demonstration Instruction") as instruction_tab:
gr.HTML(value=INSTRUCTION_PAGE, label="Demonstration Instruction")
# User Preference Elicitation Tab
with gr.Tab("Personality Injection") as personality_injection_tab:
personality_injection_tab = tab_personality_injection()
click_control_personality_injection_stage(
personality_injection_tab, system_description_without_context, system_description_user_elicitation
)
with gr.Tab("User Preference Elicitation") as preference_elicitation_tab:
user_preference_elicitation_tab = tab_creation_preference_stage()
# user_narrative = user_preference_elicitation_tab["user_narrative"]
click_control_preference_stage(
user_preference_elicitation_tab,
user_id,
user_preference_elicitation_session,
system_description_user_elicitation,
)
with gr.Tab("Personalized Stock Assessment") as financial_decision:
# Experiment Tag
first_tab = tab_creation_exploration_stage(0, first_comp, first_context)
click_control_exploration_stage(
first_tab,
user_id,
first_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
second_tab = tab_creation_exploration_stage(1, second_comp, second_context)
click_control_exploration_stage(
second_tab,
user_id,
second_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
third_tab = tab_creation_exploration_stage(2, third_comp, third_context)
click_control_exploration_stage(
third_tab,
user_id,
third_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
fourth_tab = tab_creation_exploration_stage(3, fourth_comp, fourth_context)
click_control_exploration_stage(
fourth_tab,
user_id,
fourth_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
fifth_tab = tab_creation_exploration_stage(4, fifth_comp, fifth_context)
click_control_exploration_stage(
fifth_tab,
user_id,
fifth_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
sixth_tab = tab_creation_exploration_stage(5, sixth_comp, sixth_context)
click_control_exploration_stage(
sixth_tab,
user_id,
sixth_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
seventh_tab = tab_creation_exploration_stage(6, seventh_comp, seventh_context)
click_control_exploration_stage(
seventh_tab,
user_id,
seventh_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
eighth_tab = tab_creation_exploration_stage(7, eighth_comp, eighth_context)
click_control_exploration_stage(
eighth_tab,
user_id,
eighth_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
ninth_tab = tab_creation_exploration_stage(8, ninth_comp, ninth_context)
click_control_exploration_stage(
ninth_tab,
user_id,
ninth_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
tenth_tab = tab_creation_exploration_stage(9, tenth_comp, tenth_context)
click_control_exploration_stage(
tenth_tab,
user_id,
tenth_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
eleventh_tab = tab_creation_exploration_stage(10, eleventh_comp, eleventh_context)
click_control_exploration_stage(
eleventh_tab,
user_id,
eleventh_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
twelfth_tab = tab_creation_exploration_stage(11, twelfth_comp, twelfth_context)
click_control_exploration_stage(
twelfth_tab,
user_id,
twelfth_comp_session,
user_preference_elicitation_session,
system_description_without_context,
)
(
first_general_instruction,
second_general_instruction,
third_general_instruction,
fourth_general_instruction,
fifth_general_instruction,
sixth_general_instruction,
seventh_general_instruction,
eighth_general_instruction,
ninth_general_instruction,
tenth_general_instruction,
eleventh_general_instruction,
twelfth_general_instruction,
) = (
first_tab["general_instruction"],
second_tab["general_instruction"],
third_tab["general_instruction"],
fourth_tab["general_instruction"],
fifth_tab["general_instruction"],
sixth_tab["general_instruction"],
seventh_tab["general_instruction"],
eighth_tab["general_instruction"],
ninth_tab["general_instruction"],
tenth_tab["general_instruction"],
eleventh_tab["general_instruction"],
twelfth_tab["general_instruction"],
)
demo.load(
set_initial_values,
inputs=None,
outputs=[
user_id,
user_in_narrative_id,
narrative_id,
experiment_id,
system_description_without_context,
system_description_user_elicitation,
raw_context_list,
stock_context_list,
# user_narrative,
first_comp,
first_context,
first_general_instruction,
# first_round_instruction,
second_comp,
second_context,
second_general_instruction,
# second_round_instruction,
third_comp,
third_context,
third_general_instruction,
# third_round_instruction,
fourth_comp,
fourth_context,
fourth_general_instruction,
# fourth_round_instruction,
fifth_comp,
fifth_context,
fifth_general_instruction,
# fifth_round_instruction,
sixth_comp,
sixth_context,
sixth_general_instruction,
# sixth_round_instruction,
seventh_comp,
seventh_context,
seventh_general_instruction,
# seventh_round_instruction,
eighth_comp,
eighth_context,
eighth_general_instruction,
# eighth_round_instruction,
ninth_comp,
ninth_context,
ninth_general_instruction,
# ninth_round_instruction,
tenth_comp,
tenth_context,
tenth_general_instruction,
# tenth_round_instruction,
eleventh_comp,
eleventh_context,
eleventh_general_instruction,
# eleventh_round_instruction,
twelfth_comp,
twelfth_context,
twelfth_general_instruction,
# twelfth_round_instruction,
],
)
return demo
if __name__ == "__main__":
file_path = os.path.join(ROOT_FILE, "./data/single_stock_data/experiment_processed_data.jsonl")
topics = [
"healthcare_growth_defensive",
"dividend_value_defensive",
"nondividend_value_cyclical",
]
context_info_list = get_context_list(file_path) # str to List of Dict
# system instruction consist of Task, Personality, and Context
"""
Personality
["extroverted", "introverted"]
["agreeable", "antagonistic"]
["conscientious", "unconscientious"]
["neurotic", "emotionally stable"]
["open to experience", "closed to experience"]]
"""
# Global variables
terminator = ["<eos>", "<unk>", "<sep>", "<pad>", "<cls>", "<mask>"]
demo = create_demo()
user_list, demo_list = load_username_and_pwd()
demo.launch(
share=True,
# auth=("ecir_demo", "ecir_demo"), # user_list[0], user_list[1]
# auth_message="Please enter the username and password to access the demo.",
)