slevis commited on
Commit
681b063
·
verified ·
1 Parent(s): a36eaa9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -48
app.py CHANGED
@@ -1,19 +1,25 @@
1
  import gradio as gr
2
  import pandas as pd
 
 
 
 
3
 
4
- # --- Konstanten für die Berechnung ---
5
- # These constants are fine as they don't represent a changing state.
6
  GRUNDWERTE = {"Karo": 9, "Herz": 10, "Pik": 11, "Kreuz": 12, "Grand": 24}
7
  NULL_SPIELE = {"Null": 23, "Null Hand": 35, "Null Ouvert": 46, "Null Hand Ouvert": 59}
8
  SPIELER = ["Kirsten", "Robert", "Samuel"]
9
  HISTORY_DF_HEADERS = ["Kirsten", "Robert", "Samuel", "Spielwert", "Spielart", "Alleinspieler", "Details", "Verloren"]
10
 
 
 
 
 
11
 
12
- # --- Hauptfunktionen ---
13
 
14
  def calculate_spielwert(spielart, spitzen_str, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen):
15
- """Berechnet den reinen Spielwert (Reizwert) basierend auf den Spielregeln."""
16
- # This function had no side effects and remains unchanged.
17
  if spielart in NULL_SPIELE:
18
  return NULL_SPIELE[spielart]
19
  if spielart not in GRUNDWERTE or not spitzen_str:
@@ -29,40 +35,30 @@ def calculate_spielwert(spielart, spitzen_str, hand, schneider, schwarz, schneid
29
  grundwert = GRUNDWERTE[spielart]
30
  return (spitzen_anzahl + gewinnstufe) * grundwert
31
 
32
- # --- REFACTURED FUNCTION ---
33
- # No more global variables. The history_df is now passed as an argument.
34
  def spiel_hinzufuegen(history_df, spieler, spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen, verloren):
35
- """
36
- Fügt ein neues Spiel zum History-DataFrame hinzu und berechnet die Gesamtstände dynamisch.
37
- """
38
  spielwert = calculate_spielwert(spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen)
39
-
40
- # This dictionary stores the point change for this single round.
41
  neue_punkte = {name: 0 for name in SPIELER}
42
 
43
- if spieler: # Only if a soloist was selected
44
  if not verloren:
45
- # Soloist wins
46
  neue_punkte[spieler] = 50 + spielwert
47
- # Opponents get penalty points
48
  for p in SPIELER:
49
  if p != spieler:
50
  neue_punkte[p] = -40
51
  else:
52
- # Soloist loses
53
- neue_punkte[spieler] = -50 - (2 * spielwert) # The original had an error, this is the correct calculation for a lost game (-50 and -2*game_value)
54
- # Opponents get points
55
  for p in SPIELER:
56
  if p != spieler:
57
  neue_punkte[p] = 40
58
-
59
  details = f"Spitzen: {spitzen or 'N/A'}"
60
  if hand: details += ", Hand"
61
  if schneider_angesagt: details += ", Schneider angesagt"
62
  if schwarz_angesagt: details += ", Schwarz angesagt"
63
  if offen: details += ", Offen"
64
-
65
- # Create a dictionary for the new row
66
  neues_spiel_eintrag = {
67
  "Kirsten": neue_punkte["Kirsten"],
68
  "Robert": neue_punkte["Robert"],
@@ -73,56 +69,81 @@ def spiel_hinzufuegen(history_df, spieler, spielart, spitzen, hand, schneider, s
73
  "Details": details,
74
  "Verloren": "Ja" if verloren else "Nein"
75
  }
76
-
77
- # --- NEW: STATE MANAGEMENT ---
78
- # Convert the new game entry into a DataFrame of a single row
79
  new_row_df = pd.DataFrame([neues_spiel_eintrag])
80
-
81
- # Append the new row to the existing history DataFrame
82
  updated_history_df = pd.concat([history_df, new_row_df], ignore_index=True)
83
-
84
- # Calculate the totals by summing the columns of the *updated* history DataFrame
85
  total_scores = updated_history_df[SPIELER].sum()
86
- totals_df = pd.DataFrame([total_scores]) # Convert the totals Series to a DataFrame for display
87
-
88
- # Return both updated DataFrames
89
  return totals_df, updated_history_df
90
 
91
- # --- REFACTURED FUNCTION ---
92
- # This function no longer needs to modify globals. It just creates and returns empty DataFrames.
93
  def reset_turnier():
94
- """Setzt den gesamten Spielstand und die Historie zurück."""
95
  empty_totals = pd.DataFrame([{"Kirsten": 0, "Robert": 0, "Samuel": 0}])
96
  empty_history = pd.DataFrame(columns=HISTORY_DF_HEADERS)
97
  return empty_totals, empty_history
98
 
99
- # --- UI Definition mit Gradio ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  with gr.Blocks() as demo:
102
  gr.Markdown("# Skat-Punkte-Tracker")
103
 
104
  gr.Markdown("### Gesamtpunktestand")
105
-
106
- # --- NEW: Initialize DataFrames for the UI ---
107
  initial_totals_df, initial_history_df = reset_turnier()
108
-
109
  totals_output = gr.Dataframe(
110
  value=initial_totals_df,
111
  interactive=False,
112
  show_row_numbers=False
113
  )
114
-
115
  with gr.Row():
116
  with gr.Column(scale=1):
117
  gr.Markdown("### Neues Spiel eingeben")
118
-
119
  spieler_input = gr.Dropdown(SPIELER, label="Alleinspieler")
120
  spielart_input = gr.Dropdown(
121
- choices=['Karo', 'Herz', 'Pik', 'Kreuz', 'Grand', 'Null', 'Null Hand', 'Null Ouvert', 'Null Hand Ouvert'], # Ramsch removed as it's not handled in the logic
122
  label="Spielart"
123
  )
124
  spitzen_input = gr.Dropdown(
125
- choices=[f"{m} {i}" for m in ["Mit", "Ohne"] for i in range(1, 5)], # Normal range is 1-4
126
  label="Spitzen"
127
  )
128
 
@@ -136,11 +157,15 @@ with gr.Blocks() as demo:
136
  schneider_angesagt_input = gr.Checkbox(label="Schneider angesagt")
137
  schwarz_angesagt_input = gr.Checkbox(label="Schwarz angesagt")
138
  offen_input = gr.Checkbox(label="Offen / Ouvert")
139
-
140
  with gr.Row():
141
  speichere_spiel = gr.Button("Speichere Spiel", variant="primary", scale=2)
142
  reset_button = gr.Button("Reset", variant="stop", scale=1)
143
 
 
 
 
 
144
  with gr.Column(scale=2):
145
  gr.Markdown("### Spielverlauf")
146
  turnier_output = gr.Dataframe(
@@ -150,17 +175,13 @@ with gr.Blocks() as demo:
150
  wrap=True
151
  )
152
 
153
- # List of all input components for a new game
154
  inputs_list = [
155
  spieler_input, spielart_input, spitzen_input,
156
  hand_input, schneider_input, schwarz_input,
157
  schneider_angesagt_input, schwarz_angesagt_input, offen_input,
158
  verloren_input
159
  ]
160
-
161
- # --- NEW: Updated Click Handler ---
162
- # The 'turnier_output' DataFrame is now also an INPUT to the function.
163
- # It carries the current state of the game history.
164
  speichere_spiel.click(
165
  fn=spiel_hinzufuegen,
166
  inputs=[turnier_output] + inputs_list,
@@ -173,5 +194,12 @@ with gr.Blocks() as demo:
173
  outputs=[totals_output, turnier_output]
174
  )
175
 
 
 
 
 
 
 
 
176
  if __name__ == "__main__":
177
  demo.launch(share=True)
 
1
  import gradio as gr
2
  import pandas as pd
3
+ from huggingface_hub import HfApi, HfFolder
4
+ import os
5
+ import uuid
6
+ from pathlib import Path
7
 
8
+ # --- Constants for the Calculation ---
 
9
  GRUNDWERTE = {"Karo": 9, "Herz": 10, "Pik": 11, "Kreuz": 12, "Grand": 24}
10
  NULL_SPIELE = {"Null": 23, "Null Hand": 35, "Null Ouvert": 46, "Null Hand Ouvert": 59}
11
  SPIELER = ["Kirsten", "Robert", "Samuel"]
12
  HISTORY_DF_HEADERS = ["Kirsten", "Robert", "Samuel", "Spielwert", "Spielart", "Alleinspieler", "Details", "Verloren"]
13
 
14
+ # --- Hugging Face Configuration ---
15
+ # Define a more descriptive local folder for saving tournament files before upload.
16
+ LOCAL_TOURNAMENT_DIR = Path("saved_tournaments/")
17
+ LOCAL_TOURNAMENT_DIR.mkdir(exist_ok=True) # Ensure the directory exists
18
 
19
+ # --- Core Functions ---
20
 
21
  def calculate_spielwert(spielart, spitzen_str, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen):
22
+ """Calculates the pure game value (Reizwert) based on the game rules."""
 
23
  if spielart in NULL_SPIELE:
24
  return NULL_SPIELE[spielart]
25
  if spielart not in GRUNDWERTE or not spitzen_str:
 
35
  grundwert = GRUNDWERTE[spielart]
36
  return (spitzen_anzahl + gewinnstufe) * grundwert
37
 
 
 
38
  def spiel_hinzufuegen(history_df, spieler, spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen, verloren):
39
+ """Adds a new game to the history DataFrame and dynamically calculates the total scores."""
 
 
40
  spielwert = calculate_spielwert(spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen)
41
+
 
42
  neue_punkte = {name: 0 for name in SPIELER}
43
 
44
+ if spieler:
45
  if not verloren:
 
46
  neue_punkte[spieler] = 50 + spielwert
 
47
  for p in SPIELER:
48
  if p != spieler:
49
  neue_punkte[p] = -40
50
  else:
51
+ neue_punkte[spieler] = -50 - (2 * spielwert)
 
 
52
  for p in SPIELER:
53
  if p != spieler:
54
  neue_punkte[p] = 40
55
+
56
  details = f"Spitzen: {spitzen or 'N/A'}"
57
  if hand: details += ", Hand"
58
  if schneider_angesagt: details += ", Schneider angesagt"
59
  if schwarz_angesagt: details += ", Schwarz angesagt"
60
  if offen: details += ", Offen"
61
+
 
62
  neues_spiel_eintrag = {
63
  "Kirsten": neue_punkte["Kirsten"],
64
  "Robert": neue_punkte["Robert"],
 
69
  "Details": details,
70
  "Verloren": "Ja" if verloren else "Nein"
71
  }
72
+
 
 
73
  new_row_df = pd.DataFrame([neues_spiel_eintrag])
 
 
74
  updated_history_df = pd.concat([history_df, new_row_df], ignore_index=True)
 
 
75
  total_scores = updated_history_df[SPIELER].sum()
76
+ totals_df = pd.DataFrame([total_scores])
77
+
 
78
  return totals_df, updated_history_df
79
 
 
 
80
  def reset_turnier():
81
+ """Resets the entire score and history."""
82
  empty_totals = pd.DataFrame([{"Kirsten": 0, "Robert": 0, "Samuel": 0}])
83
  empty_history = pd.DataFrame(columns=HISTORY_DF_HEADERS)
84
  return empty_totals, empty_history
85
 
86
+ def save_turnier_to_hf(history_df):
87
+ """Saves the current tournament history to a local JSON file and immediately uploads it to the Hugging Face Hub."""
88
+ # Check for Hugging Face token
89
+ if HfFolder.get_token() is None:
90
+ return "Hugging Face Token nicht gefunden. Bitte via `huggingface-cli login` anmelden."
91
+
92
+ # Prevent saving an empty tournament
93
+ if history_df.empty:
94
+ return "Keine Spieldaten zum Speichern vorhanden."
95
+
96
+ # Generate a unique filename for the tournament data to avoid overwriting files.
97
+ tournament_filename = f"skat_tournament_{uuid.uuid4()}.jsonl"
98
+ local_file_path = LOCAL_TOURNAMENT_DIR / tournament_filename
99
+
100
+ # Save the DataFrame to a local JSON Lines file.
101
+ history_df.to_json(local_file_path, orient="records", lines=True, force_ascii=False)
102
+
103
+ # Instantiate the HfApi client to upload the file.
104
+ api = HfApi()
105
+ repo_id = "skat-scores" # A more descriptive repository name
106
+
107
+ try:
108
+ # Upload the file directly. The repo will be created if it doesn't exist.
109
+ api.upload_file(
110
+ path_or_fileobj=local_file_path,
111
+ path_in_repo=f"data/{tournament_filename}",
112
+ repo_id=repo_id,
113
+ repo_type="dataset",
114
+ commit_message=f"Add new skat tournament data: {tournament_filename}"
115
+ )
116
+ return f"Turnier erfolgreich nach '{repo_id}' auf Hugging Face hochgeladen."
117
+ except Exception as e:
118
+ return f"Fehler beim Upload: {e}"
119
+
120
+
121
+ # --- UI Definition with Gradio ---
122
 
123
  with gr.Blocks() as demo:
124
  gr.Markdown("# Skat-Punkte-Tracker")
125
 
126
  gr.Markdown("### Gesamtpunktestand")
127
+
 
128
  initial_totals_df, initial_history_df = reset_turnier()
129
+
130
  totals_output = gr.Dataframe(
131
  value=initial_totals_df,
132
  interactive=False,
133
  show_row_numbers=False
134
  )
135
+
136
  with gr.Row():
137
  with gr.Column(scale=1):
138
  gr.Markdown("### Neues Spiel eingeben")
139
+
140
  spieler_input = gr.Dropdown(SPIELER, label="Alleinspieler")
141
  spielart_input = gr.Dropdown(
142
+ choices=['Karo', 'Herz', 'Pik', 'Kreuz', 'Grand', 'Null', 'Null Hand', 'Null Ouvert', 'Null Hand Ouvert'],
143
  label="Spielart"
144
  )
145
  spitzen_input = gr.Dropdown(
146
+ choices=[f"{m} {i}" for m in ["Mit", "Ohne"] for i in range(1, 5)],
147
  label="Spitzen"
148
  )
149
 
 
157
  schneider_angesagt_input = gr.Checkbox(label="Schneider angesagt")
158
  schwarz_angesagt_input = gr.Checkbox(label="Schwarz angesagt")
159
  offen_input = gr.Checkbox(label="Offen / Ouvert")
160
+
161
  with gr.Row():
162
  speichere_spiel = gr.Button("Speichere Spiel", variant="primary", scale=2)
163
  reset_button = gr.Button("Reset", variant="stop", scale=1)
164
 
165
+ save_to_hf_button = gr.Button("Turnier auf Hugging Face speichern", variant="secondary")
166
+ hf_status_output = gr.Label(value="", label="Upload Status")
167
+
168
+
169
  with gr.Column(scale=2):
170
  gr.Markdown("### Spielverlauf")
171
  turnier_output = gr.Dataframe(
 
175
  wrap=True
176
  )
177
 
 
178
  inputs_list = [
179
  spieler_input, spielart_input, spitzen_input,
180
  hand_input, schneider_input, schwarz_input,
181
  schneider_angesagt_input, schwarz_angesagt_input, offen_input,
182
  verloren_input
183
  ]
184
+
 
 
 
185
  speichere_spiel.click(
186
  fn=spiel_hinzufuegen,
187
  inputs=[turnier_output] + inputs_list,
 
194
  outputs=[totals_output, turnier_output]
195
  )
196
 
197
+ # --- Click Handler for the Hugging Face Button ---
198
+ save_to_hf_button.click(
199
+ fn=save_turnier_to_hf,
200
+ inputs=[turnier_output],
201
+ outputs=[hf_status_output]
202
+ )
203
+
204
  if __name__ == "__main__":
205
  demo.launch(share=True)