import gradio as gr import pandas as pd import plotly.express as px import plotly.graph_objects as go from datasets import load_dataset # --------------------------------------------------------------------------- # Data loading # --------------------------------------------------------------------------- def load_data(lang="en"): """Load the dataset for the given language.""" repo = "AYI-NEDJIMI/ai-agents-fr" if lang == "fr" else "AYI-NEDJIMI/ai-agents-en" ds = load_dataset(repo, split="train") df = ds.to_pandas() return df # Pre-load both datasets at startup DATA = {} for _lang in ("en", "fr"): try: DATA[_lang] = load_data(_lang) except Exception as e: print(f"Warning: could not load {_lang} dataset: {e}") DATA[_lang] = pd.DataFrame(columns=["id", "category", "subcategory", "question", "answer", "metadata", "source_url", "language"]) ALL_CATEGORIES = ["All"] + sorted(DATA["en"]["category"].dropna().unique().tolist()) # --------------------------------------------------------------------------- # Helper functions # --------------------------------------------------------------------------- def get_df(lang): return DATA.get(lang, DATA["en"]) def filter_explorer(search_text, category, lang): df = get_df(lang) if category and category != "All": df = df[df["category"] == category] if search_text: mask = ( df["question"].str.contains(search_text, case=False, na=False) | df["category"].str.contains(search_text, case=False, na=False) | df["subcategory"].str.contains(search_text, case=False, na=False) ) df = df[mask] display_df = df[["category", "subcategory", "question"]].reset_index(drop=True) return display_df def get_item_details(evt: gr.SelectData, lang): df = get_df(lang) if evt is None: return "", "", "", "" row_idx = evt.index[0] if isinstance(evt.index, (list, tuple)) else evt.index # We need to map back; the explorer table was filtered, so we search by question question_val = evt.value if isinstance(evt.value, str) else "" # Fallback: try to find by row in full df if row_idx < len(df): row = df.iloc[row_idx] else: row = df.iloc[0] # Better approach: search by the selected row's question from the displayed table return ( str(row.get("question", "")), str(row.get("answer", "")), str(row.get("metadata", "")), str(row.get("source_url", "")) ) def get_details_by_id(item_id, lang): df = get_df(lang) if item_id is None or item_id == "": return "Select an item ID", "", "", "" try: item_id = int(item_id) except (ValueError, TypeError): return "Invalid ID", "", "", "" matches = df[df["id"] == item_id] if matches.empty: return "Item not found", "", "", "" row = matches.iloc[0] return ( str(row.get("question", "")), str(row.get("answer", "")), str(row.get("metadata", "")), str(row.get("source_url", "")) ) def get_qa_pairs(category, lang): df = get_df(lang) if category and category != "All": df = df[df["category"] == category] pairs = [] for _, row in df.iterrows(): pairs.append(f"### Q: {row['question']}\n\n**A:** {row['answer']}\n\n---\n") return "\n".join(pairs) if pairs else "No items found." def get_id_choices(lang): df = get_df(lang) return [str(i) for i in sorted(df["id"].unique().tolist())] def build_category_chart(lang): df = get_df(lang) counts = df["category"].value_counts().reset_index() counts.columns = ["Category", "Count"] fig = px.bar( counts, x="Category", y="Count", color="Category", title="Distribution by Category", template="plotly_white", color_discrete_sequence=px.colors.qualitative.Set2 ) fig.update_layout(showlegend=False, xaxis_tickangle=-30, margin=dict(t=50, b=80)) return fig def build_subcategory_chart(lang): df = get_df(lang) counts = df.groupby(["category", "subcategory"]).size().reset_index(name="Count") fig = px.bar( counts, x="subcategory", y="Count", color="category", title="Distribution by Subcategory", template="plotly_white", color_discrete_sequence=px.colors.qualitative.Set2 ) fig.update_layout(xaxis_tickangle=-45, margin=dict(t=50, b=120), legend_title_text="Category") return fig def build_pie_chart(lang): df = get_df(lang) counts = df["category"].value_counts().reset_index() counts.columns = ["Category", "Count"] fig = px.pie( counts, names="Category", values="Count", title="Category Proportions", template="plotly_white", color_discrete_sequence=px.colors.qualitative.Set2 ) fig.update_layout(margin=dict(t=50, b=30)) return fig # --------------------------------------------------------------------------- # Footer HTML # --------------------------------------------------------------------------- FOOTER_HTML = """

AI Agents & Frameworks Explorer — Built by AYI-NEDJIMI Consultants

ayinedjimi-consultants.fr LinkedIn GitHub X / Twitter

""" # --------------------------------------------------------------------------- # Gradio UI # --------------------------------------------------------------------------- theme = gr.themes.Soft( primary_hue="indigo", secondary_hue="purple", neutral_hue="slate", ) with gr.Blocks(theme=theme, title="AI Agents & Frameworks Explorer") as demo: gr.Markdown("# AI Agents & Frameworks Explorer\nExplore 132 curated entries on AI agent architectures, frameworks, tools, orchestration, memory, and planning.") # Language toggle (shared state) lang_state = gr.State("en") with gr.Row(): lang_toggle = gr.Radio( choices=["EN", "FR"], value="EN", label="Language", interactive=True, scale=0 ) with gr.Tabs(): # ---- Explorer Tab ---- with gr.TabItem("Explorer"): with gr.Row(): search_box = gr.Textbox(label="Search", placeholder="Type to search questions, categories...", scale=3) cat_filter = gr.Dropdown(choices=ALL_CATEGORIES, value="All", label="Category", scale=1) explorer_table = gr.Dataframe( headers=["category", "subcategory", "question"], label="Results", interactive=False, wrap=True, ) # ---- Details Tab ---- with gr.TabItem("Details"): gr.Markdown("Select an item by its ID to view full details.") item_id_input = gr.Dropdown(label="Item ID", choices=get_id_choices("en"), interactive=True) detail_question = gr.Textbox(label="Question", lines=2, interactive=False) detail_answer = gr.Textbox(label="Answer", lines=10, interactive=False) detail_metadata = gr.Textbox(label="Metadata", lines=3, interactive=False) detail_url = gr.Textbox(label="Source URL", lines=1, interactive=False) # ---- Q&A Tab ---- with gr.TabItem("Q&A"): qa_cat_filter = gr.Dropdown(choices=ALL_CATEGORIES, value="All", label="Filter by Category") qa_output = gr.Markdown(label="Question & Answer Pairs") # ---- Statistics Tab ---- with gr.TabItem("Statistics"): stats_cat_chart = gr.Plot(label="By Category") stats_sub_chart = gr.Plot(label="By Subcategory") stats_pie_chart = gr.Plot(label="Proportions") gr.HTML(FOOTER_HTML) # ---- Event wiring ---- def on_lang_change(lang_label): lang = "fr" if lang_label == "FR" else "en" explorer = filter_explorer("", "All", lang) qa = get_qa_pairs("All", lang) cat_chart = build_category_chart(lang) sub_chart = build_subcategory_chart(lang) pie_chart = build_pie_chart(lang) id_choices = get_id_choices(lang) return ( lang, # lang_state explorer, # explorer_table qa, # qa_output cat_chart, sub_chart, pie_chart, # stats charts gr.update(choices=id_choices, value=None), # item_id_input ) lang_toggle.change( on_lang_change, inputs=[lang_toggle], outputs=[lang_state, explorer_table, qa_output, stats_cat_chart, stats_sub_chart, stats_pie_chart, item_id_input], ) # Explorer search / filter def on_explorer_change(search_text, category, lang): return filter_explorer(search_text, category, lang) search_box.change(on_explorer_change, inputs=[search_box, cat_filter, lang_state], outputs=[explorer_table]) cat_filter.change(on_explorer_change, inputs=[search_box, cat_filter, lang_state], outputs=[explorer_table]) # Details item_id_input.change( lambda item_id, lang: get_details_by_id(item_id, lang), inputs=[item_id_input, lang_state], outputs=[detail_question, detail_answer, detail_metadata, detail_url], ) # Q&A filter qa_cat_filter.change( lambda cat, lang: get_qa_pairs(cat, lang), inputs=[qa_cat_filter, lang_state], outputs=[qa_output], ) # Initial load demo.load( on_lang_change, inputs=[lang_toggle], outputs=[lang_state, explorer_table, qa_output, stats_cat_chart, stats_sub_chart, stats_pie_chart, item_id_input], ) if __name__ == "__main__": demo.launch()