gurma-dashboard / tr_tab.py
Emre Sarigöl
Deploy GURMA.ai Dashboard - 2026-02-18 14:33
7406cf4
"""
GURMA.ai — TR Branch Tab
Displays executive summaries and raw agent research data
for the Turkey subsidiary setup.
"""
import json
import os
from datetime import datetime
from pathlib import Path
import streamlit as st
# ============================================================
# Environment & Paths
# ============================================================
IS_HF_SPACE = os.getenv("HF_SPACE") or Path("/app/research.py").exists()
if IS_HF_SPACE:
DATA_ROOT = Path("/app/data")
DOCS_ROOT = Path("/app/docs")
else:
DATA_ROOT = Path(__file__).resolve().parent.parent.parent / "data"
DOCS_ROOT = Path(__file__).resolve().parent.parent.parent / "docs"
TR_DIRS = {
"tr-mali": {"label": "Mali Müşavir", "description": "Company formation, tax, IP, regulatory"},
"tr-fonlar": {"label": "Fon Araştırma", "description": "TÜBİTAK, KOSGEB, EU/bilateral funding"},
}
# ============================================================
# Data Loading
# ============================================================
@st.cache_data(ttl=120)
def _load_exec_summaries() -> list[dict]:
"""Load executive summary markdown files, newest first."""
if not DOCS_ROOT.exists():
return []
summaries = []
for f in sorted(DOCS_ROOT.glob("exec-summary-*.md"), reverse=True):
try:
content = f.read_text(encoding="utf-8")
title_line = ""
for line in content.split("\n"):
if line.startswith("# "):
title_line = line[2:].strip()
break
summaries.append({
"filename": f.name,
"title": title_line or f.stem,
"content": content,
"mtime": datetime.fromtimestamp(f.stat().st_mtime),
})
except Exception:
continue
return summaries
@st.cache_data(ttl=120)
def _load_tr_agent_stats() -> dict:
"""Load lightweight stats from TR agent JSON files (not full content)."""
stats = {}
for agent_key, cfg in TR_DIRS.items():
agent_dir = DATA_ROOT / agent_key
if not agent_dir.exists():
stats[agent_key] = None
continue
json_files = sorted(agent_dir.glob("*.json"), reverse=True)
if not json_files:
stats[agent_key] = None
continue
try:
with open(json_files[0]) as fh:
data = json.load(fh)
sections = data.get("sections", {})
total_findings = sum(len(s.get("findings", [])) for s in sections.values())
confirmed = sum(
sum(1 for f in s.get("findings", []) if isinstance(f, dict) and f.get("confirmed"))
for s in sections.values()
)
total_gaps = sum(len(s.get("gaps", [])) for s in sections.values())
stats[agent_key] = {
"timestamp": data.get("timestamp", "")[:16].replace("T", " "),
"categories": len(sections),
"findings": total_findings,
"confirmed": confirmed,
"gaps": total_gaps,
"sections": sections,
"filename": json_files[0].name,
}
except Exception:
stats[agent_key] = None
return stats
# ============================================================
# Main Entry Point
# ============================================================
def render_tr_tab():
"""Main entry point — called from app.py."""
st.title("TR Branch")
st.caption("Company formation research & funding intelligence for GURMA Turkey")
summaries = _load_exec_summaries()
agent_stats = _load_tr_agent_stats()
# --- Executive Summaries (primary content) ---
if summaries:
for s in summaries:
age = datetime.now() - s["mtime"]
age_label = "today" if age.days == 0 else f"{age.days}d ago"
st.markdown(f"##### {s['title']} &nbsp; <span style='color:#888;font-size:0.7em;'>({age_label})</span>", unsafe_allow_html=True)
st.markdown(s["content"])
st.divider()
else:
st.info("No executive summaries found in `docs/exec-summary-*.md`. Run the synthesis workflow to generate reports.")
# --- Agent Data Sources (collapsed) ---
any_data = any(v is not None for v in agent_stats.values())
if any_data:
with st.expander("Raw Research Data", expanded=False):
st.caption("Source findings collected by the Mali and Fonlar agents. These are raw search results — see executive summaries above for the synthesized analysis.")
for agent_key, cfg in TR_DIRS.items():
info = agent_stats.get(agent_key)
if info is None:
st.caption(f"**{cfg['label']}** — no data")
continue
spec_label = f"speculative" if info['findings'] - info['confirmed'] > 0 else ""
st.markdown(
f"**{cfg['label']}** — {info['findings']} findings "
f"({info['confirmed']} official{', ' + str(info['findings'] - info['confirmed']) + ' ' + spec_label if spec_label else ''}) "
f"· {info['gaps']} gaps · {info['categories']} categories "
f"· <span style='color:#888;font-size:0.8em;'>Run: {info['timestamp']}</span>",
unsafe_allow_html=True,
)
for section_data in info["sections"].values():
label = section_data.get("label", "")
findings = section_data.get("findings", [])
gaps = section_data.get("gaps", [])
if not findings and not gaps:
continue
confirmed_n = sum(1 for f in findings if isinstance(f, dict) and f.get("confirmed"))
header = f"{label} ({len(findings)} findings"
if confirmed_n:
header += f", {confirmed_n} official"
header += ")"
with st.expander(header, expanded=False):
for f in findings[:10]:
if not isinstance(f, dict):
continue
text = f.get("text", "")[:200]
source = f.get("source", "")
is_confirmed = f.get("confirmed", False)
tag = "✅" if is_confirmed else "⚠️"
source_html = ""
if source:
try:
from urllib.parse import urlparse
domain = urlparse(source).netloc.removeprefix("www.")
except Exception:
domain = ""
if domain:
source_html = f" <a href='{source}' style='color:#666;font-size:0.75em;'>{domain}</a>"
st.markdown(f"{tag} <span style='font-size:0.85em;'>{text}</span>{source_html}", unsafe_allow_html=True)
if len(findings) > 10:
st.caption(f"+ {len(findings) - 10} more")
for g in gaps:
gap_text = g.get("text", g) if isinstance(g, dict) else g
st.caption(f"🔍 **Gap:** {gap_text}")
st.markdown("")