kreemyyyy commited on
Commit
2cc4cc3
Β·
verified Β·
1 Parent(s): fa525d3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -77
app.py CHANGED
@@ -7,98 +7,133 @@ import os
7
  # 7-Day Schedule Converter with explicit iteration and header fill and download support
8
 
9
  def convert_schedule(file_path, direction):
10
- # 1. Load raw header rows to determine day labels
11
- raw = pd.read_excel(file_path, header=None)
12
- header1 = raw.iloc[0, 1:].astype(object)
13
- header2 = raw.iloc[1, 1:].astype(object)
 
14
 
15
- # Decide which header row to use: prefer second if fully populated
16
- if header2.notna().all() and not header2.str.startswith('Unnamed').any():
17
- days = header2.tolist()
18
- data_start = 2
19
- else:
20
- # Forward-fill merged first-row headers
21
- days = []
22
- last = None
23
- for val in header1:
24
- if pd.isna(val) or str(val).startswith('Unnamed'):
25
- days.append(last)
26
- else:
27
- last = str(val)
28
- days.append(last)
29
- data_start = 1
30
 
31
- # 2. Load actual data using resolved day columns
32
- df = pd.read_excel(
33
- file_path,
34
- header=data_start,
35
- index_col=0,
36
- usecols=[0] + list(range(1, len(days) + 1))
37
- )
38
- df.columns = [str(day) for day in days]
39
 
40
- # 3. Retain original day column order
41
- day_cols = list(df.columns)
42
 
43
- # 4. Build assignment mapping via explicit iteration
44
- assignments = {}
45
- if direction == 'A to B':
46
- # Models in rows β†’ Texters as rows
47
- for model in df.index.astype(str):
48
- for day in day_cols:
49
- cell = df.at[model, day]
50
- for texter in str(cell).split(','):
51
- texter = texter.strip()
52
- if not texter or texter.lower() in ['nan', 'none']:
53
  continue
54
- assignments.setdefault(texter, {d: [] for d in day_cols})
55
- assignments[texter][day].append(model)
56
- index = sorted(assignments.keys())
57
- result = pd.DataFrame(index=index, columns=day_cols)
58
- first_col_name = 'Texter'
59
- for texter, days_map in assignments.items():
60
- for day in day_cols:
61
- models = days_map.get(day, [])
62
- result.at[texter, day] = ', '.join(models) if models else 'OFF'
63
- else:
64
- # Texters in rows β†’ Models as rows
65
- for texter in df.index.astype(str):
66
- for day in day_cols:
67
- cell = df.at[texter, day]
68
- for model in str(cell).split(','):
69
- model = model.strip()
70
- if not model or model.lower() in ['nan', 'none']:
 
 
 
 
 
 
 
 
71
  continue
72
- assignments.setdefault(model, {d: [] for d in day_cols})
73
- assignments[model][day].append(texter)
74
- index = sorted(assignments.keys())
75
- result = pd.DataFrame(index=index, columns=day_cols)
76
- first_col_name = 'Model'
77
- for model, days_map in assignments.items():
78
- for day in day_cols:
79
- texters = days_map.get(day, [])
80
- result.at[model, day] = ', '.join(texters) if texters else 'OFF'
 
 
 
 
 
 
 
 
 
81
 
82
- # 5. Cleanup axis names
83
- result.index.name = None
84
- result.columns.name = None
85
 
86
- # For display, include index as a column
87
- display_df = result.reset_index().rename(columns={'index': first_col_name})
88
 
89
- # 6. Save to Excel for download (relative path so Gradio can serve it)
90
- output_filename = f"converted_{uuid.uuid4().hex}.xlsx"
91
- result.to_excel(output_filename, engine='openpyxl', index=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- # Return both DataFrame and download path
94
- return display_df, output_filename
 
 
 
 
 
95
 
96
  # Build Gradio interface and launch immediately for Hugging Face Spaces
97
  iface = gr.Interface(
98
  fn=convert_schedule,
99
  inputs=[
100
  gr.File(label='Upload Weekly Schedule (.xlsx)', file_count='single', type='filepath'),
101
- gr.Radio(['A to B', 'B to A'], label='Convert Direction')
102
  ],
103
  outputs=[
104
  gr.Dataframe(label='Converted Schedule'),
@@ -111,5 +146,7 @@ iface = gr.Interface(
111
  ),
112
  flagging_mode='never'
113
  )
 
114
  # Launch on 0.0.0.0:7860 for Spaces
115
- iface.launch(server_name='0.0.0.0', server_port=7860)
 
 
7
  # 7-Day Schedule Converter with explicit iteration and header fill and download support
8
 
9
  def convert_schedule(file_path, direction):
10
+ try:
11
+ # 1. Load raw header rows to determine day labels
12
+ raw = pd.read_excel(file_path, header=None)
13
+ header1 = raw.iloc[0, 1:].astype(object)
14
+ header2 = raw.iloc[1, 1:].astype(object)
15
 
16
+ # Decide which header row to use: prefer second if fully populated
17
+ if header2.notna().all() and not header2.str.startswith('Unnamed').any():
18
+ days = header2.tolist()
19
+ data_start = 2
20
+ else:
21
+ # Forward-fill merged first-row headers
22
+ days = []
23
+ last = None
24
+ for val in header1:
25
+ if pd.isna(val) or str(val).startswith('Unnamed'):
26
+ days.append(last)
27
+ else:
28
+ last = str(val)
29
+ days.append(last)
30
+ data_start = 1
31
 
32
+ # 2. Load actual data using resolved day columns
33
+ df = pd.read_excel(
34
+ file_path,
35
+ header=data_start,
36
+ index_col=0,
37
+ usecols=[0] + list(range(1, len(days) + 1))
38
+ )
39
+ df.columns = [str(day) for day in days]
40
 
41
+ # 3. Retain original day column order
42
+ day_cols = list(df.columns)
43
 
44
+ # 4. Build assignment mapping via explicit iteration
45
+ assignments = {}
46
+ if direction == 'A to B':
47
+ # Models in rows β†’ Texters as rows
48
+ for model in df.index.astype(str):
49
+ for day in day_cols:
50
+ cell = df.at[model, day]
51
+ # Handle NaN values properly
52
+ if pd.isna(cell):
 
53
  continue
54
+ for texter in str(cell).split(','):
55
+ texter = texter.strip()
56
+ if not texter or texter.lower() in ['nan', 'none', '']:
57
+ continue
58
+ assignments.setdefault(texter, {d: [] for d in day_cols})
59
+ assignments[texter][day].append(model)
60
+
61
+ if not assignments: # Handle empty assignments
62
+ result = pd.DataFrame(columns=day_cols)
63
+ first_col_name = 'Texter'
64
+ else:
65
+ index = sorted(assignments.keys())
66
+ result = pd.DataFrame(index=index, columns=day_cols)
67
+ first_col_name = 'Texter'
68
+ for texter, days_map in assignments.items():
69
+ for day in day_cols:
70
+ models = days_map.get(day, [])
71
+ result.at[texter, day] = ', '.join(models) if models else 'OFF'
72
+ else:
73
+ # Texters in rows β†’ Models as rows
74
+ for texter in df.index.astype(str):
75
+ for day in day_cols:
76
+ cell = df.at[texter, day]
77
+ # Handle NaN values properly
78
+ if pd.isna(cell):
79
  continue
80
+ for model in str(cell).split(','):
81
+ model = model.strip()
82
+ if not model or model.lower() in ['nan', 'none', '']:
83
+ continue
84
+ assignments.setdefault(model, {d: [] for d in day_cols})
85
+ assignments[model][day].append(texter)
86
+
87
+ if not assignments: # Handle empty assignments
88
+ result = pd.DataFrame(columns=day_cols)
89
+ first_col_name = 'Model'
90
+ else:
91
+ index = sorted(assignments.keys())
92
+ result = pd.DataFrame(index=index, columns=day_cols)
93
+ first_col_name = 'Model'
94
+ for model, days_map in assignments.items():
95
+ for day in day_cols:
96
+ texters = days_map.get(day, [])
97
+ result.at[model, day] = ', '.join(texters) if texters else 'OFF'
98
 
99
+ # 5. Cleanup axis names
100
+ result.index.name = None
101
+ result.columns.name = None
102
 
103
+ # For display, include index as a column
104
+ display_df = result.reset_index().rename(columns={'index': first_col_name})
105
 
106
+ # 6. Save to Excel for download with better error handling
107
+ output_filename = f"converted_{uuid.uuid4().hex}.xlsx"
108
+
109
+ # Clean the DataFrame before saving
110
+ result_clean = result.copy()
111
+
112
+ # Replace any problematic values
113
+ result_clean = result_clean.fillna('OFF') # Fill NaN with 'OFF'
114
+
115
+ # Ensure all values are strings to avoid Excel compatibility issues
116
+ for col in result_clean.columns:
117
+ result_clean[col] = result_clean[col].astype(str)
118
+
119
+ # Save with additional parameters for better compatibility
120
+ with pd.ExcelWriter(output_filename, engine='openpyxl', mode='w') as writer:
121
+ result_clean.to_excel(writer, sheet_name='Schedule', index=True, header=True)
122
 
123
+ # Return both DataFrame and download path
124
+ return display_df, output_filename
125
+
126
+ except Exception as e:
127
+ # Return error information
128
+ error_df = pd.DataFrame({'Error': [f"Error processing file: {str(e)}"]})
129
+ return error_df, None
130
 
131
  # Build Gradio interface and launch immediately for Hugging Face Spaces
132
  iface = gr.Interface(
133
  fn=convert_schedule,
134
  inputs=[
135
  gr.File(label='Upload Weekly Schedule (.xlsx)', file_count='single', type='filepath'),
136
+ gr.Radio(['A to B', 'B to A'], label='Convert Direction', value='A to B') # Added default value
137
  ],
138
  outputs=[
139
  gr.Dataframe(label='Converted Schedule'),
 
146
  ),
147
  flagging_mode='never'
148
  )
149
+
150
  # Launch on 0.0.0.0:7860 for Spaces
151
+ if __name__ == "__main__":
152
+ iface.launch(server_name='0.0.0.0', server_port=7860)