| import gradio as gr |
| import pandas as pd |
| import plotly.express as px |
| import plotly.graph_objects as go |
| from datasets import load_dataset |
|
|
| |
| |
| |
|
|
| def load_data(lang="en"): |
| repo = "AYI-NEDJIMI/zero-trust-en" if lang == "en" else "AYI-NEDJIMI/zero-trust-fr" |
| try: |
| ds = load_dataset(repo, split="train") |
| df = ds.to_pandas() |
| except Exception as e: |
| print(f"Error loading {repo}: {e}") |
| df = pd.DataFrame() |
| return df |
|
|
| data_cache = {} |
|
|
| def get_data(lang): |
| if lang not in data_cache: |
| data_cache[lang] = load_data(lang) |
| return data_cache[lang] |
|
|
| def safe_col(df, col): |
| return df[col] if col in df.columns else pd.Series([""] * len(df), name=col) |
|
|
| def filter_type(df, entry_type): |
| if "type" in df.columns: |
| return df[df["type"] == entry_type].reset_index(drop=True) |
| return pd.DataFrame() |
|
|
| ALL_FIELDS = [ |
| "type", "principle_name", "description", "implementation_guide", |
| "maturity_levels", "nist_reference", "benefits", "challenges", |
| "framework_name", "organization", "pillars", "key_documents", |
| "pillar_name", "technologies", "tools", "implementation_steps", |
| "quick_wins", "common_mistakes", "category", "name", "vendor", |
| "features", "pricing_model", "deployment_model", "strengths", |
| "weaknesses", "scenario", "industry", "challenge", |
| "zero_trust_solution", "architecture_components", |
| "implementation_timeline", "roi_metrics", "question", "answer", |
| "difficulty", |
| ] |
|
|
| def ensure_columns(df): |
| for col in ALL_FIELDS: |
| if col not in df.columns: |
| df[col] = "" |
| return df |
|
|
| def fmt(value): |
| """Format a cell value for display.""" |
| if value is None: |
| return "" |
| if isinstance(value, list): |
| return "\n".join(f"• {v}" for v in value) |
| if isinstance(value, dict): |
| return "\n".join(f"**{k}:** {v}" for k, v in value.items()) |
| return str(value) |
|
|
| |
| |
| |
|
|
| LABELS = { |
| "en": { |
| "title": "🔐 Zero Trust Architecture Explorer", |
| "subtitle": "Explore principles, frameworks, pillars, tools, use cases & Q&A", |
| "principles": "Principles", |
| "frameworks": "Frameworks", |
| "pillars": "Implementation Pillars", |
| "tools": "Solutions & Tools", |
| "usecases": "Use Cases", |
| "qa": "Q&A", |
| "stats": "Statistics", |
| "language": "Language", |
| "filter_org": "Filter by Organization", |
| "filter_cat": "Filter by Category", |
| "filter_ind": "Filter by Industry", |
| "all": "All", |
| "select_entry": "Select an entry", |
| "no_data": "No data available for this section.", |
| "total_entries": "Total entries", |
| "by_type": "Entries by Type", |
| "by_category": "Tools by Category", |
| "by_industry": "Use Cases by Industry", |
| "difficulty_dist": "Q&A Difficulty Distribution", |
| }, |
| "fr": { |
| "title": "🔐 Explorateur d'Architecture Zero Trust", |
| "subtitle": "Explorez les principes, cadres, piliers, outils, cas d'usage et Q&R", |
| "principles": "Principes", |
| "frameworks": "Cadres", |
| "pillars": "Piliers d'Implémentation", |
| "tools": "Solutions & Outils", |
| "usecases": "Cas d'Usage", |
| "qa": "Q&R", |
| "stats": "Statistiques", |
| "language": "Langue", |
| "filter_org": "Filtrer par Organisation", |
| "filter_cat": "Filtrer par Catégorie", |
| "filter_ind": "Filtrer par Industrie", |
| "all": "Tous", |
| "select_entry": "Sélectionnez une entrée", |
| "no_data": "Aucune donnée disponible pour cette section.", |
| "total_entries": "Total des entrées", |
| "by_type": "Entrées par Type", |
| "by_category": "Outils par Catégorie", |
| "by_industry": "Cas d'Usage par Industrie", |
| "difficulty_dist": "Distribution de Difficulté Q&R", |
| }, |
| } |
|
|
| |
| |
| |
|
|
| def build_principles(df, lang): |
| L = LABELS[lang] |
| sub = filter_type(df, "principle") |
| if sub.empty: |
| return f"### {L['no_data']}" |
| blocks = [] |
| for _, row in sub.iterrows(): |
| blocks.append( |
| f"## {fmt(row.get('principle_name',''))}\n\n" |
| f"**Description:** {fmt(row.get('description',''))}\n\n" |
| f"**Implementation Guide:** {fmt(row.get('implementation_guide',''))}\n\n" |
| f"**Benefits:** {fmt(row.get('benefits',''))}\n\n" |
| f"**Challenges:** {fmt(row.get('challenges',''))}\n\n---\n" |
| ) |
| return "\n".join(blocks) |
|
|
|
|
| def build_frameworks(df, lang, org_filter="All"): |
| L = LABELS[lang] |
| sub = filter_type(df, "framework") |
| if sub.empty: |
| return f"### {L['no_data']}", [] |
| orgs = sorted(set(str(v) for v in sub["organization"].dropna().unique())) |
| org_choices = [L["all"]] + orgs |
| if org_filter and org_filter != L["all"] and org_filter != "All": |
| sub = sub[sub["organization"] == org_filter] |
| blocks = [] |
| for _, row in sub.iterrows(): |
| blocks.append( |
| f"## {fmt(row.get('framework_name',''))}\n\n" |
| f"**Organization:** {fmt(row.get('organization',''))}\n\n" |
| f"**Description:** {fmt(row.get('description',''))}\n\n" |
| f"**Pillars:** {fmt(row.get('pillars',''))}\n\n" |
| f"**Maturity Levels:** {fmt(row.get('maturity_levels',''))}\n\n---\n" |
| ) |
| return "\n".join(blocks) if blocks else f"### {L['no_data']}", org_choices |
|
|
|
|
| def build_pillars(df, lang): |
| L = LABELS[lang] |
| sub = filter_type(df, "pillar") |
| if sub.empty: |
| return f"### {L['no_data']}" |
| blocks = [] |
| for _, row in sub.iterrows(): |
| blocks.append( |
| f"## {fmt(row.get('pillar_name',''))}\n\n" |
| f"**Description:** {fmt(row.get('description',''))}\n\n" |
| f"**Technologies:** {fmt(row.get('technologies',''))}\n\n" |
| f"**Tools:** {fmt(row.get('tools',''))}\n\n" |
| f"**Implementation Steps:** {fmt(row.get('implementation_steps',''))}\n\n" |
| f"**Quick Wins:** {fmt(row.get('quick_wins',''))}\n\n---\n" |
| ) |
| return "\n".join(blocks) |
|
|
|
|
| def build_tools(df, lang, cat_filter="All"): |
| L = LABELS[lang] |
| sub = filter_type(df, "tool") |
| if sub.empty: |
| return f"### {L['no_data']}", [] |
| cats = sorted(set(str(v) for v in sub["category"].dropna().unique())) |
| cat_choices = [L["all"]] + cats |
| if cat_filter and cat_filter != L["all"] and cat_filter != "All": |
| sub = sub[sub["category"] == cat_filter] |
| blocks = [] |
| for _, row in sub.iterrows(): |
| blocks.append( |
| f"## {fmt(row.get('name',''))}\n\n" |
| f"**Vendor:** {fmt(row.get('vendor',''))}\n\n" |
| f"**Category:** {fmt(row.get('category',''))}\n\n" |
| f"**Features:** {fmt(row.get('features',''))}\n\n" |
| f"**Pricing Model:** {fmt(row.get('pricing_model',''))}\n\n" |
| f"**Strengths:** {fmt(row.get('strengths',''))}\n\n" |
| f"**Weaknesses:** {fmt(row.get('weaknesses',''))}\n\n---\n" |
| ) |
| return "\n".join(blocks) if blocks else f"### {L['no_data']}", cat_choices |
|
|
|
|
| def build_usecases(df, lang, ind_filter="All"): |
| L = LABELS[lang] |
| sub = filter_type(df, "usecase") |
| if sub.empty: |
| return f"### {L['no_data']}", [] |
| inds = sorted(set(str(v) for v in sub["industry"].dropna().unique())) |
| ind_choices = [L["all"]] + inds |
| if ind_filter and ind_filter != L["all"] and ind_filter != "All": |
| sub = sub[sub["industry"] == ind_filter] |
| blocks = [] |
| for _, row in sub.iterrows(): |
| blocks.append( |
| f"## {fmt(row.get('scenario',''))}\n\n" |
| f"**Industry:** {fmt(row.get('industry',''))}\n\n" |
| f"**Challenge:** {fmt(row.get('challenge',''))}\n\n" |
| f"**Zero Trust Solution:** {fmt(row.get('zero_trust_solution',''))}\n\n" |
| f"**Architecture Components:** {fmt(row.get('architecture_components',''))}\n\n" |
| f"**Implementation Timeline:** {fmt(row.get('implementation_timeline',''))}\n\n" |
| f"**ROI Metrics:** {fmt(row.get('roi_metrics',''))}\n\n---\n" |
| ) |
| return "\n".join(blocks) if blocks else f"### {L['no_data']}", ind_choices |
|
|
|
|
| def build_qa(df, lang): |
| L = LABELS[lang] |
| sub = filter_type(df, "qa") |
| if sub.empty: |
| return f"### {L['no_data']}" |
| blocks = [] |
| for _, row in sub.iterrows(): |
| diff = fmt(row.get("difficulty", "")) |
| badge = f" `[{diff}]`" if diff else "" |
| blocks.append( |
| f"### ❓ {fmt(row.get('question',''))}{badge}\n\n" |
| f"**Answer:** {fmt(row.get('answer',''))}\n\n---\n" |
| ) |
| return "\n".join(blocks) |
|
|
|
|
| def build_stats(df, lang): |
| L = LABELS[lang] |
| figs = [] |
| if "type" in df.columns: |
| type_counts = df["type"].value_counts().reset_index() |
| type_counts.columns = ["Type", "Count"] |
| fig1 = px.bar(type_counts, x="Type", y="Count", title=L["by_type"], |
| color="Type", text_auto=True) |
| fig1.update_layout(showlegend=False) |
| figs.append(fig1) |
| tools_df = filter_type(df, "tool") |
| if not tools_df.empty and "category" in tools_df.columns: |
| cat_counts = tools_df["category"].value_counts().reset_index() |
| cat_counts.columns = ["Category", "Count"] |
| fig2 = px.pie(cat_counts, names="Category", values="Count", title=L["by_category"]) |
| figs.append(fig2) |
| uc_df = filter_type(df, "usecase") |
| if not uc_df.empty and "industry" in uc_df.columns: |
| ind_counts = uc_df["industry"].value_counts().reset_index() |
| ind_counts.columns = ["Industry", "Count"] |
| fig3 = px.bar(ind_counts, x="Industry", y="Count", title=L["by_industry"], |
| color="Industry", text_auto=True) |
| fig3.update_layout(showlegend=False) |
| figs.append(fig3) |
| qa_df = filter_type(df, "qa") |
| if not qa_df.empty and "difficulty" in qa_df.columns: |
| diff_counts = qa_df["difficulty"].value_counts().reset_index() |
| diff_counts.columns = ["Difficulty", "Count"] |
| fig4 = px.pie(diff_counts, names="Difficulty", values="Count", title=L["difficulty_dist"]) |
| figs.append(fig4) |
| return figs |
|
|
| |
| |
| |
|
|
| FOOTER_HTML = """ |
| <div style="text-align:center; padding:20px; margin-top:30px; border-top:1px solid #444; font-size:0.9em; color:#aaa;"> |
| <p><strong>Zero Trust Architecture Explorer</strong> — Built by AYI-NEDJIMI Consultants</p> |
| <p> |
| <a href="https://ayinedjimi-consultants.fr" target="_blank" style="margin:0 10px;">🌐 ayinedjimi-consultants.fr</a> |
| <a href="https://www.linkedin.com/company/ayi-nedjimi" target="_blank" style="margin:0 10px;">💼 LinkedIn</a> |
| <a href="https://github.com/AYI-NEDJIMI" target="_blank" style="margin:0 10px;">🐙 GitHub</a> |
| <a href="https://x.com/AYI_NEDJIMI" target="_blank" style="margin:0 10px;">🐦 X / Twitter</a> |
| </p> |
| </div> |
| """ |
|
|
| |
| |
| |
|
|
| def create_app(): |
| |
| for lang in ("en", "fr"): |
| df = get_data(lang) |
| ensure_columns(df) |
|
|
| with gr.Blocks( |
| title="Zero Trust Architecture Explorer", |
| theme=gr.themes.Soft(primary_hue="blue", secondary_hue="indigo"), |
| css=""" |
| .main-title {text-align:center; margin-bottom:0;} |
| .sub-title {text-align:center; color:#666; margin-top:0;} |
| """ |
| ) as demo: |
|
|
| |
| lang_state = gr.State("en") |
|
|
| |
| title_md = gr.Markdown("# 🔐 Zero Trust Architecture Explorer", elem_classes=["main-title"]) |
| subtitle_md = gr.Markdown("*Explore principles, frameworks, pillars, tools, use cases & Q&A*", |
| elem_classes=["sub-title"]) |
|
|
| with gr.Row(): |
| lang_toggle = gr.Radio( |
| choices=["English", "Français"], |
| value="English", |
| label="Language / Langue", |
| scale=1, |
| ) |
| entry_count = gr.Markdown("") |
|
|
| |
| with gr.Tabs() as tabs: |
| |
| with gr.Tab("Principles", id="tab_principles") as tab_principles: |
| principles_md = gr.Markdown() |
|
|
| |
| with gr.Tab("Frameworks", id="tab_frameworks") as tab_frameworks: |
| fw_org_filter = gr.Dropdown(label="Filter by Organization", choices=["All"], value="All", interactive=True) |
| frameworks_md = gr.Markdown() |
|
|
| |
| with gr.Tab("Implementation Pillars", id="tab_pillars") as tab_pillars: |
| pillars_md = gr.Markdown() |
|
|
| |
| with gr.Tab("Solutions & Tools", id="tab_tools") as tab_tools: |
| tools_cat_filter = gr.Dropdown(label="Filter by Category", choices=["All"], value="All", interactive=True) |
| tools_md = gr.Markdown() |
|
|
| |
| with gr.Tab("Use Cases", id="tab_usecases") as tab_usecases: |
| uc_ind_filter = gr.Dropdown(label="Filter by Industry", choices=["All"], value="All", interactive=True) |
| usecases_md = gr.Markdown() |
|
|
| |
| with gr.Tab("Q&A", id="tab_qa") as tab_qa: |
| qa_md = gr.Markdown() |
|
|
| |
| with gr.Tab("Statistics", id="tab_stats") as tab_stats: |
| stats_plots = [gr.Plot() for _ in range(4)] |
|
|
| |
| gr.HTML(FOOTER_HTML) |
|
|
| |
|
|
| def refresh_all(lang_label, org_f, cat_f, ind_f): |
| lang = "fr" if lang_label == "Français" else "en" |
| L = LABELS[lang] |
| df = get_data(lang) |
| ensure_columns(df) |
|
|
| count_text = f"**{L['total_entries']}:** {len(df)}" |
|
|
| |
| p_md = build_principles(df, lang) |
|
|
| |
| fw_md, fw_orgs = build_frameworks(df, lang, org_f) |
| fw_org_val = org_f if org_f in fw_orgs else (L["all"] if fw_orgs else "All") |
|
|
| |
| pl_md = build_pillars(df, lang) |
|
|
| |
| t_md, t_cats = build_tools(df, lang, cat_f) |
| t_cat_val = cat_f if cat_f in t_cats else (L["all"] if t_cats else "All") |
|
|
| |
| uc_md, uc_inds = build_usecases(df, lang, ind_f) |
| uc_ind_val = ind_f if ind_f in uc_inds else (L["all"] if uc_inds else "All") |
|
|
| |
| q_md = build_qa(df, lang) |
|
|
| |
| stat_figs = build_stats(df, lang) |
| while len(stat_figs) < 4: |
| stat_figs.append(go.Figure()) |
|
|
| return [ |
| f"# {L['title']}", |
| f"*{L['subtitle']}*", |
| count_text, |
| p_md, |
| gr.update(choices=fw_orgs if fw_orgs else ["All"], value=fw_org_val, label=L["filter_org"]), |
| fw_md, |
| pl_md, |
| gr.update(choices=t_cats if t_cats else ["All"], value=t_cat_val, label=L["filter_cat"]), |
| t_md, |
| gr.update(choices=uc_inds if uc_inds else ["All"], value=uc_ind_val, label=L["filter_ind"]), |
| uc_md, |
| q_md, |
| ] + stat_figs |
|
|
| outputs = [ |
| title_md, subtitle_md, entry_count, |
| principles_md, |
| fw_org_filter, frameworks_md, |
| pillars_md, |
| tools_cat_filter, tools_md, |
| uc_ind_filter, usecases_md, |
| qa_md, |
| ] + stats_plots |
|
|
| |
| lang_toggle.change( |
| fn=refresh_all, |
| inputs=[lang_toggle, fw_org_filter, tools_cat_filter, uc_ind_filter], |
| outputs=outputs, |
| ) |
|
|
| |
| fw_org_filter.change( |
| fn=refresh_all, |
| inputs=[lang_toggle, fw_org_filter, tools_cat_filter, uc_ind_filter], |
| outputs=outputs, |
| ) |
| tools_cat_filter.change( |
| fn=refresh_all, |
| inputs=[lang_toggle, fw_org_filter, tools_cat_filter, uc_ind_filter], |
| outputs=outputs, |
| ) |
| uc_ind_filter.change( |
| fn=refresh_all, |
| inputs=[lang_toggle, fw_org_filter, tools_cat_filter, uc_ind_filter], |
| outputs=outputs, |
| ) |
|
|
| |
| demo.load( |
| fn=refresh_all, |
| inputs=[lang_toggle, fw_org_filter, tools_cat_filter, uc_ind_filter], |
| outputs=outputs, |
| ) |
|
|
| return demo |
|
|
|
|
| if __name__ == "__main__": |
| app = create_app() |
| app.launch() |
|
|