gtani commited on
Commit
1fd1f1d
·
verified ·
1 Parent(s): ef0959f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -68
app.py CHANGED
@@ -1,4 +1,3 @@
1
- # app.py
2
  import os, base64
3
  import gradio as gr
4
  import pandas as pd
@@ -10,7 +9,7 @@ LOGO_PATH = Path("rowsquared-logo-large.png")
10
  with open(LOGO_PATH, "rb") as f:
11
  logo_b64 = base64.b64encode(f.read()).decode()
12
 
13
- # --- load your ISCO hierarchy and build nested dict (as before) ---
14
  PROCESSED_DATA_DIR = Path(".")
15
  df_isco = (
16
  pd.read_excel(
@@ -25,34 +24,33 @@ for _, r in df_isco.iterrows():
25
  .setdefault(r.sub_major_label, {})\
26
  .setdefault(r.minor_label, [])\
27
  .append(r.unit_label)
28
- # dedupe & sort units
29
  for maj in hierarchy:
30
  for sub in hierarchy[maj]:
31
  for mn in hierarchy[maj][sub]:
32
  hierarchy[maj][sub][mn] = sorted(dict.fromkeys(hierarchy[maj][sub][mn]))
33
 
34
- def majors(): return sorted(hierarchy.keys())
35
- def submajors(m):return sorted(hierarchy.get(m,{}).keys())
36
- def minors(m,s): return sorted(hierarchy.get(m,{}).get(s,{}).keys())
37
- def units(m,s,n):return hierarchy.get(m,{}).get(s,{}).get(n,[])
38
 
39
- # --- load your records (same as before) ---
40
  records = pd.read_excel(PROCESSED_DATA_DIR/"isco_predictions.xlsx").copy()
41
  for c in ["major_label","sub_major_label","minor_label","unit_label"]:
42
- if c not in records: records[c]=""
43
- if "annotated" not in records: records["annotated"]=False
44
  records.reset_index(drop=True,inplace=True)
45
 
46
- # --- clamp + save + load + handlers (copy in your code) ---
47
  def clamp_path(maj,sub,mn,un):
48
  maj_c = majors()
49
- if maj not in maj_c: maj = maj_c[0] if maj_c else ""
50
  sub_c = submajors(maj)
51
- if sub not in sub_c: sub = sub_c[0] if sub_c else ""
52
  mn_c = minors(maj,sub)
53
- if mn not in mn_c: mn = mn_c[0] if mn_c else ""
54
  un_c = units(maj,sub,mn)
55
- if un not in un_c: un = un_c[0] if un_c else ""
56
  return maj,sub,mn,un, maj_c,sub_c,mn_c,un_c
57
 
58
  def save_record(i,maj,sub,mn,un):
@@ -64,10 +62,8 @@ def status_text(i):
64
 
65
  def load_record(i):
66
  r = records.loc[i]
67
- maj,sub,mn,un,maj_c,sub_c,mn_c,un_c = clamp_path(
68
- r.major_label, r.sub_major_label, r.minor_label, r.unit_label
69
- )
70
- save_record(i, maj,sub,mn,un)
71
  md = f"## Occupation: {r.occupation_title_main}\n## Industry: {r.industry_title_main}"
72
  return (
73
  md,
@@ -79,15 +75,15 @@ def load_record(i):
79
  )
80
 
81
  def on_major_change(new_maj,i):
82
- sub_c = submajors(new_maj); sub = sub_c[0] if sub_c else ""
83
- mn_c = minors(new_maj,sub); mn = mn_c[0] if mn_c else ""
84
  un_c = units(new_maj,sub,mn); un = un_c[0] if un_c else ""
85
  save_record(i,new_maj,sub,mn,un)
86
  return (
87
- gr.update(choices=majors(),value=new_maj),
88
- gr.update(choices=sub_c,value=sub),
89
- gr.update(choices=mn_c,value=mn),
90
- gr.update(choices=un_c,value=un),
91
  status_text(i),
92
  )
93
 
@@ -98,8 +94,8 @@ def on_sub_change(new_sub,i,maj):
98
  records.loc[i,"annotated"]=True
99
  return (
100
  gr.update(choices=submajors(maj),value=new_sub),
101
- gr.update(choices=mn_c,value=mn),
102
- gr.update(choices=un_c,value=un),
103
  status_text(i),
104
  )
105
 
@@ -109,13 +105,13 @@ def on_minor_change(new_mn,i,maj,sub):
109
  records.loc[i,"annotated"]=True
110
  return (
111
  gr.update(choices=minors(maj,sub),value=new_mn),
112
- gr.update(choices=un_c,value=un),
113
  status_text(i),
114
  )
115
 
116
  def on_unit_change(new_un,i,maj,sub,mn):
117
  un_c=units(maj,sub,mn)
118
- if new_un not in un_c: new_un = un_c[0] if un_c else ""
119
  records.loc[i,"unit_label"]=new_un
120
  records.loc[i,"annotated"]=True
121
  return gr.update(choices=un_c,value=new_un), status_text(i)
@@ -123,73 +119,76 @@ def on_unit_change(new_un,i,maj,sub,mn):
123
  def go_next(i): return (i+1)%len(records)
124
  def go_prev(i): return (i-1)%len(records)
125
 
126
- def save_and_jump(i,dir):
127
- # clamp and save first
128
  r=records.loc[i]
129
- maj,sub,mn,un,*_ = clamp_path(r.major_label, r.sub_major_label, r.minor_label, r.unit_label)
130
  save_record(i,maj,sub,mn,un)
131
- j = go_next(i) if dir=="next" else go_prev(i)
132
  return (j,)+load_record(j)
133
 
134
  def download_csv():
135
- path = PROCESSED_DATA_DIR/"annotated_output.csv"
136
- records.to_csv(path,index=False)
137
- return str(path)
138
 
139
- # --- now build the Blocks with a login gate ---
140
  def build_gradio_app():
141
  USER = os.getenv("APP_USER","")
142
  PWD = os.getenv("APP_PASS","")
143
 
144
  with gr.Blocks() as demo:
145
- gr.HTML(f"""<style>
146
- footer, .share-link, .api-link {{display:none!important}}
147
- #logo {{margin-bottom:1em}}
148
- #title{{text-align:center;margin-bottom:1em}}
149
  </style>""")
150
 
151
- # login panel
152
- with gr.Column(elem_id="login_panel"):
153
- gr.HTML(f'<img id="logo" src="data:image/png;base64,{logo_b64}" width="180" '
154
- 'style="pointer-events:none;user-select:none;display:block;margin:auto;" />')
155
- user_in = gr.Textbox(label="Username")
156
- pass_in = gr.Textbox(label="Password", type="password")
157
- login_btn= gr.Button("🔒 Log in")
158
- login_msg= gr.Markdown("", visible=False)
159
-
160
- # main app panel (hidden until auth)
161
- with gr.Column(elem_id="app_panel", visible=False):
162
- gr.HTML(f'<img id="logo" src="data:image/png;base64,{logo_b64}" width="180" '
163
- 'style="pointer-events:none;user-select:none;display:block;margin:auto;" />')
164
  gr.Markdown("# ISCO Annotation", elem_id="title")
165
  idx_state = gr.State(0)
166
  record_md = gr.Markdown()
167
  status_md = gr.Markdown()
168
- with gr.Row():
169
- prev_btn = gr.Button(" Previous")
170
- next_btn = gr.Button(" Next")
171
- with gr.Row():
172
- major_radio = gr.Radio("Level 1: Major", choices=[], interactive=True)
173
- sub_radio = gr.Radio("Level 2: Sub-major", choices=[], interactive=True)
174
- minor_radio = gr.Radio("Level 3: Minor", choices=[], interactive=True)
175
- unit_radio = gr.Radio("Level 4: Unit", choices=[], interactive=True)
176
  download_btn = gr.Button("📥 Download CSV")
177
  download_file = gr.File(visible=False)
178
 
179
- # login logic
180
  def check_creds(u,p):
181
  if u==USER and p==PWD:
182
- return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), ""
 
 
 
 
 
183
  else:
184
- return None, None, gr.update(visible=True,value="❌ Bad credentials"), ""
 
 
185
 
186
  login_btn.click(
187
  check_creds,
188
  inputs=[user_in,pass_in],
189
- outputs=[login_panel, app_panel, login_msg, user_in]
190
  )
191
 
192
- # app logic wiring
193
  demo.load(lambda: (0,)+load_record(0),
194
  outputs=[idx_state,record_md,status_md,
195
  major_radio,sub_radio,minor_radio,unit_radio])
@@ -224,4 +223,6 @@ def build_gradio_app():
224
 
225
  if __name__=="__main__":
226
  demo = build_gradio_app()
227
- demo.queue().launch(show_api=False, share=True)
 
 
 
 
1
  import os, base64
2
  import gradio as gr
3
  import pandas as pd
 
9
  with open(LOGO_PATH, "rb") as f:
10
  logo_b64 = base64.b64encode(f.read()).decode()
11
 
12
+ # --- load your ISCO hierarchy and build nested dict ---
13
  PROCESSED_DATA_DIR = Path(".")
14
  df_isco = (
15
  pd.read_excel(
 
24
  .setdefault(r.sub_major_label, {})\
25
  .setdefault(r.minor_label, [])\
26
  .append(r.unit_label)
 
27
  for maj in hierarchy:
28
  for sub in hierarchy[maj]:
29
  for mn in hierarchy[maj][sub]:
30
  hierarchy[maj][sub][mn] = sorted(dict.fromkeys(hierarchy[maj][sub][mn]))
31
 
32
+ def majors(): return sorted(hierarchy.keys())
33
+ def submajors(m): return sorted(hierarchy.get(m,{}).keys())
34
+ def minors(m,s): return sorted(hierarchy.get(m,{}).get(s,{}).keys())
35
+ def units(m,s,n): return hierarchy.get(m,{}).get(s,{}).get(n,[])
36
 
37
+ # --- load your records ---
38
  records = pd.read_excel(PROCESSED_DATA_DIR/"isco_predictions.xlsx").copy()
39
  for c in ["major_label","sub_major_label","minor_label","unit_label"]:
40
+ if c not in records: records[c] = ""
41
+ if "annotated" not in records: records["annotated"] = False
42
  records.reset_index(drop=True,inplace=True)
43
 
44
+ # --- clamp + save + load + handlers ---
45
  def clamp_path(maj,sub,mn,un):
46
  maj_c = majors()
47
+ maj = maj if maj in maj_c else (maj_c[0] if maj_c else "")
48
  sub_c = submajors(maj)
49
+ sub = sub if sub in sub_c else (sub_c[0] if sub_c else "")
50
  mn_c = minors(maj,sub)
51
+ mn = mn if mn in mn_c else (mn_c[0] if mn_c else "")
52
  un_c = units(maj,sub,mn)
53
+ un = un if un in un_c else (un_c[0] if un_c else "")
54
  return maj,sub,mn,un, maj_c,sub_c,mn_c,un_c
55
 
56
  def save_record(i,maj,sub,mn,un):
 
62
 
63
  def load_record(i):
64
  r = records.loc[i]
65
+ maj,sub,mn,un,maj_c,sub_c,mn_c,un_c = clamp_path(r.major_label, r.sub_major_label, r.minor_label, r.unit_label)
66
+ save_record(i,maj,sub,mn,un)
 
 
67
  md = f"## Occupation: {r.occupation_title_main}\n## Industry: {r.industry_title_main}"
68
  return (
69
  md,
 
75
  )
76
 
77
  def on_major_change(new_maj,i):
78
+ sub_c = submajors(new_maj); sub = sub_c[0] if sub_c else ""
79
+ mn_c = minors(new_maj,sub); mn = mn_c[0] if mn_c else ""
80
  un_c = units(new_maj,sub,mn); un = un_c[0] if un_c else ""
81
  save_record(i,new_maj,sub,mn,un)
82
  return (
83
+ gr.update(choices=majors(), value=new_maj),
84
+ gr.update(choices=sub_c, value=sub),
85
+ gr.update(choices=mn_c, value=mn),
86
+ gr.update(choices=un_c, value=un),
87
  status_text(i),
88
  )
89
 
 
94
  records.loc[i,"annotated"]=True
95
  return (
96
  gr.update(choices=submajors(maj),value=new_sub),
97
+ gr.update(choices=mn_c, value=mn),
98
+ gr.update(choices=un_c, value=un),
99
  status_text(i),
100
  )
101
 
 
105
  records.loc[i,"annotated"]=True
106
  return (
107
  gr.update(choices=minors(maj,sub),value=new_mn),
108
+ gr.update(choices=un_c, value=un),
109
  status_text(i),
110
  )
111
 
112
  def on_unit_change(new_un,i,maj,sub,mn):
113
  un_c=units(maj,sub,mn)
114
+ new_un = new_un if new_un in un_c else (un_c[0] if un_c else "")
115
  records.loc[i,"unit_label"]=new_un
116
  records.loc[i,"annotated"]=True
117
  return gr.update(choices=un_c,value=new_un), status_text(i)
 
119
  def go_next(i): return (i+1)%len(records)
120
  def go_prev(i): return (i-1)%len(records)
121
 
122
+ def save_and_jump(i,direction):
 
123
  r=records.loc[i]
124
+ maj,sub,mn,un,*_ = clamp_path(r.major_label,r.sub_major_label,r.minor_label,r.unit_label)
125
  save_record(i,maj,sub,mn,un)
126
+ j = go_next(i) if direction=="next" else go_prev(i)
127
  return (j,)+load_record(j)
128
 
129
  def download_csv():
130
+ out = PROCESSED_DATA_DIR/"annotated_output.csv"
131
+ records.to_csv(out,index=False)
132
+ return str(out)
133
 
134
+ # --- build with login gate ---
135
  def build_gradio_app():
136
  USER = os.getenv("APP_USER","")
137
  PWD = os.getenv("APP_PASS","")
138
 
139
  with gr.Blocks() as demo:
140
+ gr.HTML("""
141
+ <style>
142
+ footer, .share-link, .api-link {display:none!important}
143
+ #title{text-align:center;margin:0.5em}
144
  </style>""")
145
 
146
+ # === capture the two panels ===
147
+ with gr.Column(elem_id="login_panel") as login_panel:
148
+ gr.HTML(f'<img src="data:image/png;base64,{logo_b64}" width="160" '
149
+ 'style="pointer-events:none;user-select:none;display:block;margin:auto;"/>')
150
+ user_in = gr.Textbox(label="Username")
151
+ pass_in = gr.Textbox(label="Password", type="password")
152
+ login_btn = gr.Button("🔒 Log in")
153
+ login_msg = gr.Markdown("", visible=False)
154
+
155
+ with gr.Column(elem_id="app_panel", visible=False) as app_panel:
156
+ gr.HTML(f'<img src="data:image/png;base64,{logo_b64}" width="160" '
157
+ 'style="pointer-events:none;user-select:none;display:block;margin:auto;"/>')
 
158
  gr.Markdown("# ISCO Annotation", elem_id="title")
159
  idx_state = gr.State(0)
160
  record_md = gr.Markdown()
161
  status_md = gr.Markdown()
162
+ prev_btn = gr.Button("⬅ Previous")
163
+ next_btn = gr.Button(" Next")
164
+ major_radio = gr.Radio("Level 1 Major", choices=[], interactive=True)
165
+ sub_radio = gr.Radio("Level 2 Sub-major",choices=[], interactive=True)
166
+ minor_radio = gr.Radio("Level 3 Minor", choices=[], interactive=True)
167
+ unit_radio = gr.Radio("Level 4 Unit", choices=[], interactive=True)
 
 
168
  download_btn = gr.Button("📥 Download CSV")
169
  download_file = gr.File(visible=False)
170
 
171
+ # --- login handler ---
172
  def check_creds(u,p):
173
  if u==USER and p==PWD:
174
+ return (
175
+ gr.update(visible=False), # hide login
176
+ gr.update(visible=True), # show app
177
+ gr.update(visible=False), # hide error
178
+ "" # clear user_in
179
+ )
180
  else:
181
+ return (None, None,
182
+ gr.update(visible=True,value="❌ Bad credentials"),
183
+ "")
184
 
185
  login_btn.click(
186
  check_creds,
187
  inputs=[user_in,pass_in],
188
+ outputs=[login_panel,app_panel,login_msg,user_in]
189
  )
190
 
191
+ # --- main app wiring ---
192
  demo.load(lambda: (0,)+load_record(0),
193
  outputs=[idx_state,record_md,status_md,
194
  major_radio,sub_radio,minor_radio,unit_radio])
 
223
 
224
  if __name__=="__main__":
225
  demo = build_gradio_app()
226
+ demo.queue().launch(show_api=False, share=True,
227
+ # require Gradio‐level HTTP auth
228
+ auth=(os.getenv("APP_USER",""), os.getenv("APP_PASS","")))