File size: 5,030 Bytes
de189a6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
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()
|