File size: 6,798 Bytes
0836e11
9374a4b
0836e11
 
036ae9d
 
9374a4b
8425b4c
 
424218f
0caadca
58c2739
 
 
9374a4b
58c2739
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8425b4c
 
ab6bd39
8425b4c
9374a4b
8425b4c
 
 
0caadca
 
 
8425b4c
 
 
 
 
ab6bd39
5a78c3e
 
9374a4b
0caadca
9374a4b
 
 
 
 
ab6bd39
5a78c3e
c6074bd
9219e07
 
 
e8b7ee1
 
0caadca
036ae9d
9219e07
0836e11
 
9374a4b
0836e11
9374a4b
 
 
 
0836e11
 
9374a4b
 
0836e11
9374a4b
0836e11
9374a4b
 
 
 
0836e11
9374a4b
 
 
 
0836e11
9374a4b
0968051
0dd86af
9374a4b
0836e11
 
 
 
9374a4b
 
0836e11
9374a4b
0836e11
9374a4b
0836e11
 
 
 
9374a4b
0836e11
 
 
 
 
9374a4b
 
 
 
 
0836e11
 
 
 
9374a4b
0836e11
 
 
 
 
9374a4b
 
 
0836e11
 
9374a4b
 
0836e11
 
 
 
 
 
 
 
9374a4b
 
 
0836e11
9374a4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import os
import pandas as pd
import random
import re
from sklearn.preprocessing import MinMaxScaler

# Function to assign main accounts
def assign_main_accounts(creators_file, chatter_files):
    creators = pd.read_excel(creators_file)
    creators.columns = creators.columns.str.strip()

    # Debugging: Check initial columns
    print("DEBUG: Initial Columns in Creator File:", creators.columns)

    # Standardize column names
    column_mapping = {
        "Creator": "Creator",
        "Total earnings": "Total earnings",
        "Subscription": "Subscription",
        "Active Fans": "ActiveFans",
        "Total active fans": "ActiveFans",
    }
    creators.rename(columns={k: v for k, v in column_mapping.items() if k in creators.columns}, inplace=True)

    # Debugging: Check renamed columns
    print("DEBUG: Renamed Columns in Creator File:", creators.columns)

    required_columns = ["Creator", "Total earnings", "Subscription", "ActiveFans"]
    missing_columns = [col for col in required_columns if col not in creators.columns]
    if missing_columns:
        raise KeyError(f"Missing required columns in creators file: {missing_columns}")

    # Process creators file
    creators["Total earnings"] = creators["Total earnings"].replace("[\$,]", "", regex=True).astype(float)
    creators["Subscription"] = creators["Subscription"].replace("[\$,]", "", regex=True).astype(float)
    creators["ActiveFans"] = pd.to_numeric(creators["ActiveFans"], errors="coerce").fillna(0)

    # Normalize data
    scaler = MinMaxScaler()
    creators[["Earnings_Normalized", "Subscriptions_Normalized"]] = scaler.fit_transform(
        creators[["Total earnings", "Subscription"]]
    )
    creators["Penalty Factor"] = 1 - abs(creators["Earnings_Normalized"] - creators["Subscriptions_Normalized"])
    creators["Score"] = (
        0.7 * creators["Earnings_Normalized"] + 0.3 * creators["Subscriptions_Normalized"]
    ) * creators["Penalty Factor"]
    creators["Rank"] = creators["Score"].rank(ascending=False)
    creators = creators.sort_values(by="Rank").reset_index(drop=True)

    processed_creator_file = creators[["Creator", "ActiveFans"]]

    updated_chatter_files = []
    for chatter_file in chatter_files:
        chatters = pd.read_excel(chatter_file)
        chatters.columns = chatters.columns.str.strip()
        if len(chatters) > len(creators):
            raise ValueError("Not enough creators to assign to all chatters.")

        # Assign creators to chatters
        chatters["Main Account"] = creators.iloc[:len(chatters)]["Creator"].values
        updated_chatter_files.append(chatters)

    # Combine all updated chatter files into a single DataFrame
    combined_assignments = pd.concat(updated_chatter_files, ignore_index=True)

    return updated_chatter_files, processed_creator_file, combined_assignments




def save_processed_files(assignments, output_dir):
    """
    Save processed chatter files to the output directory.
    """
    for idx, (shift, data) in enumerate(assignments.items()):
        output_file = os.path.join(output_dir, f"Updated_{shift.lower()}_file.xlsx")
        data.to_excel(output_file, index=False)
        print(f"Saved {shift} file to {output_file}")


# Function to clean chatter data
def clean_chatter_data(chatter_data):
    """
    Clean and prepare chatter data for scheduling.
    """
    required_columns = ["Name", "Main Account", "Final Rating", "Available Work Days"]
    for col in required_columns:
        if col not in chatter_data.columns:
            raise KeyError(f"Missing required column in chatter data: {col}")

    chatter_data["WorkDays"] = pd.to_numeric(chatter_data.get("Available Work Days", 6), errors="coerce").fillna(6).astype(int)
    chatter_data["Desired Off Day"] = chatter_data["Desired Off Day"].fillna("").apply(
        lambda x: [day.strip().capitalize() for day in re.split(r"[ ,]+", x) if day.strip()]
    )

    return chatter_data


# Function to create a blank schedule template
def create_schedule_template(account_data):
    """
    Create a blank schedule template with required columns.
    """
    if "Creator" not in account_data.columns or "ActiveFans" not in account_data.columns:
        raise KeyError("Account data must contain 'Creator' and 'ActiveFans' columns.")

    schedule_template = account_data[["Creator", "ActiveFans"]].copy()
    for day in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]:
        schedule_template[day] = None

    return schedule_template


# Function to assign main accounts to the schedule
def assign_main_accounts_to_schedule(schedule, chatter_data):
    """
    Assign main accounts to the schedule based on chatter data.
    """
    for _, chatter in chatter_data.iterrows():
        main_account = chatter["Main Account"]
        if main_account in schedule["Creator"].values:
            idx = schedule[schedule["Creator"] == main_account].index[0]
            for day in schedule.columns[2:]:
                schedule.at[idx, day] = chatter["Name"]

    return schedule


# Function to assign off days
def assign_off_days(schedule, chatter_data):
    """
    Assign days off for each chatter based on their 'Desired Off Day' field.
    """
    for _, chatter in chatter_data.iterrows():
        for off_day in chatter["Desired Off Day"]:
            if off_day in schedule.columns[2:]:
                schedule.loc[schedule[off_day] == chatter["Name"], off_day] = None
    return schedule


# Function to randomly fill schedule slots
def randomly_fill_slots(schedule, chatter_data, max_accounts_per_day=3, max_fans_per_day=1000):
    """
    Randomly fill remaining slots in the schedule while respecting constraints.
    """
    days_of_week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
    chatters_list = chatter_data["Name"].tolist()

    for day in days_of_week:
        for idx, row in schedule.iterrows():
            if pd.isnull(schedule.at[idx, day]):
                random.shuffle(chatters_list)
                for chatter in chatters_list:
                    schedule.at[idx, day] = chatter
                    break

    return schedule


# Main schedule generation function
def generate_schedule(chatter_files, account_data):
    schedules = {}
    shift_names = ["Overnight", "Day", "Prime"]

    for idx, chatter_df in enumerate(chatter_files):
        shift_name = shift_names[idx]
        chatter_df = clean_chatter_data(chatter_df)
        schedule = create_schedule_template(account_data)
        schedule = assign_main_accounts_to_schedule(schedule, chatter_df)
        schedule = assign_off_days(schedule, chatter_df)
        schedule = randomly_fill_slots(schedule, chatter_df)
        schedules[shift_name] = schedule

    return schedules