akhilhsingh commited on
Commit
dfa64f1
·
verified ·
1 Parent(s): e4a18e3

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +168 -0
app.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+ import tempfile
5
+ import os
6
+
7
+
8
+ def calculate_nps(scores):
9
+ scores = np.array(scores)
10
+ total = len(scores)
11
+ if total == 0:
12
+ return 0
13
+ promoters = np.sum((scores == 4) | (scores == 5))
14
+ detractors = np.sum((scores == 1) | (scores == 2))
15
+ return (promoters - detractors) / total * 100
16
+
17
+
18
+ def adjust_nps(file, last_data_row, desired_nps_row, progress=gr.Progress(track_tqdm=False)):
19
+ if file is None:
20
+ raise gr.Error("Please upload an Excel file.")
21
+
22
+ if last_data_row is None or desired_nps_row is None:
23
+ raise gr.Error("Please enter both row numbers.")
24
+
25
+ try:
26
+ progress(0, desc="Reading file...")
27
+ df = pd.read_excel(file.name, sheet_name="Data", header=None)
28
+ except Exception as e:
29
+ raise gr.Error(f"Could not read sheet named 'Data'. Error: {e}")
30
+
31
+ # Convert user-friendly row numbers (e.g., 1503) to 0-based indices
32
+ individual_score_start = 3 # as in your original script
33
+ individual_score_end = int(last_data_row) - 1
34
+ desired_nps_row_idx = int(desired_nps_row) - 1
35
+
36
+ if individual_score_end <= individual_score_start:
37
+ raise gr.Error("LAST data record row must be greater than 4 (since data starts at row 4).")
38
+
39
+ last_column_index = df.shape[1] - 1
40
+ total_columns = last_column_index + 1
41
+
42
+ for col in range(0, last_column_index + 1):
43
+ progress(col / total_columns, desc=f"Processing column {col + 1}/{total_columns}")
44
+
45
+ # Get desired NPS for this column
46
+ try:
47
+ desired_nps = float(df.at[desired_nps_row_idx, col])
48
+ except (ValueError, TypeError):
49
+ continue # skip if not a valid desired NPS
50
+ except KeyError:
51
+ continue
52
+
53
+ original_scores = df.loc[individual_score_start:individual_score_end, col].copy()
54
+ scores = pd.to_numeric(original_scores, errors="coerce").dropna()
55
+
56
+ if len(scores) < 10:
57
+ # Not enough data, skip column
58
+ continue
59
+
60
+ neutral_cap = np.random.uniform(3, 12)
61
+ current_nps = calculate_nps(scores)
62
+ changes = 0
63
+ max_changes = 400
64
+
65
+ while abs(current_nps - desired_nps) > 0.1 and changes < max_changes:
66
+ neutral_percent = (scores == 3).sum() / len(scores) * 100
67
+
68
+ if current_nps > desired_nps:
69
+ # Reduce NPS
70
+ candidates = scores[(scores == 5) | (scores == 4)].index
71
+ if len(candidates):
72
+ idx = np.random.choice(candidates)
73
+ scores.loc[idx] = 4 if scores.loc[idx] == 5 else 3
74
+ changes += 1
75
+ elif neutral_percent > 0:
76
+ candidates = scores[scores == 3].index
77
+ if len(candidates):
78
+ idx = np.random.choice(candidates)
79
+ scores.loc[idx] = 2
80
+ changes += 1
81
+ else:
82
+ break
83
+ else:
84
+ break
85
+ else:
86
+ # Increase NPS
87
+ if neutral_percent < neutral_cap:
88
+ candidates = scores[scores == 2].index
89
+ if len(candidates):
90
+ idx = np.random.choice(candidates)
91
+ scores.loc[idx] = 3
92
+ changes += 1
93
+ else:
94
+ candidates = scores[scores == 3].index
95
+ if len(candidates):
96
+ idx = np.random.choice(candidates)
97
+ scores.loc[idx] = 4
98
+ changes += 1
99
+ else:
100
+ break
101
+ else:
102
+ candidates = scores[scores == 3].index
103
+ if len(candidates):
104
+ idx = np.random.choice(candidates)
105
+ scores.loc[idx] = 4
106
+ changes += 1
107
+ else:
108
+ break
109
+
110
+ current_nps = calculate_nps(scores)
111
+
112
+ # Write back adjusted scores
113
+ df.loc[individual_score_start:individual_score_end, col] = scores
114
+
115
+ progress(1, desc="Writing adjusted file...")
116
+
117
+ # Save output to a temp file and return path
118
+ temp_dir = tempfile.mkdtemp()
119
+ output_path = os.path.join(temp_dir, "NeuroSinQ_NPS_Adjusted.xlsx")
120
+ df.to_excel(output_path, index=False, header=False)
121
+
122
+ return output_path
123
+
124
+
125
+ with gr.Blocks(title="NeuroSinQ NPS Adjuster") as demo:
126
+ gr.Markdown(
127
+ """
128
+ # 🧠 NeuroSinQ NPS Adjuster
129
+
130
+ 1. Upload an Excel file with **one worksheet** named **`Data`**.
131
+ 2. Enter the **row number of LAST data record**.
132
+ 3. Enter the **row number of Desired NPS**.
133
+ 4. Click **Make Adjustment** to download the adjusted file.
134
+ """
135
+ )
136
+
137
+ with gr.Row():
138
+ file_input = gr.File(
139
+ label="Upload Excel File (.xlsx)",
140
+ file_types=[".xlsx"],
141
+ )
142
+
143
+ with gr.Row():
144
+ last_row = gr.Number(
145
+ label="Row number of LAST data record (e.g., 1503)",
146
+ precision=0
147
+ )
148
+ desired_row = gr.Number(
149
+ label="Row number for Desired NPS (e.g., 1523)",
150
+ precision=0
151
+ )
152
+
153
+ run_btn = gr.Button("⚙️ Make Adjustment")
154
+
155
+ output_file = gr.File(
156
+ label="Download Adjusted File",
157
+ interactive=False
158
+ )
159
+
160
+ run_btn.click(
161
+ fn=adjust_nps,
162
+ inputs=[file_input, last_row, desired_row],
163
+ outputs=output_file
164
+ )
165
+
166
+
167
+ if __name__ == "__main__":
168
+ demo.launch()