kreemyyyy commited on
Commit
bce6b06
·
verified ·
1 Parent(s): ce1ddc0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -98
app.py CHANGED
@@ -1,115 +1,175 @@
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 in the working directory
90
- output_filename = f"converted_{uuid.uuid4().hex}.xlsx"
91
- output_path = os.path.join(os.getcwd(), output_filename)
92
- display_df.to_excel(output_path, engine='openpyxl', index=False)
 
 
93
 
94
- # Return both DataFrame and absolute download path
95
- return display_df, output_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
- # Build Gradio interface and launch immediately for Hugging Face Spaces
98
- iface = gr.Interface(
99
- fn=convert_schedule,
100
- inputs=[
101
- gr.File(label='Upload Weekly Schedule (.xlsx)', file_count='single', type='filepath'),
102
- gr.Radio(['A to B', 'B to A'], label='Convert Direction')
103
- ],
104
- outputs=[
105
- gr.Dataframe(label='Converted Schedule'),
106
- gr.File(label='Download Converted Excel')
107
- ],
108
- title='7-Day Schedule Converter',
109
- description=(
110
- 'Upload a 7-column weekly schedule (Models vs Days) with merged or single headers, '
111
- 'then flip between Models→Texters or Texters→Models. Download the result as .xlsx.'
112
- ),
113
- flagging_mode='never'
114
- )
115
- 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 tempfile
5
  import os
6
+ from datetime import datetime
 
7
 
8
  def convert_schedule(file_path, direction):
9
+ if file_path is None:
10
+ return pd.DataFrame({'Error': ['Please upload a file']}), None
11
+
12
+ try:
13
+ # 1. Load raw header rows to determine day labels
14
+ raw = pd.read_excel(file_path, header=None)
15
+ header1 = raw.iloc[0, 1:].astype(object)
16
+ header2 = raw.iloc[1, 1:].astype(object)
17
 
18
+ # Decide which header row to use: prefer second if fully populated
19
+ if header2.notna().all() and not header2.str.startswith('Unnamed').any():
20
+ days = header2.tolist()
21
+ data_start = 2
22
+ else:
23
+ # Forward-fill merged first-row headers
24
+ days = []
25
+ last = None
26
+ for val in header1:
27
+ if pd.isna(val) or str(val).startswith('Unnamed'):
28
+ days.append(last)
29
+ else:
30
+ last = str(val)
31
+ days.append(last)
32
+ data_start = 1
33
 
34
+ # 2. Load actual data using resolved day columns
35
+ df = pd.read_excel(
36
+ file_path,
37
+ header=data_start,
38
+ index_col=0,
39
+ usecols=[0] + list(range(1, len(days) + 1))
40
+ )
41
+ df.columns = [str(day) for day in days]
42
 
43
+ # 3. Retain original day column order
44
+ day_cols = list(df.columns)
45
 
46
+ # 4. Build assignment mapping via explicit iteration
47
+ assignments = {}
48
+ if direction == 'A to B':
49
+ # Models in rows → Texters as rows
50
+ for model in df.index.astype(str):
51
+ for day in day_cols:
52
+ cell = df.at[model, day]
53
+ if pd.isna(cell):
 
 
54
  continue
55
+ for texter in str(cell).split(','):
56
+ texter = texter.strip()
57
+ if not texter or texter.lower() in ['nan', 'none', '']:
58
+ continue
59
+ assignments.setdefault(texter, {d: [] for d in day_cols})
60
+ assignments[texter][day].append(model)
61
+
62
+ if not assignments:
63
+ result = pd.DataFrame(columns=day_cols)
64
+ first_col_name = 'Texter'
65
+ else:
66
+ index = sorted(assignments.keys())
67
+ result = pd.DataFrame(index=index, columns=day_cols)
68
+ first_col_name = 'Texter'
69
+ for texter, days_map in assignments.items():
70
+ for day in day_cols:
71
+ models = days_map.get(day, [])
72
+ result.at[texter, day] = ', '.join(models) if models else 'OFF'
73
+ else:
74
+ # Texters in rows → Models as rows
75
+ for texter in df.index.astype(str):
76
+ for day in day_cols:
77
+ cell = df.at[texter, day]
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:
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. Create downloadable file with proper path handling
107
+ result_clean = result.copy().fillna('OFF')
108
+
109
+ # Ensure all values are strings
110
+ for col in result_clean.columns:
111
+ result_clean[col] = result_clean[col].astype(str)
112
 
113
+ # Create download file in a way that works with Gradio
114
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
115
+ output_filename = f"converted_schedule_{timestamp}.xlsx"
116
+
117
+ # Use tempfile.NamedTemporaryFile but keep it open
118
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx', prefix='schedule_')
119
+ temp_path = temp_file.name
120
+ temp_file.close()
121
+
122
+ # Save to the temporary file
123
+ download_df = result_clean.reset_index().rename(columns={'index': first_col_name})
124
+ download_df.to_excel(temp_path, sheet_name='Converted Schedule', index=False, engine='openpyxl')
125
+
126
+ return display_df, temp_path
127
+
128
+ except Exception as e:
129
+ error_msg = f"Error processing file: {str(e)}"
130
+ print(f"DEBUG: {error_msg}") # For debugging
131
+ error_df = pd.DataFrame({'Error': [error_msg]})
132
+ return error_df, None
133
+
134
+ # Create the interface with better error handling
135
+ def create_interface():
136
+ iface = gr.Interface(
137
+ fn=convert_schedule,
138
+ inputs=[
139
+ gr.File(
140
+ label='Upload Weekly Schedule (.xlsx)',
141
+ file_count='single',
142
+ file_types=['.xlsx', '.xls']
143
+ ),
144
+ gr.Radio(
145
+ ['A to B', 'B to A'],
146
+ label='Convert Direction',
147
+ value='A to B',
148
+ info='A to B: Models→Texters, B to A: Texters→Models'
149
+ )
150
+ ],
151
+ outputs=[
152
+ gr.Dataframe(label='Converted Schedule (Preview)', wrap=True),
153
+ gr.File(label='Download Converted Schedule')
154
+ ],
155
+ title='🔄 7-Day Schedule Converter',
156
+ description=(
157
+ '**How to use:**\n'
158
+ '1. Upload your Excel file with a 7-day schedule\n'
159
+ '2. Choose conversion direction\n'
160
+ '3. Preview the result and download the converted file\n\n'
161
+ '*Supports merged headers and handles Models ↔ Texters conversion*'
162
+ ),
163
+ flagging_mode='never',
164
+ allow_flagging='never'
165
+ )
166
+ return iface
167
 
168
+ if __name__ == "__main__":
169
+ iface = create_interface()
170
+ iface.launch(
171
+ server_name='0.0.0.0',
172
+ server_port=7860,
173
+ share=False,
174
+ debug=True
175
+ )