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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -120
app.py CHANGED
@@ -1,150 +1,115 @@
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)
 
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)