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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -135
app.py CHANGED
@@ -1,151 +1,114 @@
1
  import pandas as pd
2
- import openpyxl
3
  import gradio as gr
 
 
 
 
4
 
5
  def convert_schedule(file_path, direction):
6
- try:
7
- # 1. Load raw header rows to determine day labels
8
- raw = pd.read_excel(file_path, header=None)
9
- header1 = raw.iloc[0, 1:].astype(object)
10
- header2 = raw.iloc[1, 1:].astype(object)
11
 
12
- # Decide which header row to use: prefer second if fully populated
13
- if header2.notna().all() and not header2.str.startswith('Unnamed').any():
14
- days = header2.tolist()
15
- data_start = 2
16
- else:
17
- # Forward-fill merged first-row headers
18
- days = []
19
- last = None
20
- for val in header1:
21
- if pd.isna(val) or str(val).startswith('Unnamed'):
22
- days.append(last)
23
- else:
24
- last = str(val)
25
- days.append(last)
26
- data_start = 1
27
 
28
- # 2. Load actual data using resolved day columns
29
- df = pd.read_excel(
30
- file_path,
31
- header=data_start,
32
- index_col=0,
33
- usecols=[0] + list(range(1, len(days) + 1))
34
- )
35
- df.columns = [str(day) for day in days]
36
 
37
- # 3. Retain original day column order
38
- day_cols = list(df.columns)
39
 
40
- # 4. Build assignment mapping via explicit iteration
41
- assignments = {}
42
- if direction == 'A to B':
43
- # Models in rows → Texters as rows
44
- for model in df.index.astype(str):
45
- for day in day_cols:
46
- cell = df.at[model, day]
47
- if pd.isna(cell):
 
 
48
  continue
49
- for texter in str(cell).split(','):
50
- texter = texter.strip()
51
- if not texter or texter.lower() in ['nan', 'none', '']:
52
- continue
53
- assignments.setdefault(texter, {d: [] for d in day_cols})
54
- assignments[texter][day].append(model)
55
-
56
- if not assignments:
57
- result = pd.DataFrame(columns=day_cols)
58
- first_col_name = 'Texter'
59
- else:
60
- index = sorted(assignments.keys())
61
- result = pd.DataFrame(index=index, columns=day_cols)
62
- first_col_name = 'Texter'
63
- for texter, days_map in assignments.items():
64
- for day in day_cols:
65
- models = days_map.get(day, [])
66
- result.at[texter, day] = ', '.join(models) if models else 'OFF'
67
- else:
68
- # Texters in rows → Models as rows
69
- for texter in df.index.astype(str):
70
- for day in day_cols:
71
- cell = df.at[texter, day]
72
- if pd.isna(cell):
73
  continue
74
- for model in str(cell).split(','):
75
- model = model.strip()
76
- if not model or model.lower() in ['nan', 'none', '']:
77
- continue
78
- assignments.setdefault(model, {d: [] for d in day_cols})
79
- assignments[model][day].append(texter)
80
-
81
- if not assignments:
82
- result = pd.DataFrame(columns=day_cols)
83
- first_col_name = 'Model'
84
- else:
85
- index = sorted(assignments.keys())
86
- result = pd.DataFrame(index=index, columns=day_cols)
87
- first_col_name = 'Model'
88
- for model, days_map in assignments.items():
89
- for day in day_cols:
90
- texters = days_map.get(day, [])
91
- result.at[model, day] = ', '.join(texters) if texters else 'OFF'
92
 
93
- # 5. Cleanup axis names
94
- result.index.name = None
95
- result.columns.name = None
96
 
97
  # For display, include index as a column
98
- display_df = result.reset_index().rename(columns={'index': first_col_name})
99
-
100
- # 6. Create CSV content as string
101
- result_clean = result.copy().fillna('OFF')
102
-
103
- # Ensure all values are strings
104
- for col in result_clean.columns:
105
- result_clean[col] = result_clean[col].astype(str)
106
 
107
- # Convert to CSV string
108
- csv_content = result_clean.to_csv(index=True)
109
-
110
- return display_df, csv_content
111
 
112
- except Exception as e:
113
- error_df = pd.DataFrame({'Error': [f"Error processing file: {str(e)}"]})
114
- return error_df, f"Error: {str(e)}"
115
-
116
- # Create the interface
117
- with gr.Blocks(title="7-Day Schedule Converter") as iface:
118
- gr.Markdown("# 7-Day Schedule Converter")
119
- gr.Markdown("Upload a 7-column weekly schedule and convert between Models↔Texters")
120
-
121
- with gr.Row():
122
- with gr.Column():
123
- file_input = gr.File(label='Upload Weekly Schedule (.xlsx)', file_count='single', type='filepath')
124
- direction_input = gr.Radio(['A to B', 'B to A'], label='Convert Direction', value='A to B')
125
- convert_btn = gr.Button("Convert Schedule", variant="primary")
126
-
127
- with gr.Row():
128
- output_df = gr.Dataframe(label='Converted Schedule Preview')
129
-
130
- with gr.Row():
131
- csv_output = gr.Textbox(
132
- label="CSV Data - Copy this text and paste into Excel/Google Sheets",
133
- lines=10,
134
- max_lines=20,
135
- placeholder="Converted CSV data will appear here..."
136
- )
137
-
138
- gr.Markdown("### Instructions:")
139
- gr.Markdown("1. After conversion, copy ALL the text from the CSV Data box above")
140
- gr.Markdown("2. Open Excel or Google Sheets")
141
- gr.Markdown("3. Paste the data (it will automatically format into columns)")
142
- gr.Markdown("4. Save as .xlsx file")
143
-
144
- convert_btn.click(
145
- fn=convert_schedule,
146
- inputs=[file_input, direction_input],
147
- outputs=[output_df, csv_output]
148
- )
149
 
150
- if __name__ == "__main__":
151
- 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 (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)