kreemyyyy commited on
Commit
441a231
·
verified ·
1 Parent(s): 358aaac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -84
app.py CHANGED
@@ -1,114 +1,150 @@
1
  import pandas as pd
2
- import openpyxl # ensure XLSX engine is available
3
  import gradio as gr
4
- import uuid
5
  import os
6
-
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
- display_df.to_excel(output_filename, engine='openpyxl', index=False)
 
 
 
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'),
105
- gr.File(label='Download Converted Excel')
106
  ],
107
  title='7-Day Schedule Converter',
108
  description=(
109
  'Upload a 7-column weekly schedule (Models vs Days) with merged or single headers, '
110
- 'then flip between Models→Texters or Texters→Models. Download the result as .xlsx.'
 
111
  ),
112
  flagging_mode='never'
113
  )
114
- iface.launch(server_name='0.0.0.0', server_port=7860)
 
 
 
1
  import pandas as pd
2
+ import openpyxl
3
  import gradio as gr
4
+ import io
5
  import os
6
+ import tempfile
7
+ from datetime import datetime
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
+ if pd.isna(cell):
 
 
52
  continue
53
+ for texter in str(cell).split(','):
54
+ texter = texter.strip()
55
+ if not texter or texter.lower() in ['nan', 'none', '']:
56
+ continue
57
+ assignments.setdefault(texter, {d: [] for d in day_cols})
58
+ assignments[texter][day].append(model)
59
+
60
+ if not assignments:
61
+ result = pd.DataFrame(columns=day_cols)
62
+ first_col_name = 'Texter'
63
+ else:
64
+ index = sorted(assignments.keys())
65
+ result = pd.DataFrame(index=index, columns=day_cols)
66
+ first_col_name = 'Texter'
67
+ for texter, days_map in assignments.items():
68
+ for day in day_cols:
69
+ models = days_map.get(day, [])
70
+ result.at[texter, day] = ', '.join(models) if models else 'OFF'
71
+ else:
72
+ # Texters in rows → Models as rows
73
+ for texter in df.index.astype(str):
74
+ for day in day_cols:
75
+ cell = df.at[texter, day]
76
+ if pd.isna(cell):
77
  continue
78
+ for model in str(cell).split(','):
79
+ model = model.strip()
80
+ if not model or model.lower() in ['nan', 'none', '']:
81
+ continue
82
+ assignments.setdefault(model, {d: [] for d in day_cols})
83
+ assignments[model][day].append(texter)
84
+
85
+ if not assignments:
86
+ result = pd.DataFrame(columns=day_cols)
87
+ first_col_name = 'Model'
88
+ else:
89
+ index = sorted(assignments.keys())
90
+ result = pd.DataFrame(index=index, columns=day_cols)
91
+ first_col_name = 'Model'
92
+ for model, days_map in assignments.items():
93
+ for day in day_cols:
94
+ texters = days_map.get(day, [])
95
+ result.at[model, day] = ', '.join(texters) if texters else 'OFF'
96
 
97
+ # 5. Cleanup axis names
98
+ result.index.name = None
99
+ result.columns.name = None
100
 
101
  # For display, include index as a column
102
+ display_df = result.reset_index().rename(columns={'index': first_col_name})
103
 
104
+ # 6. Create downloadable file
105
+ result_clean = result.copy().fillna('OFF')
106
+
107
+ # Ensure all values are strings
108
+ for col in result_clean.columns:
109
+ result_clean[col] = result_clean[col].astype(str)
110
 
111
+ # Create a temporary file for download
112
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
113
+ temp_dir = tempfile.gettempdir()
114
+ output_filename = f"converted_schedule_{timestamp}.xlsx"
115
+ output_path = os.path.join(temp_dir, output_filename)
116
+
117
+ # Save to Excel file
118
+ with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
119
+ # Reset index to include the first column name
120
+ download_df = result_clean.reset_index().rename(columns={'index': first_col_name})
121
+ download_df.to_excel(writer, sheet_name='Converted Schedule', index=False)
122
 
123
+ return display_df, output_path
124
+
125
+ except Exception as e:
126
+ error_df = pd.DataFrame({'Error': [f"Error processing file: {str(e)}"]})
127
+ return error_df, None
128
+
129
+ # Gradio interface with proper file download
130
  iface = gr.Interface(
131
  fn=convert_schedule,
132
  inputs=[
133
  gr.File(label='Upload Weekly Schedule (.xlsx)', file_count='single', type='filepath'),
134
+ gr.Radio(['A to B', 'B to A'], label='Convert Direction', value='A to B')
135
  ],
136
  outputs=[
137
+ gr.Dataframe(label='Converted Schedule (Preview)'),
138
+ gr.File(label='Download Converted Schedule (.xlsx)')
139
  ],
140
  title='7-Day Schedule Converter',
141
  description=(
142
  'Upload a 7-column weekly schedule (Models vs Days) with merged or single headers, '
143
+ 'then flip between Models→Texters or Texters→Models. '
144
+ 'The converted file will be available for download as an Excel file.'
145
  ),
146
  flagging_mode='never'
147
  )
148
+
149
+ if __name__ == "__main__":
150
+ iface.launch(server_name='0.0.0.0', server_port=7860)