@ -731,21 +731,20 @@ def build_mp_quiz_tab(db_path: str) -> None:
if " mp_quiz_asked " not in st . session_state :
if " mp_quiz_asked " not in st . session_state :
st . session_state [ " mp_quiz_asked " ] = [ ]
st . session_state [ " mp_quiz_asked " ] = [ ]
from database import MotionDatabase as _MotionDatabase
db_inst = _MotionDatabase ( db_path )
df = load_motions_df ( db_path )
df = load_motions_df ( db_path )
if df . empty :
if df . empty :
st . warning ( " Geen moties beschikbaar om de quiz te starten. " )
st . warning ( " Geen moties beschikbaar om de quiz te starten. " )
return
return
# seed motions by controversy_score, prefer those with layman_explanation
# seed from motions that actually have individual MP vote records
candidates_df = df [ df [ " layman_explanation " ] . notna ( ) ]
seed_ids = db_inst . get_motions_with_individual_votes ( k = SEED_MOTIONS )
if candidates_df . empty :
if not seed_ids :
candidates_df = df
st . warning ( " Geen individuele stemdata beschikbaar voor de quiz. " )
seed = (
return
candidates_df . sort_values ( by = " controversy_score " , ascending = False )
. head ( SEED_MOTIONS )
. copy ( )
)
seed_ids = [ int ( x ) for x in seed [ " id " ] . tolist ( ) ]
# Determine next motion to ask
# Determine next motion to ask
def _next_motion_id ( ) :
def _next_motion_id ( ) :
@ -755,13 +754,12 @@ def build_mp_quiz_tab(db_path: str) -> None:
return mid
return mid
# otherwise ask discriminating motion based on remaining candidate MPs
# otherwise ask discriminating motion based on remaining candidate MPs
# compute current candidate set
# compute current candidate set
from database import db as global_db
try :
try :
user_votes = {
user_votes = {
int ( k ) : v for k , v in st . session_state [ " mp_quiz_votes " ] . items ( )
int ( k ) : v for k , v in st . session_state [ " mp_quiz_votes " ] . items ( )
}
}
ranked = global_ db. match_mps_for_votes ( user_votes , limit = 200 )
ranked = db_inst . match_mps_for_votes ( user_votes , limit = 200 )
except Exception :
except Exception :
ranked = [ ]
ranked = [ ]
@ -770,9 +768,7 @@ def build_mp_quiz_tab(db_path: str) -> None:
if not candidates :
if not candidates :
return None
return None
try :
try :
next_ids = global_db . choose_discriminating_motions (
next_ids = db_inst . choose_discriminating_motions ( candidates , excluded , k = 1 )
candidates , excluded , k = 1
)
return next_ids [ 0 ] if next_ids else None
return next_ids [ 0 ] if next_ids else None
except Exception :
except Exception :
return None
return None
@ -786,14 +782,20 @@ def build_mp_quiz_tab(db_path: str) -> None:
if st . button ( " Reset quiz " ) :
if st . button ( " Reset quiz " ) :
st . session_state [ " mp_quiz_votes " ] = { }
st . session_state [ " mp_quiz_votes " ] = { }
st . session_state [ " mp_quiz_asked " ] = [ ]
st . session_state [ " mp_quiz_asked " ] = [ ]
st . experimental_ rerun( )
st . rerun ( )
# main question loop (single question per render)
# main question loop (single question per render)
next_mid = _next_motion_id ( )
next_mid = _next_motion_id ( )
if next_mid is None :
if next_mid is None :
st . info ( " Geen nieuwe vragen beschikbaar om kandidaten te scheiden. " )
st . info ( " Geen nieuwe vragen beschikbaar om kandidaten te scheiden. " )
else :
else :
motion_row = df [ df [ " id " ] == next_mid ] . iloc [ 0 ]
motion_rows = df [ df [ " id " ] == next_mid ]
if motion_rows . empty :
# motion has votes but isn't in the motions DataFrame — skip it
st . session_state [ " mp_quiz_votes " ] [ str ( next_mid ) ] = " Geen stem "
st . rerun ( )
return
motion_row = motion_rows . iloc [ 0 ]
st . markdown ( f " ### { motion_row . get ( ' title ' ) or f ' Motie # { next_mid } ' } " )
st . markdown ( f " ### { motion_row . get ( ' title ' ) or f ' Motie # { next_mid } ' } " )
if motion_row . get ( " layman_explanation " ) :
if motion_row . get ( " layman_explanation " ) :
st . info ( motion_row . get ( " layman_explanation " ) )
st . info ( motion_row . get ( " layman_explanation " ) )
@ -808,14 +810,12 @@ def build_mp_quiz_tab(db_path: str) -> None:
if st . button ( " Beantwoord en verder " , key = f " mp_quiz_submit_ { next_mid } " ) :
if st . button ( " Beantwoord en verder " , key = f " mp_quiz_submit_ { next_mid } " ) :
st . session_state [ " mp_quiz_votes " ] [ str ( next_mid ) ] = choice
st . session_state [ " mp_quiz_votes " ] [ str ( next_mid ) ] = choice
st . session_state [ " mp_quiz_asked " ] . append ( next_mid )
st . session_state [ " mp_quiz_asked " ] . append ( next_mid )
st . experimental_ rerun( )
st . rerun ( )
# display current ranking
# display current ranking
from database import db as global_db
try :
try :
user_votes = { int ( k ) : v for k , v in st . session_state [ " mp_quiz_votes " ] . items ( ) }
user_votes = { int ( k ) : v for k , v in st . session_state [ " mp_quiz_votes " ] . items ( ) }
ranking = global_ db. match_mps_for_votes ( user_votes , limit = 50 )
ranking = db_inst . match_mps_for_votes ( user_votes , limit = 50 )
except Exception :
except Exception :
ranking = [ ]
ranking = [ ]
@ -901,9 +901,9 @@ def run_app() -> None:
build_search_tab ( db_path , show_rejected )
build_search_tab ( db_path , show_rejected )
with tab4 :
with tab4 :
build_browser_tab ( db_path , show_rejected )
build_browser_tab ( db_path , show_rejected )
with tab6 :
build_mp_quiz_tab ( db_path )
with tab5 :
with tab5 :
build_mp_quiz_tab ( db_path )
with tab6 :
build_svd_components_tab ( db_path )
build_svd_components_tab ( db_path )
else :
else :
# Fallback for environments where `st.tabs` is not available: use a radio selector
# Fallback for environments where `st.tabs` is not available: use a radio selector