Skip to content

Instantly share code, notes, and snippets.

@galopyz
Created August 21, 2025 21:45
Show Gist options
  • Select an option

  • Save galopyz/c3a40839fbafe99350673b10a313a67b to your computer and use it in GitHub Desktop.

Select an option

Save galopyz/c3a40839fbafe99350673b10a313a67b to your computer and use it in GitHub Desktop.
My Dialog
import os, json, urllib, pymupdf
from typing import *
from fastcore.utils import *
from fasthtml.common import *
from monsterui.all import *
from httpx import get as xget
from PIL import Image
import matplotlib.pyplot as plt
ANKI_API_KEY = os.environ.get('ANKI_API_KEY')
HOME_URL = os.environ.get('HOME_URL')
def extract_text_by_pages(pdf_path: str) -> List[str]:
"Extract text from PDF pages using pymupdf"
doc = pymupdf.open(pdf_path)
pages = [page.get_text() for page in doc]
doc.close()
return pages
def view_page(pages: List[str], page_num: int, chars: Optional[int] = None) -> str:
"View content of a specific page with optional character limit"
if page_num < 1 or page_num > len(pages): return f"Error: Page number must be between 1 and {len(pages)}"
return pages[page_num-1][:chars] if chars else pages[page_num-1]
def request(action: str, params: Dict = None) -> dict:
"Create AnkiConnect API request with action and parameters"
if params is None: params = {}
return dict(action=action, params=params, version=6, key=ANKI_API_KEY)
def invoke(action: str, params: Dict = None) -> Any:
"Send AnkiConnect API request and return result"
if params is None: params = {}
requestJson = json.dumps(request(action, params)).encode('utf-8')
response = json.load(urllib.request.urlopen(urllib.request.Request(HOME_URL, requestJson)))
if len(response) != 2: raise Exception('response has an unexpected number of fields')
if 'error' not in response: raise Exception('response is missing required error field')
if 'result' not in response: raise Exception('response is missing required result field')
if response['error'] is not None: raise Exception(response['error'])
return response['result']
class AnkiCard:
"Anki flashcard with front/back content and deck management"
def __init__(self, front: str, back: str, deck: str = "test1", tags: Optional[List[str]] = None, card_id: Optional[int] = None):
self.front,self.back,self.deck,self.tags,self.card_id = front,back,deck,tags or [],card_id
def add_to_anki(self) -> int:
"Add this card to Anki and update with assigned ID"
note = dict(deckName=self.deck, modelName="Basic", fields=dict(Front=self.front, Back=self.back), tags=self.tags)
self.card_id = invoke('addNote', note=note)
return self.card_id
def update(self) -> None:
"Update an existing card in Anki"
if not self.card_id: raise ValueError("Card hasn't been added to Anki yet")
note = dict(id=self.card_id, fields=dict(Front=self.front, Back=self.back), tags=self.tags)
invoke('updateNote', note=note)
def delete(self) -> None:
"Delete this card from Anki"
if not self.card_id: raise ValueError("Card hasn't been added to Anki yet")
invoke('deleteNotes', notes=[self.card_id])
self.card_id = None
def get_deck_cards(deck_name: str) -> List[Dict]:
"Get all cards from a deck with their front/back content"
card_ids = invoke('findCards', dict(query=f'deck:"{deck_name}"'))
return invoke('cardsInfo', dict(cards=card_ids))
@classmethod
def from_anki_data(cls, card_data: Dict) -> 'Card':
"Create Card object from Anki card data"
front = card_data['fields']['Front']['value']
back = card_data['fields']['Back']['value']
deck = card_data['deckName']
card_id = card_data['cardId']
return cls(front, back, deck, card_id=card_id)
AnkiCard.from_anki_data = from_anki_data
@patch
def __repr__(self:AnkiCard) -> str:
"String representation showing card status and preview"
status = "saved" if self.card_id else "unsaved"
return f"AnkiCard(front='{self.front[:120]}...',\n back='{self.back[:120]}...',\n deck='{self.deck},\n status={status}')"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment