kong
initial commit
de189a6
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()