Download app.py from Agents-MCP-Hackathon/AnkiCardGenerator: direct link, hf CLI and curl.
- Browser
- Download file 5.03 kB
-
https://huggingface.co/spaces/Agents-MCP-Hackathon/AnkiCardGenerator/resolve/main/app.py
- Command line
-
hf download hf://spaces/Agents-MCP-Hackathon/AnkiCardGenerator/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Agents-MCP-Hackathon/AnkiCardGenerator/resolve/main/app.py
5.03 kB
| from __future__ import annotations | |
| import json | |
| import random | |
| import tempfile | |
| from pathlib import Path | |
| from typing import Optional | |
| import gradio as gr | |
| from agent import create_anki_deck | |
| try: | |
| import genanki # type: ignore | |
| GENANKI_AVAILABLE = True | |
| except ImportError: | |
| GENANKI_AVAILABLE = False | |
| # --------------------------------------------------------------------------- | |
| # generate .apkg or JSON) | |
| # --------------------------------------------------------------------------- | |
| def _build_package_file(deck_dict: dict, deck_name_override: str | None = None) -> str: # β θΏε str | |
| deck_title = (deck_name_override or deck_dict.get("name") or "AI_Deck").strip() | |
| if GENANKI_AVAILABLE: | |
| # ---------- generate .apkg ---------- | |
| import genanki | |
| basic_model = genanki.Model( | |
| 1607392319, | |
| "AI Basic Model", | |
| fields=[{"name": "Front"}, {"name": "Back"}], | |
| templates=[{ | |
| "name": "Card 1", | |
| "qfmt": "{{Front}}", | |
| "afmt": "{{FrontSide}}<hr id=answer>{{Back}}", | |
| }], | |
| ) | |
| cloze_model = genanki.Model( | |
| 1091735104, | |
| "AI Cloze Model", | |
| model_type=genanki.Model.CLOZE, | |
| fields=[{"name": "Text"}, {"name": "Back"}], | |
| templates=[{ | |
| "name": "Cloze Card", | |
| "qfmt": "{{cloze:Text}}", | |
| "afmt": "{{cloze:Text}}<br>{{Back}}", | |
| }], | |
| ) | |
| deck = genanki.Deck(random.getrandbits(32), deck_title) | |
| tags = deck_dict.get("tags", []) | |
| for card in deck_dict["cards"]: | |
| model = cloze_model if card["type"].lower().startswith("cloze") else basic_model | |
| note = genanki.Note(model=model, fields=[card["front"], card["back"]], tags=tags) | |
| deck.add_note(note) | |
| pkg = genanki.Package(deck) | |
| tmpf = tempfile.NamedTemporaryFile(delete=False, suffix=".apkg") | |
| pkg.write_to_file(tmpf.name) | |
| return tmpf.name | |
| # ---------- generate JSON ---------- | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".json", mode="w", encoding="utf-8") as tf: | |
| json.dump(deck_dict, tf, ensure_ascii=False, indent=2) | |
| return tf.name | |
| # --------------------------------------------------------------------------- | |
| # callback function to generate Anki deck | |
| # --------------------------------------------------------------------------- | |
| def generate_deck( | |
| uploaded_path: Optional[str], | |
| url_input: str, | |
| card_type_pref: str, | |
| deck_name_pref: str, | |
| tags_pref: str, | |
| user_req_pref: str, | |
| ): | |
| if not uploaded_path and not url_input.strip(): | |
| raise gr.Error("Please upload a file or enter a URL.") | |
| params: dict[str, object] = { | |
| "card_types": card_type_pref, | |
| "user_requirements": user_req_pref, | |
| } | |
| if uploaded_path: | |
| path = Path(uploaded_path) | |
| params["pdf_file" if path.suffix.lower() == ".pdf" else "img_file"] = path | |
| else: | |
| params["url"] = url_input.strip() | |
| # agent | |
| deck_dict = create_anki_deck(**params)["deck"] | |
| if deck_name_pref.strip(): | |
| deck_dict["name"] = deck_name_pref.strip() | |
| if tags_pref.strip(): | |
| deck_dict["tags"] = [t.strip() for t in tags_pref.split(",") if t.strip()] | |
| output_path = _build_package_file(deck_dict, deck_name_pref) | |
| return str(output_path) | |
| # --------------------------------------------------------------------------- | |
| # Gradio UI | |
| # --------------------------------------------------------------------------- | |
| demo = gr.Blocks(theme=gr.themes.Soft(), title="Anki Card Generator") | |
| with demo: | |
| gr.Markdown("# π§ Anki Card Generator") | |
| gr.Markdown("Upload an image or PDF, or enter a URL to generate Anki cards.") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| file_input = gr.File(label="π Upload PDF or image", file_types=["image", ".pdf"], type="filepath") | |
| url_input = gr.Textbox(label="π Or enter url", placeholder="https://example.com/article") | |
| user_requirements_input = gr.Textbox(label="π― Your requirements", lines=4) | |
| card_type_input = gr.Textbox(label="π Card type", value="Basic,Cloze") | |
| deck_name_input = gr.Textbox(label="π·οΈ Deck name", value="Animal") | |
| tags_input = gr.Textbox(label="β¨ Tags (comma-separated)", placeholder="e.g. biology, mammals", value="biology,mammals") | |
| generate_button = gr.Button("Generate", variant="primary") | |
| with gr.Column(scale=1): | |
| anki_output_file = gr.File(label="π₯ Download (.apkg / .json)") | |
| generate_button.click( | |
| fn=generate_deck, | |
| inputs=[file_input, url_input, card_type_input, deck_name_input, tags_input, user_requirements_input], | |
| outputs=[anki_output_file], | |
| ) | |
| gr.Markdown("---") | |
| gr.Markdown("β genanki :{}".format("Available" if GENANKI_AVAILABLE else "Not installed (will export JSON)")) | |
| if __name__ == "__main__": | |
| demo.launch() | |