Eric Chamoun commited on
Commit ·
eeb69fa
1
Parent(s): 0a55f0f
Clarify downstream-impact view in demo
Browse files- hf_space/streamlit_app.py +23 -16
- hf_space/streamlit_config.py +1 -1
hf_space/streamlit_app.py
CHANGED
|
@@ -55,10 +55,10 @@ CUSTOM_CSS = """
|
|
| 55 |
.field {font-size: 0.88rem; line-height: 1.5; color: #374151; margin-top: 0.4rem;}
|
| 56 |
.field b {color: #111827;}
|
| 57 |
.grounding-block {margin-top: 0.75rem; display: grid; gap: 0.55rem;}
|
| 58 |
-
.grounding-card {border-radius: 10px; padding: 0.65rem 0.75rem; border: 1px solid #
|
| 59 |
.grounding-card.additional {border-color: #fed7aa; background: #fff7ed;}
|
| 60 |
.grounding-label {font-size: 0.7rem; font-weight: 900; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.25rem;}
|
| 61 |
-
.grounding-label.primary {color: #
|
| 62 |
.grounding-label.additional {color: #c2410c;}
|
| 63 |
.grounding-title {font-size: 0.9rem; font-weight: 800; color: #111827; line-height: 1.35;}
|
| 64 |
.grounding-meta {font-size: 0.78rem; color: #64748b; margin-top: 0.2rem;}
|
|
@@ -253,10 +253,9 @@ def _grounding_html(grounding: Optional[dict], label: str, kind: str) -> str:
|
|
| 253 |
if isinstance(authors, list) and authors:
|
| 254 |
meta.append(", ".join(str(author) for author in authors[:3]))
|
| 255 |
meta_html = f"<div class='grounding-meta'>{_esc(' · '.join(meta))}</div>" if meta else ""
|
| 256 |
-
extra_class = " additional" if kind == "additional" else ""
|
| 257 |
return (
|
| 258 |
-
|
| 259 |
-
f"<div class='grounding-label
|
| 260 |
f"<div class='grounding-title'>{_esc(title)}</div>"
|
| 261 |
f"{meta_html}"
|
| 262 |
"</div>"
|
|
@@ -278,8 +277,8 @@ def _collect_grounded_studies(discoveries: list[dict], ingredients: list[dict])
|
|
| 278 |
if not isinstance(item, dict):
|
| 279 |
continue
|
| 280 |
copied = dict(item)
|
| 281 |
-
copied["_grounding_kind"] = "
|
| 282 |
-
copied["_grounding_label"] = "
|
| 283 |
key = _study_key(copied)
|
| 284 |
if key:
|
| 285 |
seen.add(key)
|
|
@@ -298,8 +297,8 @@ def _collect_grounded_studies(discoveries: list[dict], ingredients: list[dict])
|
|
| 298 |
if key and (key == canonical_key or key in seen):
|
| 299 |
continue
|
| 300 |
copied = dict(ref)
|
| 301 |
-
copied["_grounding_kind"] = "
|
| 302 |
-
copied["_grounding_label"] = f"
|
| 303 |
copied.setdefault("role", annotation.get("role") or ", ".join(annotation.get("roles") or []))
|
| 304 |
copied.setdefault("contribution", annotation.get("contribution"))
|
| 305 |
copied.setdefault("rationale", annotation.get("rationale"))
|
|
@@ -316,7 +315,6 @@ def _render_reference_list(discoveries: list[dict], ingredients: Optional[list[d
|
|
| 316 |
return
|
| 317 |
for item in studies:
|
| 318 |
title = item.get("ref_title") or item.get("title") or item.get("ref_id") or item.get("paper_id") or "Untitled reference"
|
| 319 |
-
is_additional = item.get("_grounding_kind") == "additional"
|
| 320 |
meta = []
|
| 321 |
if item.get("_grounding_label"):
|
| 322 |
meta.append(str(item.get("_grounding_label")))
|
|
@@ -324,7 +322,7 @@ def _render_reference_list(discoveries: list[dict], ingredients: Optional[list[d
|
|
| 324 |
meta.append(str(item.get("role")))
|
| 325 |
if item.get("ref_year"):
|
| 326 |
meta.append(str(item.get("ref_year")))
|
| 327 |
-
class_name = "cluster-card additional-study"
|
| 328 |
body = [f"<div class='{class_name}'><div class='cluster-title'>{_esc(title)}</div>"]
|
| 329 |
if meta:
|
| 330 |
body.append(f"<div class='cluster-meta'>{_esc(' · '.join(meta))}</div>")
|
|
@@ -345,6 +343,11 @@ def _render_claims_tab(payload: Optional[dict]):
|
|
| 345 |
st.markdown("<div class='empty-card'>The run completed, but no target contributions were produced.</div>", unsafe_allow_html=True)
|
| 346 |
return
|
| 347 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
for idx, claim in enumerate(claims, start=1):
|
| 349 |
claim_id = claim.get("claim_id") or f"C{idx}"
|
| 350 |
claim_text = claim.get("rewritten_claim") or claim.get("text") or "(missing target contribution text)"
|
|
@@ -385,7 +388,7 @@ def _render_claims_tab(payload: Optional[dict]):
|
|
| 385 |
grounding_parts = []
|
| 386 |
if canonical_grounding:
|
| 387 |
grounding_parts.append(
|
| 388 |
-
_grounding_html(canonical_grounding, "
|
| 389 |
)
|
| 390 |
for ref in extras:
|
| 391 |
if not isinstance(ref, dict):
|
|
@@ -396,13 +399,13 @@ def _render_claims_tab(payload: Optional[dict]):
|
|
| 396 |
):
|
| 397 |
continue
|
| 398 |
grounding_parts.append(
|
| 399 |
-
_grounding_html(ref, "
|
| 400 |
)
|
| 401 |
if not grounding_parts:
|
| 402 |
canonical_ref_id = ingredient.get("canonical_ref_id") or "__NONE__"
|
| 403 |
grounding_parts.append(
|
| 404 |
"<div class='grounding-card'>"
|
| 405 |
-
"<div class='grounding-label
|
| 406 |
f"<div class='grounding-title'>{_esc(canonical_ref_id)}</div>"
|
| 407 |
"</div>"
|
| 408 |
)
|
|
@@ -428,7 +431,7 @@ def _render_claims_tab(payload: Optional[dict]):
|
|
| 428 |
unsafe_allow_html=True,
|
| 429 |
)
|
| 430 |
with right:
|
| 431 |
-
st.markdown("<div class='section-label'>
|
| 432 |
_render_reference_list(discoveries, ingredients)
|
| 433 |
|
| 434 |
|
|
@@ -436,6 +439,10 @@ def _render_clusters_tab(discovery: Optional[dict], contributions: list[dict]):
|
|
| 436 |
if not discovery:
|
| 437 |
st.markdown("<div class='empty-card'>No refined cluster file is available yet.</div>", unsafe_allow_html=True)
|
| 438 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
clusters = discovery.get("clusters") or []
|
| 440 |
dropped = discovery.get("dropped_clusters") or []
|
| 441 |
if not clusters:
|
|
@@ -796,7 +803,7 @@ def main():
|
|
| 796 |
|
| 797 |
st.markdown("<div class='hero-title'>Forecasting Scientific Contribution Pathways</div>", unsafe_allow_html=True)
|
| 798 |
st.markdown(
|
| 799 |
-
"<div class='hero-sub'>
|
| 800 |
unsafe_allow_html=True,
|
| 801 |
)
|
| 802 |
|
|
|
|
| 55 |
.field {font-size: 0.88rem; line-height: 1.5; color: #374151; margin-top: 0.4rem;}
|
| 56 |
.field b {color: #111827;}
|
| 57 |
.grounding-block {margin-top: 0.75rem; display: grid; gap: 0.55rem;}
|
| 58 |
+
.grounding-card {border-radius: 10px; padding: 0.65rem 0.75rem; border: 1px solid #fed7aa; background: #fff7ed;}
|
| 59 |
.grounding-card.additional {border-color: #fed7aa; background: #fff7ed;}
|
| 60 |
.grounding-label {font-size: 0.7rem; font-weight: 900; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.25rem;}
|
| 61 |
+
.grounding-label.primary {color: #c2410c;}
|
| 62 |
.grounding-label.additional {color: #c2410c;}
|
| 63 |
.grounding-title {font-size: 0.9rem; font-weight: 800; color: #111827; line-height: 1.35;}
|
| 64 |
.grounding-meta {font-size: 0.78rem; color: #64748b; margin-top: 0.2rem;}
|
|
|
|
| 253 |
if isinstance(authors, list) and authors:
|
| 254 |
meta.append(", ".join(str(author) for author in authors[:3]))
|
| 255 |
meta_html = f"<div class='grounding-meta'>{_esc(' · '.join(meta))}</div>" if meta else ""
|
|
|
|
| 256 |
return (
|
| 257 |
+
"<div class='grounding-card'>"
|
| 258 |
+
f"<div class='grounding-label additional'>{_esc(label)}</div>"
|
| 259 |
f"<div class='grounding-title'>{_esc(title)}</div>"
|
| 260 |
f"{meta_html}"
|
| 261 |
"</div>"
|
|
|
|
| 277 |
if not isinstance(item, dict):
|
| 278 |
continue
|
| 279 |
copied = dict(item)
|
| 280 |
+
copied["_grounding_kind"] = "grounding"
|
| 281 |
+
copied["_grounding_label"] = "Grounding"
|
| 282 |
key = _study_key(copied)
|
| 283 |
if key:
|
| 284 |
seen.add(key)
|
|
|
|
| 297 |
if key and (key == canonical_key or key in seen):
|
| 298 |
continue
|
| 299 |
copied = dict(ref)
|
| 300 |
+
copied["_grounding_kind"] = "grounding"
|
| 301 |
+
copied["_grounding_label"] = f"Grounding for enabling contribution {idx}"
|
| 302 |
copied.setdefault("role", annotation.get("role") or ", ".join(annotation.get("roles") or []))
|
| 303 |
copied.setdefault("contribution", annotation.get("contribution"))
|
| 304 |
copied.setdefault("rationale", annotation.get("rationale"))
|
|
|
|
| 315 |
return
|
| 316 |
for item in studies:
|
| 317 |
title = item.get("ref_title") or item.get("title") or item.get("ref_id") or item.get("paper_id") or "Untitled reference"
|
|
|
|
| 318 |
meta = []
|
| 319 |
if item.get("_grounding_label"):
|
| 320 |
meta.append(str(item.get("_grounding_label")))
|
|
|
|
| 322 |
meta.append(str(item.get("role")))
|
| 323 |
if item.get("ref_year"):
|
| 324 |
meta.append(str(item.get("ref_year")))
|
| 325 |
+
class_name = "cluster-card additional-study"
|
| 326 |
body = [f"<div class='{class_name}'><div class='cluster-title'>{_esc(title)}</div>"]
|
| 327 |
if meta:
|
| 328 |
body.append(f"<div class='cluster-meta'>{_esc(' · '.join(meta))}</div>")
|
|
|
|
| 343 |
st.markdown("<div class='empty-card'>The run completed, but no target contributions were produced.</div>", unsafe_allow_html=True)
|
| 344 |
return
|
| 345 |
|
| 346 |
+
st.markdown(
|
| 347 |
+
"<div class='soft-card'>This decomposition is done in hindsight: SciPaths uses the observed downstream citation clusters to identify reusable target contributions, then reconstructs the enabling contributions and groundings that made each target contribution possible.</div>",
|
| 348 |
+
unsafe_allow_html=True,
|
| 349 |
+
)
|
| 350 |
+
|
| 351 |
for idx, claim in enumerate(claims, start=1):
|
| 352 |
claim_id = claim.get("claim_id") or f"C{idx}"
|
| 353 |
claim_text = claim.get("rewritten_claim") or claim.get("text") or "(missing target contribution text)"
|
|
|
|
| 388 |
grounding_parts = []
|
| 389 |
if canonical_grounding:
|
| 390 |
grounding_parts.append(
|
| 391 |
+
_grounding_html(canonical_grounding, "Grounding", "grounding")
|
| 392 |
)
|
| 393 |
for ref in extras:
|
| 394 |
if not isinstance(ref, dict):
|
|
|
|
| 399 |
):
|
| 400 |
continue
|
| 401 |
grounding_parts.append(
|
| 402 |
+
_grounding_html(ref, "Grounding", "grounding")
|
| 403 |
)
|
| 404 |
if not grounding_parts:
|
| 405 |
canonical_ref_id = ingredient.get("canonical_ref_id") or "__NONE__"
|
| 406 |
grounding_parts.append(
|
| 407 |
"<div class='grounding-card'>"
|
| 408 |
+
"<div class='grounding-label additional'>Grounding</div>"
|
| 409 |
f"<div class='grounding-title'>{_esc(canonical_ref_id)}</div>"
|
| 410 |
"</div>"
|
| 411 |
)
|
|
|
|
| 431 |
unsafe_allow_html=True,
|
| 432 |
)
|
| 433 |
with right:
|
| 434 |
+
st.markdown("<div class='section-label'>Groundings</div>", unsafe_allow_html=True)
|
| 435 |
_render_reference_list(discoveries, ingredients)
|
| 436 |
|
| 437 |
|
|
|
|
| 439 |
if not discovery:
|
| 440 |
st.markdown("<div class='empty-card'>No refined cluster file is available yet.</div>", unsafe_allow_html=True)
|
| 441 |
return
|
| 442 |
+
st.markdown(
|
| 443 |
+
"<div class='soft-card'>Citation clusters are forward-looking: they summarize how later papers use or extend the input paper, giving a downstream-impact view of what became reusable.</div>",
|
| 444 |
+
unsafe_allow_html=True,
|
| 445 |
+
)
|
| 446 |
clusters = discovery.get("clusters") or []
|
| 447 |
dropped = discovery.get("dropped_clusters") or []
|
| 448 |
if not clusters:
|
|
|
|
| 803 |
|
| 804 |
st.markdown("<div class='hero-title'>Forecasting Scientific Contribution Pathways</div>", unsafe_allow_html=True)
|
| 805 |
st.markdown(
|
| 806 |
+
"<div class='hero-sub'>SciPaths first looks forward, grouping downstream papers by how they use or extend the input paper. It then performs the target contribution decomposition in hindsight: given those observed downstream-impact clusters, it identifies reusable target contributions and decomposes them into enabling contributions and groundings.</div>",
|
| 807 |
unsafe_allow_html=True,
|
| 808 |
)
|
| 809 |
|
hf_space/streamlit_config.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
from runner import STEP_LABELS
|
| 2 |
|
| 3 |
EXAMPLES = {
|
| 4 |
-
"
|
| 5 |
"AVerImaTeC": "https://arxiv.org/abs/2505.17978",
|
| 6 |
"CSCD-NS (2022)": "https://arxiv.org/abs/2211.08788",
|
| 7 |
}
|
|
|
|
| 1 |
from runner import STEP_LABELS
|
| 2 |
|
| 3 |
EXAMPLES = {
|
| 4 |
+
"PASTA: Participant States in Narratives": "https://arxiv.org/abs/2208.00329",
|
| 5 |
"AVerImaTeC": "https://arxiv.org/abs/2505.17978",
|
| 6 |
"CSCD-NS (2022)": "https://arxiv.org/abs/2211.08788",
|
| 7 |
}
|