File size: 4,298 Bytes
cdf2807
41a9969
cdf2807
bc36177
 
cdf2807
41a9969
aa3525b
e22be08
41a9969
40ca158
 
 
a3de3da
41a9969
40ca158
 
 
 
41a9969
40ca158
 
 
 
 
 
 
 
 
cdf2807
41a9969
40ca158
 
 
 
41a9969
40ca158
 
 
41a9969
aa3525b
cdf2807
41a9969
aa3525b
 
40ca158
aa3525b
40ca158
 
aa3525b
 
 
40ca158
 
41a9969
aa3525b
 
 
 
 
 
40ca158
 
aa3525b
40ca158
 
aa3525b
 
 
40ca158
 
aa3525b
 
 
 
 
 
af26c90
41a9969
af26c90
 
bc36177
1fd5317
bc36177
1fd5317
 
41a9969
 
 
bc36177
af26c90
41a9969
aa3525b
 
 
 
 
40ca158
aa3525b
bc36177
 
 
 
aa3525b
41a9969
 
 
 
aa3525b
 
 
cdf2807
eb59eaa
1fd5317
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import pandas as pd
import openpyxl  # ensure XLSX engine is available
import gradio as gr
import uuid
import os

# 7-Day Schedule Converter with explicit iteration and header fill and download support

def convert_schedule(file_path, direction):
    # 1. Load Excel sheet without header to inspect real headers
    raw = pd.read_excel(file_path, header=None)
    header1 = raw.iloc[0,1:].astype(object)
    header2 = raw.iloc[1,1:].astype(object)

    # Decide which header row to use: prefer fully populated second row
    if header2.notna().all() and not header2.str.startswith('Unnamed').any():
        days = header2.tolist()
        data_start = 2
    else:
        # Forward-fill merged first-row headers
        days = []
        last = None
        for val in header1:
            if pd.isna(val) or str(val).startswith('Unnamed'):
                days.append(last)
            else:
                last = str(val)
                days.append(last)
        data_start = 1

    # 2. Load actual data with resolved day columns
    df = pd.read_excel(
        file_path,
        header=data_start,
        index_col=0,
        usecols=[0] + list(range(1, len(days) + 1))
    )
    df.columns = [str(day) for day in days]

    # 3. Retain exactly the original day columns
    day_cols = list(df.columns)

    # 4. Build assignment mapping via explicit iteration
    assignments = {}
    if direction == 'A to B':
        for model in df.index.astype(str):
            for day in day_cols:
                cell = df.at[model, day]
                for texter in str(cell).split(','):
                    texter = texter.strip()
                    if not texter or texter.lower() in ['nan', 'none']:
                        continue
                    assignments.setdefault(texter, {d: [] for d in day_cols})
                    assignments[texter][day].append(model)
        # Create result DataFrame
        index = sorted(assignments.keys())
        result = pd.DataFrame(index=index, columns=day_cols)
        for texter, days_map in assignments.items():
            for day in day_cols:
                models = days_map.get(day, [])
                result.at[texter, day] = ', '.join(models) if models else 'OFF'
    else:
        for texter in df.index.astype(str):
            for day in day_cols:
                cell = df.at[texter, day]
                for model in str(cell).split(','):
                    model = model.strip()
                    if not model or model.lower() in ['nan', 'none']:
                        continue
                    assignments.setdefault(model, {d: [] for d in day_cols})
                    assignments[model][day].append(texter)
        index = sorted(assignments.keys())
        result = pd.DataFrame(index=index, columns=day_cols)
        for model, days_map in assignments.items():
            for day in day_cols:
                texters = days_map.get(day, [])
                result.at[model, day] = ', '.join(texters) if texters else 'OFF'

    # 5. Cleanup axis names
    result.index.name = None
    result.columns.name = None

        # 6. Save to Excel for download, specifying engine
    output_filename = f"converted_{uuid.uuid4().hex}.xlsx"
    # Save under /mnt/data so HF Spaces can serve it
    output_path = os.path.join('/mnt/data', output_filename)
    result.to_excel(output_path, engine='openpyxl', index=True)

    # Return both DataFrame and download path
    return result, output_path

# Gradio UI definition
def main():
    iface = gr.Interface(
        fn=convert_schedule,
        inputs=[
            gr.File(label='Upload Weekly Schedule (.xlsx)', file_count='single', type='filepath'),
            gr.Radio(['A to B', 'B to A'], label='Convert Direction')
        ],
        outputs=[
            gr.Dataframe(label='Converted Schedule'),
            gr.File(label='Download Converted Excel')
        ],
        title='7-Day Schedule Converter',
        description=(
            'Upload a 7-column weekly schedule (Models vs Days) with merged or single headers, '
            'then flip between Models→Texters or Texters→Models. Download the result as .xlsx.'
        ),
        allow_flagging='never'
    )
    iface.launch(server_name='0.0.0.0', server_port=7860)

if __name__ == '__main__':
    main()