|  | import streamlit as st | 
					
						
						|  | from fuzzywuzzy import process | 
					
						
						|  |  | 
					
						
						|  | def find_name_mismatches(contest_df, projections_df, ownership_df, fpts_df): | 
					
						
						|  |  | 
					
						
						|  | name_columns = [col for col in contest_df.columns if not col in ['BaseName', 'EntryCount']] | 
					
						
						|  |  | 
					
						
						|  | if 'player_names' not in projections_df.columns: | 
					
						
						|  | st.error("No 'player_names' column found in projections file") | 
					
						
						|  | return contest_df, projections_df | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | portfolio_players = set() | 
					
						
						|  | for col in name_columns: | 
					
						
						|  | portfolio_players.update(contest_df[col].unique()) | 
					
						
						|  | projection_players = set(projections_df['player_names'].unique()) | 
					
						
						|  | portfolio_players_list = list(portfolio_players) | 
					
						
						|  | projection_players_list = list(projection_players) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | players_missing_from_projections = list(projection_players - portfolio_players) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | auto_matches = {} | 
					
						
						|  | players_to_process = [] | 
					
						
						|  | for player in players_missing_from_projections: | 
					
						
						|  | if not isinstance(player, str): | 
					
						
						|  | st.warning(f"Skipping non-string value: {player}") | 
					
						
						|  | continue | 
					
						
						|  | closest_matches = process.extract(player, portfolio_players_list, limit=1) | 
					
						
						|  | if closest_matches[0][1] >= 95: | 
					
						
						|  | match_name = closest_matches[0][0] | 
					
						
						|  | auto_matches[player] = match_name | 
					
						
						|  | st.success(f"Automatically matched '{player}' with '{match_name}' ({closest_matches[0][1]}% match)") | 
					
						
						|  | elif closest_matches[0][1] >= 75: | 
					
						
						|  | players_to_process.append(player) | 
					
						
						|  | else: | 
					
						
						|  | st.warning(f"No match found for '{player}'") | 
					
						
						|  |  | 
					
						
						|  | if players_to_process: | 
					
						
						|  | st.warning(f"Found {len(players_to_process)} players that need manual matching") | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | with st.form("name_matching_form"): | 
					
						
						|  |  | 
					
						
						|  | tabs = st.tabs([f"Player {i+1}" for i in range(len(players_to_process))]) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | selections = {} | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | for i, player in enumerate(players_to_process): | 
					
						
						|  | with tabs[i]: | 
					
						
						|  | st.write(f"**Projection Name:** {player}") | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | closest_matches = process.extract(player, portfolio_players_list, limit=3) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | options = [f"{match[0]} ({match[1]}%)" for match in closest_matches] | 
					
						
						|  | options.append("None of these") | 
					
						
						|  |  | 
					
						
						|  | selections[player] = st.radio( | 
					
						
						|  | f"Select correct match:", | 
					
						
						|  | options, | 
					
						
						|  | key=f"radio_{player}" | 
					
						
						|  | ) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | submitted = st.form_submit_button("Apply All Changes") | 
					
						
						|  |  | 
					
						
						|  | if submitted: | 
					
						
						|  |  | 
					
						
						|  | for projection_name, contest_name in auto_matches.items(): | 
					
						
						|  | for col in name_columns: | 
					
						
						|  | contest_df[col] = contest_df[col].replace(contest_name, projection_name) | 
					
						
						|  | ownership_df['Player'] = ownership_df['Player'].replace(contest_name, projection_name) | 
					
						
						|  | fpts_df['Player'] = fpts_df['Player'].replace(contest_name, projection_name) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | for projection_name, selection in selections.items(): | 
					
						
						|  | if selection != "None of these": | 
					
						
						|  | selected_name = selection.split(" (")[0] | 
					
						
						|  | for col in name_columns: | 
					
						
						|  | contest_df[col] = contest_df[col].replace(selected_name, projection_name) | 
					
						
						|  | ownership_df['Player'] = ownership_df['Player'].replace(selected_name, projection_name) | 
					
						
						|  | fpts_df['Player'] = fpts_df['Player'].replace(selected_name, projection_name) | 
					
						
						|  | st.success(f"Replaced '{selected_name}' with '{projection_name}'") | 
					
						
						|  | st.success("All changes applied successfully!") | 
					
						
						|  | return contest_df, projections_df, ownership_df, fpts_df | 
					
						
						|  | else: | 
					
						
						|  | st.success("All players have been automatically matched!") | 
					
						
						|  |  | 
					
						
						|  | for projection_name, contest_name in auto_matches.items(): | 
					
						
						|  | for col in name_columns: | 
					
						
						|  | contest_df[col] = contest_df[col].replace(contest_name, projection_name) | 
					
						
						|  | ownership_df['Player'] = ownership_df['Player'].replace(contest_name, projection_name) | 
					
						
						|  | fpts_df['Player'] = fpts_df['Player'].replace(contest_name, projection_name) | 
					
						
						|  | return contest_df, projections_df, ownership_df, fpts_df | 
					
						
						|  |  |