gvlktejaswi commited on
Commit
6c11134
·
verified ·
1 Parent(s): bcfc87f

Delete page_files/categorized/Backend/plot_mapping_ui.py

Browse files
page_files/categorized/Backend/plot_mapping_ui.py DELETED
@@ -1,397 +0,0 @@
1
- """
2
- plot_mapping_ui.py
3
- ------------------
4
- Drop-in replacement for the "Extracted Plots" tab (tab2) in Upload_Data.py.
5
-
6
- HOW TO INTEGRATE
7
- ────────────────
8
- 1. Copy plot_property_mapper.py next to upload_backend.py.
9
- 2. In Upload_Data.py, add at the top:
10
-
11
- from plot_mapping_ui import render_plot_mapping_tab
12
-
13
- 3. Replace the entire `with tab2:` block with:
14
-
15
- with tab2:
16
- render_plot_mapping_tab(pdf_path, paper_id)
17
-
18
- That's it. The function reads everything it needs from st.session_state
19
- (which your existing tab1 code already populates).
20
- """
21
-
22
- import json
23
- import os
24
-
25
- import cv2
26
- import numpy as np
27
- import streamlit as st
28
-
29
- from plot_property_mapper import (
30
- batch_map_plots,
31
- fetch_properties_for_material,
32
- save_plot_image_mapping,
33
- )
34
-
35
- # ── tiny helper ───────────────────────────────────────────────────────────────
36
-
37
- def _confidence_badge(conf: str) -> str:
38
- colors = {"high": "#16a34a", "medium": "#d97706", "low": "#dc2626"}
39
- c = colors.get(conf.lower(), "#6b7280")
40
- return (
41
- f"<span style='background:{c};color:#fff;padding:2px 10px;"
42
- f"border-radius:99px;font-size:0.78rem;font-weight:700'>{conf.upper()}</span>"
43
- )
44
-
45
-
46
- # ── main render function ───────────────────────────────────────────────────────
47
-
48
- def render_plot_mapping_tab(pdf_path: str, paper_id: str):
49
- """Render the full Extracted Plots + Property Mapping tab."""
50
-
51
- st.subheader("Extracted Plot Images & Property Mapping")
52
-
53
- # ── session-state keys ────────────────────────────────────────────────────
54
- for key, default in [
55
- ("pdf_processed", False),
56
- ("image_results", []),
57
- ("mapped_results", []),
58
- ("mapping_done", False),
59
- ("saved_image_mapping", {}),
60
- ("pdf_extracted_df", __import__("pandas").DataFrame()),
61
- ("pdf_extracted_meta", {}),
62
- ]:
63
- if key not in st.session_state:
64
- st.session_state[key] = default
65
-
66
- # ── 1. Extract plots if not done yet ─────────────────────────────────────
67
- if not st.session_state.pdf_processed:
68
- with st.spinner("Extracting plots from PDF…"):
69
- import fitz
70
- from upload_backend import extract_images
71
-
72
- doc = fitz.open(pdf_path)
73
- st.session_state.image_results = extract_images(doc)
74
- doc.close()
75
- st.session_state.pdf_processed = True
76
- st.session_state.mapping_done = False # reset mapping on new PDF
77
-
78
- image_results = st.session_state.image_results
79
-
80
- if not image_results:
81
- st.warning("No plots found in this PDF.")
82
- return
83
-
84
- # ── 2. Info bar ───────────────────────────────────────────────────────────
85
- has_data = not st.session_state.pdf_extracted_df.empty
86
- material_class = st.session_state.get("selected_material_class") # set below
87
-
88
- if has_data:
89
- df = st.session_state.pdf_extracted_df
90
- mat_abbr = df.iloc[0]["material_abbreviation"]
91
- st.info(
92
- f"**{len(image_results)} plots** extracted | "
93
- f"Material: **{mat_abbr}** | "
94
- f"{len(df['property_name'].unique())} DB properties available"
95
- )
96
- else:
97
- st.warning(
98
- "Extract material data in the **Material Data** tab first "
99
- "to enable AI property mapping."
100
- )
101
-
102
- st.divider()
103
-
104
- # ── 3. Download buttons (always visible) ──────────────────────────────────
105
- from upload_backend import create_zip
106
-
107
- col_img, col_json, col_all = st.columns(3)
108
- with col_img:
109
- img_zip = create_zip(image_results, include_json=False)
110
- st.download_button(
111
- "⬇ Download Images",
112
- data=img_zip,
113
- file_name=f"{paper_id}_images.zip",
114
- mime="application/zip",
115
- use_container_width=True,
116
- key="dl_images",
117
- )
118
- with col_json:
119
- json_data = [
120
- {"caption": r["caption"], "page": r["page"],
121
- "image_count": len(r["image_data"])}
122
- for r in image_results
123
- ]
124
- st.download_button(
125
- "⬇ Download JSON",
126
- data=json.dumps(json_data, indent=4),
127
- file_name=f"{paper_id}_metadata.json",
128
- mime="application/json",
129
- use_container_width=True,
130
- key="dl_json",
131
- )
132
- with col_all:
133
- full_zip = create_zip(image_results, include_json=True)
134
- st.download_button(
135
- "⬇ Download All",
136
- data=full_zip,
137
- file_name=f"{paper_id}_complete.zip",
138
- mime="application/zip",
139
- use_container_width=True,
140
- key="dl_all",
141
- )
142
-
143
- st.divider()
144
-
145
- # ── 4. AI mapping panel (only when data is extracted) ────────────────────
146
- if has_data:
147
- from db import fetch_all # your existing db module
148
-
149
- df = st.session_state.pdf_extracted_df
150
- mat_abbr = df.iloc[0]["material_abbreviation"]
151
- extracted_json = st.session_state.get("pdf_extracted_meta", {})
152
-
153
- # Material class selector (needed to route to the right table)
154
- material_class = st.selectbox(
155
- "Material class (for DB lookup)",
156
- ["Polymer", "Fiber", "Composite"],
157
- index=0,
158
- key="selected_material_class",
159
- help="Determines which PostgreSQL table to fetch properties from.",
160
- )
161
-
162
- run_mapping = st.button(
163
- "🤖 Run AI Property Mapping",
164
- type="primary",
165
- disabled=st.session_state.mapping_done,
166
- help="Sends each plot + caption + extracted JSON to Gemini for matching.",
167
- )
168
-
169
- if run_mapping:
170
- # Fetch DB properties
171
- with st.spinner("Fetching properties from PostgreSQL…"):
172
- try:
173
- db_properties = fetch_properties_for_material(
174
- mat_abbr, material_class, fetch_all
175
- )
176
- except Exception as exc:
177
- st.error(f"DB error: {exc}")
178
- db_properties = []
179
-
180
- if not db_properties:
181
- st.warning(
182
- f"No properties found for **{mat_abbr}** in the "
183
- f"**{material_class}** table. Mapping will use all properties."
184
- )
185
-
186
- # Run batch mapping with progress bar
187
- progress_bar = st.progress(0, text="Mapping plots…")
188
-
189
- def _update(i, total, caption):
190
- pct = int((i / max(total, 1)) * 100)
191
- progress_bar.progress(
192
- pct,
193
- text=f"Mapping {i+1}/{total}: {caption[:60]}…",
194
- )
195
-
196
- with st.spinner("AI is analysing plots…"):
197
- mapped = batch_map_plots(
198
- image_results=image_results,
199
- extracted_json=extracted_json,
200
- db_properties=db_properties,
201
- progress_callback=_update,
202
- )
203
-
204
- progress_bar.progress(100, text="Done!")
205
- st.session_state.mapped_results = mapped
206
- st.session_state.mapping_done = True
207
- st.success(f"✅ Mapped {len(mapped)} plots")
208
- st.rerun()
209
-
210
- if st.session_state.mapping_done and st.session_state.mapped_results:
211
- st.caption("Mapping complete. Review & confirm each match below.")
212
-
213
- st.divider()
214
-
215
- # ── 5. Plot cards ─────────────────────────────────────────────────────────
216
- use_mapped = (
217
- has_data
218
- and st.session_state.mapping_done
219
- and bool(st.session_state.mapped_results)
220
- )
221
-
222
- display_list = (
223
- st.session_state.mapped_results if use_mapped else image_results
224
- )
225
-
226
- for idx, item in enumerate(display_list):
227
- caption = item.get("caption", f"Figure {idx+1}")
228
- page = item.get("page", "?")
229
- img_list = item.get("image_data", [])
230
- mapping = item.get("mapping_result") if use_mapped else None
231
-
232
- with st.container(border=True):
233
-
234
- # — header row —
235
- col_cap, col_del = st.columns([0.88, 0.12])
236
- col_cap.markdown(f"**Page {page}** — {caption}")
237
- if col_del.button("🗑 Delete", key=f"del_group_{idx}"):
238
- if use_mapped:
239
- st.session_state.mapped_results.pop(idx)
240
- else:
241
- st.session_state.image_results.pop(idx)
242
- st.rerun()
243
-
244
- # — AI mapping result banner —
245
- if mapping:
246
- prop_name = mapping.get("property_name", "")
247
- section = mapping.get("section", "")
248
- confidence = mapping.get("confidence", "low")
249
- reasoning = mapping.get("reasoning", "")
250
- db_row = mapping.get("db_row")
251
- candidates = mapping.get("all_candidates", [])
252
-
253
- badge = _confidence_badge(confidence)
254
- if prop_name:
255
- st.markdown(
256
- f"🔗 **AI Match:** `{section}` › **{prop_name}** &nbsp; {badge}",
257
- unsafe_allow_html=True,
258
- )
259
- if reasoning:
260
- st.caption(f"💬 {reasoning}")
261
-
262
- # DB row details
263
- if db_row:
264
- with st.expander("📋 Matched DB row", expanded=False):
265
- col_v, col_u, col_c = st.columns(3)
266
- col_v.metric("Value", db_row.get("value", "—"))
267
- col_u.metric("Unit", db_row.get("unit", "—"))
268
- col_c.metric("Condition", db_row.get("test_condition", "—"))
269
- if db_row.get("comments"):
270
- st.caption(f"Comments: {db_row['comments']}")
271
- if db_row.get("english"):
272
- st.caption(f"English units: {db_row['english']}")
273
-
274
- # Alternative candidates
275
- if candidates:
276
- with st.expander("🔄 All candidates", expanded=False):
277
- for c in candidates:
278
- rank = c.get("rank", "?")
279
- cn = c.get("confidence", "low")
280
- st.markdown(
281
- f"{rank}. `{c.get('section','?')}` › "
282
- f"**{c.get('property_name','?')}** "
283
- f"&nbsp; {_confidence_badge(cn)}",
284
- unsafe_allow_html=True,
285
- )
286
- else:
287
- st.warning("⚠️ AI could not match this plot to any DB property.")
288
-
289
- # — sub-images —
290
- for p_idx, img_data in enumerate(img_list):
291
- bgr = img_data.get("array")
292
- if bgr is None:
293
- continue
294
-
295
- img_key = f"{idx}_{p_idx}_{page}"
296
-
297
- # Show the plot
298
- st.image(bgr, channels="BGR", width=420)
299
-
300
- # — mapping controls —
301
- if has_data:
302
- df = st.session_state.pdf_extracted_df
303
- mat_abbr = df.iloc[0]["material_abbreviation"]
304
- property_list = df["property_name"].unique().tolist()
305
-
306
- # Pre-select the AI suggestion if available
307
- ai_suggestion = mapping.get("property_name", "") if mapping else ""
308
- default_idx = 0
309
- options = ["— Select property —"] + property_list
310
- if ai_suggestion in property_list:
311
- default_idx = property_list.index(ai_suggestion) + 1
312
-
313
- col_sel, col_sec, col_save, col_rem = st.columns(
314
- [0.42, 0.18, 0.20, 0.20]
315
- )
316
-
317
- with col_sel:
318
- selected = st.selectbox(
319
- "Property",
320
- options=options,
321
- index=default_idx,
322
- key=f"prop_sel_{img_key}",
323
- label_visibility="collapsed",
324
- )
325
-
326
- with col_sec:
327
- section_override = st.text_input(
328
- "Section",
329
- value=mapping.get("section", "") if mapping else "",
330
- key=f"sec_{img_key}",
331
- label_visibility="collapsed",
332
- placeholder="Section",
333
- )
334
-
335
- with col_save:
336
- if st.button("💾 Save", key=f"save_{img_key}"):
337
- if selected and selected != "— Select property —":
338
- filepath = save_plot_image_mapping(
339
- mat_abbr,
340
- selected,
341
- section_override,
342
- bgr,
343
- save_dir="images",
344
- )
345
- st.session_state.saved_image_mapping[img_key] = {
346
- "property": selected,
347
- "section": section_override,
348
- "caption": caption,
349
- "filename": os.path.basename(filepath),
350
- "path": filepath,
351
- }
352
- st.success(f"Saved → `{os.path.basename(filepath)}`")
353
- st.rerun()
354
- else:
355
- st.warning("Select a property first.")
356
-
357
- with col_rem:
358
- if st.button("✕ Remove", key=f"rem_{img_key}"):
359
- img_list.pop(p_idx)
360
- if not img_list:
361
- if use_mapped:
362
- st.session_state.mapped_results.pop(idx)
363
- else:
364
- st.session_state.image_results.pop(idx)
365
- st.rerun()
366
-
367
- # Saved badge
368
- if img_key in st.session_state.saved_image_mapping:
369
- m = st.session_state.saved_image_mapping[img_key]
370
- st.info(f"✅ Saved as **{m['property']}** → `{m['filename']}`")
371
-
372
- else:
373
- # No data extracted yet — just allow removal
374
- col_msg, col_rem = st.columns([0.80, 0.20])
375
- col_msg.caption(
376
- "Extract material data in the **Material Data** tab to enable mapping."
377
- )
378
- if col_rem.button("✕ Remove", key=f"rem_nodata_{img_key}"):
379
- img_list.pop(p_idx)
380
- if not img_list:
381
- st.session_state.image_results.pop(idx)
382
- st.rerun()
383
-
384
- st.divider()
385
-
386
- # ── 6. Saved-mappings summary ─────────────────────────────────────────────
387
- if st.session_state.saved_image_mapping:
388
- with st.expander(
389
- f"📁 Saved mappings ({len(st.session_state.saved_image_mapping)})",
390
- expanded=False,
391
- ):
392
- for key, info in st.session_state.saved_image_mapping.items():
393
- st.markdown(
394
- f"**{info['property']}** &nbsp;›&nbsp; `{info['filename']}` \n"
395
- f"<small>Caption: {info['caption']}</small>",
396
- unsafe_allow_html=True,
397
- )