Spaces:
Sleeping
Sleeping
Ashmi Banerjee
commited on
Commit
·
0759822
1
Parent(s):
90cb4f4
updated with resuming surveys:
Browse files- README.md +2 -1
- app.py +56 -92
- db/crud.py +37 -15
- db/setup.py +5 -1
- views/continue_survey.py +57 -0
- views/intro_screen.py +18 -12
- views/nav_buttons.py +25 -20
- views/questions_screen.py +142 -125
README.md
CHANGED
@@ -26,4 +26,5 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
|
|
26 |
[ ] Implement questions with proper buttons (with text)
|
27 |
[ ] Back button
|
28 |
[ ] Dataset linking
|
29 |
-
[ ] prettify the context field with new lines and highlighting popularity etc. keywords in bold
|
|
|
|
26 |
[ ] Implement questions with proper buttons (with text)
|
27 |
[ ] Back button
|
28 |
[ ] Dataset linking
|
29 |
+
[ ] prettify the context field with new lines and highlighting popularity etc. keywords in bold
|
30 |
+
[ ] Doing it for two models
|
app.py
CHANGED
@@ -2,83 +2,44 @@ import json
|
|
2 |
from typing import Dict
|
3 |
|
4 |
from db.schema import Feedback, Response
|
5 |
-
from db.crud import ingest, read
|
6 |
import pandas as pd
|
7 |
import streamlit as st
|
8 |
from datetime import datetime
|
9 |
import os
|
10 |
from dotenv import load_dotenv
|
11 |
-
from views.intro_screen import
|
12 |
-
from views.questions_screen import
|
|
|
13 |
from css.layout import custom_css
|
14 |
|
15 |
load_dotenv()
|
16 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
17 |
|
18 |
|
19 |
-
class SurveyState:
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
return state
|
43 |
-
except Exception as e:
|
44 |
-
st.error(f"Error loading state from Firebase: {e}")
|
45 |
-
return {}
|
46 |
-
|
47 |
-
class SurveyState:
|
48 |
-
"""Class to handle survey state management"""
|
49 |
-
|
50 |
-
def __init__(self):
|
51 |
-
pass
|
52 |
-
|
53 |
-
@staticmethod
|
54 |
-
def save_state(self, username: str, current_state: Dict) -> None:
|
55 |
-
"""Save current state to Firebase"""
|
56 |
-
try:
|
57 |
-
# Saving to Firebase via the ingest function
|
58 |
-
feedback = Feedback(user_id=username, time_stamp=datetime.now().isoformat(),
|
59 |
-
responses=current_state["responses"])
|
60 |
-
ingest(feedback) # Ingest feedback to Firebase
|
61 |
-
st.success("Your progress has been saved! You can continue later.")
|
62 |
-
except Exception as e:
|
63 |
-
st.error(f"Error saving state to Firebase: {e}")
|
64 |
-
|
65 |
-
def load_state(self, username: str) -> Dict:
|
66 |
-
"""Load state for a specific user from Firebase"""
|
67 |
-
try:
|
68 |
-
# Retrieve the state from Firebase for the given Prolific ID
|
69 |
-
state = self.get_state_from_firebase(username)
|
70 |
-
if state:
|
71 |
-
return state
|
72 |
-
except Exception as e:
|
73 |
-
st.error(f"Error loading state from Firebase: {e}")
|
74 |
-
return {}
|
75 |
-
|
76 |
-
def get_state_from_firebase(self, username: str) -> Dict:
|
77 |
-
# Placeholder method to simulate getting state from Firebase
|
78 |
-
# In practice, you will query Firebase to get the current state
|
79 |
-
data = read(username)
|
80 |
-
return {}
|
81 |
-
|
82 |
|
83 |
def initialization():
|
84 |
"""Initialize session state variables."""
|
@@ -90,8 +51,14 @@ def initialization():
|
|
90 |
st.session_state.responses = []
|
91 |
if "completed" not in st.session_state:
|
92 |
st.session_state.completed = False
|
93 |
-
if "
|
94 |
-
st.session_state.
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
|
97 |
def exit_screen():
|
@@ -109,45 +76,42 @@ def exit_screen():
|
|
109 |
st.rerun()
|
110 |
|
111 |
|
112 |
-
def submit_survey():
|
113 |
-
"""Submit the complete survey"""
|
114 |
-
try:
|
115 |
-
feedback = Feedback(
|
116 |
-
id=st.session_state.current_index,
|
117 |
-
user_id=st.session_state.username,
|
118 |
-
time_stamp=datetime.now().isoformat(),
|
119 |
-
responses=st.session_state.responses,
|
120 |
-
)
|
121 |
-
print(feedback)
|
122 |
-
ingest(feedback)
|
123 |
-
st.session_state.completed = True
|
124 |
-
st.rerun()
|
125 |
-
except Exception as e:
|
126 |
-
st.error(f"An error occurred while submitting feedback: {e}")
|
127 |
-
|
128 |
-
|
129 |
def reset_survey():
|
130 |
"""Reset the survey state to start over."""
|
131 |
-
st.session_state.username = None
|
132 |
-
st.session_state.current_index = 0
|
133 |
st.session_state.responses = []
|
134 |
-
st.session_state.completed = False
|
|
|
135 |
|
136 |
|
137 |
def ui():
|
138 |
"""Main function to control the survey flow."""
|
139 |
custom_css()
|
140 |
-
data = pd.read_csv("data/gemini_results_subset.csv")[:
|
141 |
initialization()
|
142 |
|
143 |
-
if st.session_state.completed:
|
144 |
exit_screen()
|
145 |
return
|
146 |
|
147 |
if st.session_state.username is None:
|
148 |
-
|
149 |
else:
|
150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
|
152 |
|
153 |
if __name__ == "__main__":
|
|
|
2 |
from typing import Dict
|
3 |
|
4 |
from db.schema import Feedback, Response
|
5 |
+
from db.crud import ingest, read, save_feedback
|
6 |
import pandas as pd
|
7 |
import streamlit as st
|
8 |
from datetime import datetime
|
9 |
import os
|
10 |
from dotenv import load_dotenv
|
11 |
+
from views.intro_screen import welcome_screen
|
12 |
+
from views.questions_screen import questions_screen, survey_completed
|
13 |
+
from views.continue_survey import continue_survey_screen
|
14 |
from css.layout import custom_css
|
15 |
|
16 |
load_dotenv()
|
17 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
18 |
|
19 |
|
20 |
+
# class SurveyState:
|
21 |
+
# """Class to handle survey state management"""
|
22 |
+
#
|
23 |
+
# def __init__(self):
|
24 |
+
# pass
|
25 |
+
#
|
26 |
+
# def save_state(self, username: str, current_state: Dict) -> None:
|
27 |
+
# """Save current state to Firebase"""
|
28 |
+
# try:
|
29 |
+
# """Handles feedback submission to the database."""
|
30 |
+
# feedback = Feedback(
|
31 |
+
# id=st.session_state.current_index + 1,
|
32 |
+
# user_id=st.session_state.username,
|
33 |
+
# time_stamp=datetime.now().isoformat(),
|
34 |
+
# responses=st.session_state.responses,
|
35 |
+
# )
|
36 |
+
# save_feedback(feedback)
|
37 |
+
# st.success("Your progress has been saved! You can continue later.")
|
38 |
+
# st.session_state.completed = True
|
39 |
+
# st.rerun()
|
40 |
+
# except Exception as e:
|
41 |
+
# st.error(f"An error occurred while submitting feedback: {e}")
|
42 |
+
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
def initialization():
|
45 |
"""Initialize session state variables."""
|
|
|
51 |
st.session_state.responses = []
|
52 |
if "completed" not in st.session_state:
|
53 |
st.session_state.completed = False
|
54 |
+
if "show_questions" not in st.session_state:
|
55 |
+
st.session_state.show_questions = False
|
56 |
+
if "survey_continued" not in st.session_state:
|
57 |
+
st.session_state.survey_continued = None
|
58 |
+
if "start_new_survey" not in st.session_state:
|
59 |
+
st.session_state.start_new_survey = False
|
60 |
+
# if "survey_state" not in st.session_state:
|
61 |
+
# st.session_state.survey_state = SurveyState()
|
62 |
|
63 |
|
64 |
def exit_screen():
|
|
|
76 |
st.rerun()
|
77 |
|
78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
def reset_survey():
|
80 |
"""Reset the survey state to start over."""
|
|
|
|
|
81 |
st.session_state.responses = []
|
82 |
+
st.session_state.completed = True #TODO: Change to False?
|
83 |
+
st.session_state.start_new_survey = True
|
84 |
|
85 |
|
86 |
def ui():
|
87 |
"""Main function to control the survey flow."""
|
88 |
custom_css()
|
89 |
+
data = pd.read_csv("data/gemini_results_subset.csv")[:5]
|
90 |
initialization()
|
91 |
|
92 |
+
if st.session_state.completed and not st.session_state.start_new_survey:
|
93 |
exit_screen()
|
94 |
return
|
95 |
|
96 |
if st.session_state.username is None:
|
97 |
+
welcome_screen()
|
98 |
else:
|
99 |
+
# Check if user progress exists in Firebase
|
100 |
+
saved_state = read(st.session_state.username)
|
101 |
+
if saved_state:
|
102 |
+
# If there's saved progress and the survey has not been continued, show continue screen
|
103 |
+
if "survey_continued" not in st.session_state or not st.session_state.survey_continued:
|
104 |
+
continue_survey_screen(data)
|
105 |
+
else:
|
106 |
+
if st.session_state.current_index >= len(data):
|
107 |
+
# If all questions have been answered, show the exit screen
|
108 |
+
print("survey completed")
|
109 |
+
survey_completed()
|
110 |
+
# Otherwise, show questions from where they left off
|
111 |
+
questions_screen(data)
|
112 |
+
else:
|
113 |
+
# If no saved progress (new user), start with the questions screen
|
114 |
+
questions_screen(data)
|
115 |
|
116 |
|
117 |
if __name__ == "__main__":
|
db/crud.py
CHANGED
@@ -8,32 +8,44 @@ from db.setup import db_setup
|
|
8 |
def ingest(data: Feedback):
|
9 |
ref = db_setup() # Ensure Firebase is initialized
|
10 |
print(f"Attempting to ingest feedback data from user '{data.user_id}'...")
|
11 |
-
# Check if the user_id already exists in the feedback data
|
12 |
-
# user_id_str = str(data.user_id)
|
13 |
-
# existing_feedback = ref.child('feedback').order_by_child('user_id').equal_to(user_id_str).get()
|
14 |
-
#
|
15 |
-
#
|
16 |
-
# # TODO: This should probably change. If the same user has multiple feedbacks, we should allow it. -> change to update
|
17 |
-
# if existing_feedback:
|
18 |
-
# print(f"Feedback from user '{data.user_id}' already exists. Ingestion aborted.")
|
19 |
-
# else:
|
20 |
-
# # feedback_data = data.dict() # Convert Pydantic model to a dictionary
|
21 |
feedback_data = data.model_dump()
|
22 |
feedback_data["time_stamp"] = feedback_data['time_stamp'].isoformat()
|
23 |
ref.child('feedback').push(feedback_data)
|
24 |
print(f"Feedback data from user '{data.user_id}' pushed to Firebase!")
|
25 |
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
# Read operation (Fetch feedback data from Firebase)
|
28 |
def read(user_id: str):
|
|
|
29 |
ref = db_setup()
|
30 |
feedback_ref = ref.child('feedback').order_by_child('user_id').equal_to(user_id).get()
|
31 |
|
32 |
if feedback_ref:
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
return None
|
37 |
|
38 |
|
39 |
# Update operation (Update feedback data in Firebase)
|
@@ -64,6 +76,17 @@ def delete(feedback_id: int):
|
|
64 |
print("Feedback not found to delete!")
|
65 |
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
def test():
|
68 |
# Create a feedback object
|
69 |
# feedback = Feedback(
|
@@ -101,4 +124,3 @@ def test():
|
|
101 |
#
|
102 |
# # Delete (Remove)
|
103 |
# delete(1)
|
104 |
-
|
|
|
8 |
def ingest(data: Feedback):
|
9 |
ref = db_setup() # Ensure Firebase is initialized
|
10 |
print(f"Attempting to ingest feedback data from user '{data.user_id}'...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
feedback_data = data.model_dump()
|
12 |
feedback_data["time_stamp"] = feedback_data['time_stamp'].isoformat()
|
13 |
ref.child('feedback').push(feedback_data)
|
14 |
print(f"Feedback data from user '{data.user_id}' pushed to Firebase!")
|
15 |
|
16 |
|
17 |
+
def save_feedback(data: Feedback):
|
18 |
+
ref = db_setup() # Ensure Firebase is initialized
|
19 |
+
print(f"Processing feedback for user '{data.user_id}'...")
|
20 |
+
|
21 |
+
# Convert Pydantic model to dictionary
|
22 |
+
feedback_data = data.model_dump()
|
23 |
+
feedback_data["time_stamp"] = feedback_data["time_stamp"].isoformat()
|
24 |
+
|
25 |
+
# Check if the user already has feedback
|
26 |
+
existing_feedback = ref.child("feedback").order_by_child("user_id").equal_to(data.user_id).get()
|
27 |
+
|
28 |
+
if existing_feedback:
|
29 |
+
# Update existing feedback
|
30 |
+
for key in existing_feedback:
|
31 |
+
ref.child("feedback").child(key).update(feedback_data)
|
32 |
+
print(f"Feedback updated for user '{data.user_id}'!")
|
33 |
+
else:
|
34 |
+
# Insert new feedback
|
35 |
+
ref.child("feedback").push(feedback_data)
|
36 |
+
print(f"(Ingestion) New feedback added for user '{data.user_id}'!")
|
37 |
+
|
38 |
+
|
39 |
# Read operation (Fetch feedback data from Firebase)
|
40 |
def read(user_id: str):
|
41 |
+
"""Fetch feedback data for a specific user from Firebase."""
|
42 |
ref = db_setup()
|
43 |
feedback_ref = ref.child('feedback').order_by_child('user_id').equal_to(user_id).get()
|
44 |
|
45 |
if feedback_ref:
|
46 |
+
for key, value in feedback_ref.items():
|
47 |
+
return value # Return the first found entry
|
48 |
+
return None # No progress found
|
|
|
49 |
|
50 |
|
51 |
# Update operation (Update feedback data in Firebase)
|
|
|
76 |
print("Feedback not found to delete!")
|
77 |
|
78 |
|
79 |
+
def reset_feedback_in_db(user_id: str):
|
80 |
+
"""Deletes previous feedback for a user, resetting progress in Firebase."""
|
81 |
+
ref = db_setup()
|
82 |
+
feedback_ref = ref.child('feedback').order_by_child('user_id').equal_to(user_id).get()
|
83 |
+
|
84 |
+
if feedback_ref:
|
85 |
+
for key in feedback_ref:
|
86 |
+
ref.child('feedback').child(key).delete()
|
87 |
+
print(f"Feedback data for user '{user_id}' reset in Firebase.")
|
88 |
+
|
89 |
+
|
90 |
def test():
|
91 |
# Create a feedback object
|
92 |
# feedback = Feedback(
|
|
|
124 |
#
|
125 |
# # Delete (Remove)
|
126 |
# delete(1)
|
|
db/setup.py
CHANGED
@@ -34,6 +34,10 @@ def initialize_firebase():
|
|
34 |
|
35 |
|
36 |
def db_setup():
|
37 |
-
|
|
|
|
|
|
|
|
|
38 |
ref = db.reference('/')
|
39 |
return ref
|
|
|
34 |
|
35 |
|
36 |
def db_setup():
|
37 |
+
try:
|
38 |
+
initialize_firebase()
|
39 |
+
except Exception as e:
|
40 |
+
print(f"Error initializing Firebase: {e}")
|
41 |
+
firebase_admin.get_app()
|
42 |
ref = db.reference('/')
|
43 |
return ref
|
views/continue_survey.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from db.crud import read, reset_feedback_in_db
|
3 |
+
from views.questions_screen import questions_screen
|
4 |
+
|
5 |
+
|
6 |
+
def continue_survey_screen(data):
|
7 |
+
"""Screen for existing users to continue or restart their survey."""
|
8 |
+
st.title("Resume Your Survey")
|
9 |
+
|
10 |
+
st.write("Welcome back! Would you like to continue from where you left off or restart the survey?")
|
11 |
+
|
12 |
+
# Fetch user progress from Firebase
|
13 |
+
saved_state = read(st.session_state.username)
|
14 |
+
|
15 |
+
col1, col2 = st.columns(2)
|
16 |
+
|
17 |
+
with col1:
|
18 |
+
if st.button("Continue"):
|
19 |
+
if saved_state:
|
20 |
+
# Set session state values based on saved progress
|
21 |
+
st.session_state.current_index = saved_state.get("current_index", 0)
|
22 |
+
st.session_state.responses = saved_state.get("responses", [])
|
23 |
+
|
24 |
+
# Find the last answered config_id in responses
|
25 |
+
last_config_id = None
|
26 |
+
if st.session_state.responses:
|
27 |
+
last_config_id = st.session_state.responses[-1].get("config_id")
|
28 |
+
|
29 |
+
# Set the index to the matching config_id
|
30 |
+
if last_config_id is not None:
|
31 |
+
matching_index = data[data["config_id"] == last_config_id].index
|
32 |
+
if not matching_index.empty:
|
33 |
+
st.session_state.current_index = matching_index[0]+1
|
34 |
+
|
35 |
+
st.success("Resuming your survey!")
|
36 |
+
# Set survey_continued flag to True only when there's saved progress
|
37 |
+
st.session_state.survey_continued = True
|
38 |
+
print(st.session_state.current_index)
|
39 |
+
st.rerun()
|
40 |
+
# questions_screen(data)
|
41 |
+
|
42 |
+
else:
|
43 |
+
st.warning("No previous progress found. Starting a new survey.")
|
44 |
+
st.session_state.current_index = 0
|
45 |
+
st.session_state.responses = []
|
46 |
+
|
47 |
+
with col2:
|
48 |
+
if st.button("Restart"):
|
49 |
+
st.session_state.current_index = 0
|
50 |
+
st.session_state.responses = []
|
51 |
+
st.success("Survey restarted!")
|
52 |
+
|
53 |
+
# Reset Firebase data for the user
|
54 |
+
reset_feedback_in_db(st.session_state.username)
|
55 |
+
|
56 |
+
st.rerun()
|
57 |
+
|
views/intro_screen.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
import streamlit as st
|
2 |
import os
|
3 |
from dotenv import load_dotenv
|
|
|
|
|
4 |
|
5 |
load_dotenv()
|
6 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
@@ -15,28 +17,32 @@ def validate_code(input_code: str) -> bool:
|
|
15 |
return input_code.strip() == VALIDATION_CODE
|
16 |
|
17 |
|
18 |
-
def
|
19 |
-
"""Display the
|
20 |
st.title("Welcome to the Feedback Survey")
|
21 |
|
22 |
username_input = st.text_input("Enter your First name and press TAB:")
|
23 |
validation_code_input = st.text_input("Enter the validation code to proceed and press ENTER:")
|
24 |
|
25 |
next_button = st.button("Next")
|
|
|
26 |
if (username_input and validation_code_input) or next_button:
|
27 |
-
# Validate Prolific ID and code
|
28 |
if validate_username(username_input) and validate_code(validation_code_input):
|
29 |
st.session_state.username = username_input
|
30 |
|
31 |
-
#
|
32 |
-
saved_state =
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
|
|
|
|
|
|
|
|
40 |
else:
|
41 |
if not validate_username(username_input):
|
42 |
st.warning("Invalid Prolific ID. Please check and try again.")
|
|
|
1 |
import streamlit as st
|
2 |
import os
|
3 |
from dotenv import load_dotenv
|
4 |
+
from views.continue_survey import continue_survey_screen
|
5 |
+
from db.crud import read
|
6 |
|
7 |
load_dotenv()
|
8 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
|
|
17 |
return input_code.strip() == VALIDATION_CODE
|
18 |
|
19 |
|
20 |
+
def welcome_screen():
|
21 |
+
"""Display the welcome screen and direct users accordingly."""
|
22 |
st.title("Welcome to the Feedback Survey")
|
23 |
|
24 |
username_input = st.text_input("Enter your First name and press TAB:")
|
25 |
validation_code_input = st.text_input("Enter the validation code to proceed and press ENTER:")
|
26 |
|
27 |
next_button = st.button("Next")
|
28 |
+
|
29 |
if (username_input and validation_code_input) or next_button:
|
|
|
30 |
if validate_username(username_input) and validate_code(validation_code_input):
|
31 |
st.session_state.username = username_input
|
32 |
|
33 |
+
# # Check if user progress exists in Firebase
|
34 |
+
# saved_state = read(username_input)
|
35 |
+
#
|
36 |
+
# if saved_state:
|
37 |
+
# # Show continue survey screen for returning users
|
38 |
+
# st.success("Previous progress found.")
|
39 |
+
# continue_survey_screen()
|
40 |
+
# else:
|
41 |
+
# # Start fresh for new users
|
42 |
+
# st.success("Starting a new survey.")
|
43 |
+
# st.session_state.current_index = 0
|
44 |
+
# st.session_state.responses = []
|
45 |
+
# st.rerun()
|
46 |
else:
|
47 |
if not validate_username(username_input):
|
48 |
st.warning("Invalid Prolific ID. Please check and try again.")
|
views/nav_buttons.py
CHANGED
@@ -1,9 +1,5 @@
|
|
1 |
-
import
|
2 |
-
from
|
3 |
-
|
4 |
-
from db.schema import Feedback, Response
|
5 |
-
from db.crud import ingest, read
|
6 |
-
import pandas as pd
|
7 |
import streamlit as st
|
8 |
from datetime import datetime
|
9 |
import os
|
@@ -12,7 +8,23 @@ load_dotenv()
|
|
12 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
13 |
|
14 |
|
15 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
"""Display navigation buttons."""
|
17 |
current_index = st.session_state.current_index
|
18 |
|
@@ -25,22 +37,15 @@ def navigation_buttons(data, rating_v, rating_p0, rating_p1):
|
|
25 |
|
26 |
with col2: # Next button
|
27 |
if st.button("Next"):
|
28 |
-
if
|
29 |
st.warning("Please provide a rating before proceeding.")
|
30 |
else:
|
31 |
if current_index < len(data) - 1:
|
32 |
st.session_state.current_index += 1
|
33 |
st.rerun()
|
34 |
else:
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
)
|
41 |
-
try:
|
42 |
-
ingest(feedback)
|
43 |
-
st.session_state.completed = True
|
44 |
-
st.rerun()
|
45 |
-
except Exception as e:
|
46 |
-
st.error(f"An error occurred while submitting feedback: {e}")
|
|
|
1 |
+
from db.schema import Feedback
|
2 |
+
from db.crud import save_feedback, read
|
|
|
|
|
|
|
|
|
3 |
import streamlit as st
|
4 |
from datetime import datetime
|
5 |
import os
|
|
|
8 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
9 |
|
10 |
|
11 |
+
def submit_feedback(current_index):
|
12 |
+
"""Handles feedback submission to the database."""
|
13 |
+
feedback = Feedback(
|
14 |
+
id=current_index + 1,
|
15 |
+
user_id=st.session_state.username,
|
16 |
+
time_stamp=datetime.now().isoformat(),
|
17 |
+
responses=st.session_state.responses,
|
18 |
+
)
|
19 |
+
try:
|
20 |
+
save_feedback(feedback)
|
21 |
+
st.session_state.completed = True
|
22 |
+
st.rerun()
|
23 |
+
except Exception as e:
|
24 |
+
st.error(f"An error occurred while submitting feedback: {e}")
|
25 |
+
|
26 |
+
|
27 |
+
def navigation_buttons(data, ratings_v, ratings_p0, ratings_p1):
|
28 |
"""Display navigation buttons."""
|
29 |
current_index = st.session_state.current_index
|
30 |
|
|
|
37 |
|
38 |
with col2: # Next button
|
39 |
if st.button("Next"):
|
40 |
+
if any(rating == 0 for rating in [ratings_v, ratings_p0, ratings_p1]):
|
41 |
st.warning("Please provide a rating before proceeding.")
|
42 |
else:
|
43 |
if current_index < len(data) - 1:
|
44 |
st.session_state.current_index += 1
|
45 |
st.rerun()
|
46 |
else:
|
47 |
+
submit_feedback(current_index)
|
48 |
+
|
49 |
+
with col3: # Save & Resume Later button
|
50 |
+
if st.button("Exit & Resume Later"):
|
51 |
+
submit_feedback(current_index)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
views/questions_screen.py
CHANGED
@@ -12,131 +12,148 @@ load_dotenv()
|
|
12 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
13 |
|
14 |
|
15 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
"""Display the questions screen with split layout"""
|
17 |
current_index = st.session_state.current_index
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
st.
|
31 |
-
|
32 |
-
|
33 |
-
st.
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
st.
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
)
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
"
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
comment = st.text_area("Additional Comments (Optional):")
|
123 |
-
|
124 |
-
# Collecting the response data
|
125 |
-
response = Response(
|
126 |
-
config_id=config["config_id"],
|
127 |
-
query_v=query_v_ratings, # Use the ratings dictionary for query_v
|
128 |
-
query_p0=query_p0_ratings, # Use the ratings dictionary for query_p0
|
129 |
-
query_p1=query_p1_ratings, # Use the ratings dictionary for query_p1
|
130 |
-
comment=comment,
|
131 |
-
timestamp=datetime.now().isoformat()
|
132 |
-
)
|
133 |
-
|
134 |
-
# Storing the response
|
135 |
-
print(response)
|
136 |
-
if len(st.session_state.responses) > current_index:
|
137 |
-
st.session_state.responses[current_index] = response
|
138 |
-
else:
|
139 |
-
st.session_state.responses.append(response)
|
140 |
-
|
141 |
-
# Navigation buttons
|
142 |
-
navigation_buttons(data, query_v_ratings["clarity"], query_p0_ratings["clarity"], query_p1_ratings["clarity"])
|
|
|
12 |
VALIDATION_CODE = os.getenv("VALIDATION_CODE")
|
13 |
|
14 |
|
15 |
+
def survey_completed():
|
16 |
+
"""Display the survey completion message."""
|
17 |
+
st.markdown("""
|
18 |
+
<div class='exit-container'>
|
19 |
+
<h1>You have already completed the survey! Thank you for participating!</h1>
|
20 |
+
<p>Your responses have been saved successfully.</p>
|
21 |
+
<p>You can safely close this window or start a new survey.</p>
|
22 |
+
</div>
|
23 |
+
""", unsafe_allow_html=True)
|
24 |
+
st.session_state.show_questions = False
|
25 |
+
st.session_state.completed = True
|
26 |
+
st.session_state.start_new_survey = True
|
27 |
+
# st.rerun()
|
28 |
+
|
29 |
+
|
30 |
+
def questions_screen(data):
|
31 |
+
# TODO: refactor to avoid code duplication
|
32 |
"""Display the questions screen with split layout"""
|
33 |
current_index = st.session_state.current_index
|
34 |
+
try:
|
35 |
+
config = data.iloc[current_index]
|
36 |
+
|
37 |
+
# Progress bar
|
38 |
+
progress = (current_index + 1) / len(data)
|
39 |
+
st.progress(progress)
|
40 |
+
st.write(f"Question {current_index + 1} of {len(data)}")
|
41 |
+
st.subheader(f"Config ID: {config['config_id']}")
|
42 |
+
|
43 |
+
# Context information
|
44 |
+
st.markdown("### Context Information")
|
45 |
+
|
46 |
+
with st.expander("Persona", expanded=True):
|
47 |
+
st.write(config['persona'])
|
48 |
+
|
49 |
+
with st.expander("Filters & Cities", expanded=True):
|
50 |
+
st.write("**Filters:**", config['filters'])
|
51 |
+
st.write("**Cities:**", config['city'])
|
52 |
+
|
53 |
+
with st.expander("Full Context", expanded=False):
|
54 |
+
st.write(config['context'])
|
55 |
+
|
56 |
+
# Split layout for questions and ratings
|
57 |
+
col11, col12, col13, col14 = st.columns([1, 1, 1, 1]) # Sub-columns for query ratings
|
58 |
+
options = [0, 1, 2, 3, 4, 5]
|
59 |
+
|
60 |
+
# Query_v and its ratings
|
61 |
+
st.markdown("### Query_v")
|
62 |
+
st.write(config['query_v'])
|
63 |
+
col_v_1, col_v_2, col_v_3 = st.columns(3)
|
64 |
+
with col_v_1:
|
65 |
+
clarity_rating = st.radio("Clarity:", options, key=f"rating_v_clarity_{current_index}")
|
66 |
+
|
67 |
+
with col_v_2:
|
68 |
+
relevance_rating = st.radio("Relevance:", options, key=f"rating_v_relevance_{current_index}")
|
69 |
+
|
70 |
+
with col_v_3:
|
71 |
+
coverage_rating = st.radio("Coverage:", options, key=f"rating_v_coverage_{current_index}")
|
72 |
+
|
73 |
+
query_v_ratings = {
|
74 |
+
"clarity": clarity_rating,
|
75 |
+
"relevance": relevance_rating,
|
76 |
+
"coverage": coverage_rating,
|
77 |
+
}
|
78 |
+
|
79 |
+
# Query_p0 and its ratings
|
80 |
+
st.markdown("### Query_p0")
|
81 |
+
st.write(config['query_p0'])
|
82 |
+
col_p0_1, col_p0_2, col_p0_3, col_p0_4 = st.columns(4)
|
83 |
+
|
84 |
+
with col_p0_1:
|
85 |
+
clarity_rating = st.radio("Clarity:", options, key=f"rating_p0_clarity_{current_index}")
|
86 |
+
|
87 |
+
with col_p0_2:
|
88 |
+
relevance_rating = st.radio("Relevance:", options, key=f"rating_p0_relevance_{current_index}")
|
89 |
+
|
90 |
+
with col_p0_3:
|
91 |
+
coverage_rating = st.radio("Coverage:", options, key=f"rating_p0_coverage_{current_index}")
|
92 |
+
|
93 |
+
with col_p0_4:
|
94 |
+
persona_alignment_rating = st.radio(
|
95 |
+
"Persona Alignment:", options=[0, 1, 2, 3, 4], # These are the values
|
96 |
+
format_func=lambda x: ["N/A", "Not Aligned", "Partially Aligned", "Aligned", "Unclear"][x],
|
97 |
+
key=f"rating_p0_persona_alignment_{current_index}"
|
98 |
+
)
|
99 |
+
|
100 |
+
# Collecting the ratings for query_p0
|
101 |
+
query_p0_ratings = {
|
102 |
+
"clarity": clarity_rating,
|
103 |
+
"relevance": relevance_rating,
|
104 |
+
"coverage": coverage_rating,
|
105 |
+
"persona_alignment": persona_alignment_rating
|
106 |
+
}
|
107 |
+
|
108 |
+
# Query_p1 and its ratings
|
109 |
+
st.markdown("### Query_p1")
|
110 |
+
st.write(config['query_p1'])
|
111 |
+
# Split the layout into 4 columns for query_p1 ratings
|
112 |
+
col_p1_1, col_p1_2, col_p1_3, col_p1_4 = st.columns(4)
|
113 |
+
|
114 |
+
with col_p1_1:
|
115 |
+
clarity_rating_p1 = st.radio("Clarity:", options, key=f"rating_p1_clarity_{current_index}")
|
116 |
+
|
117 |
+
with col_p1_2:
|
118 |
+
relevance_rating_p1 = st.radio("Relevance:", options, key=f"rating_p1_relevance_{current_index}")
|
119 |
+
|
120 |
+
with col_p1_3:
|
121 |
+
coverage_rating_p1 = st.radio("Coverage:", options, key=f"rating_p1_coverage_{current_index}")
|
122 |
+
|
123 |
+
with col_p1_4:
|
124 |
+
persona_alignment_rating_p1 = st.radio(
|
125 |
+
"Persona Alignment:", options=[0, 1, 2, 3, 4], # These are the values
|
126 |
+
format_func=lambda x: ["N/A", "Not Aligned", "Partially Aligned", "Aligned", "Unclear"][x],
|
127 |
+
key=f"rating_p1_persona_alignment_{current_index}"
|
128 |
+
)
|
129 |
+
|
130 |
+
# Collecting the ratings for query_p1
|
131 |
+
query_p1_ratings = {
|
132 |
+
"clarity": clarity_rating_p1,
|
133 |
+
"relevance": relevance_rating_p1,
|
134 |
+
"coverage": coverage_rating_p1,
|
135 |
+
"persona_alignment": persona_alignment_rating_p1
|
136 |
+
}
|
137 |
+
|
138 |
+
# Additional comments
|
139 |
+
comment = st.text_area("Additional Comments (Optional):")
|
140 |
+
|
141 |
+
# Collecting the response data
|
142 |
+
response = Response(
|
143 |
+
config_id=config["config_id"],
|
144 |
+
query_v=query_v_ratings, # Use the ratings dictionary for query_v
|
145 |
+
query_p0=query_p0_ratings, # Use the ratings dictionary for query_p0
|
146 |
+
query_p1=query_p1_ratings, # Use the ratings dictionary for query_p1
|
147 |
+
comment=comment,
|
148 |
+
timestamp=datetime.now().isoformat()
|
149 |
)
|
150 |
+
if len(st.session_state.responses) > current_index:
|
151 |
+
st.session_state.responses[current_index] = response
|
152 |
+
else:
|
153 |
+
st.session_state.responses.append(response)
|
154 |
+
|
155 |
+
# Navigation buttons
|
156 |
+
navigation_buttons(data, query_v_ratings["clarity"], query_p0_ratings["clarity"], query_p1_ratings["clarity"])
|
157 |
+
except IndexError:
|
158 |
+
print("Survey completed!")
|
159 |
+
# st.stop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|