I use beeminder to track my anki reviews. for a long time I manually inputted a +1 when I finished, but I’d always wanted an autodata solution because I find it tedious to keep up with manual data entry for more than a couple goals at a time.
however, none of the existing solutions quite did it for me - the thing I most care about is whether I did all of my reviews, not exactly how many reviews I did (which fluctuates by day) or some other incidental statistic.
I’ve come up with an autodata extension which basically works for me. it’s not at all plug and play, but for anyone else looking to work up an autodata solution for this or some other goal, it might be helpful as simple guidelines.
# ~/.local/share/Anki2/addons21/ankibee/__init__.py
from string import Template
import requests
import os
# from anki.collection import Collection
from aqt import mw
from aqt import gui_hooks
try:
from dotenv import load_dotenv
load_dotenv() # loads from .env by default
except ImportError:
pass
bee_user = os.getenv('BEEMINDER_USER')
bee_auth_token = os.getenv('BEEMINDER_AUTH_TOKEN')
bee_goal = "anki"
# is this a good way of doing this? probably not
# but it sends 0 when I haven't done any reviews, 1 when I've done all of them,
# and something in between when I've done something in between. "good enough"
def get_review_ratio():
try:
reviews_due = mw.col.sched.counts()[2]
except AttributeError:
return # something isn't set if we haven't done any reviews this session, dirty way out
review_cards_rated = len(mw.col.find_cards("rated:1 is:review"))
review_ratio = review_cards_rated / (reviews_due + review_cards_rated)
return review_ratio
from aqt.utils import showInfo
def send_datapoint(goal, value, comment = 'via ankibee'):
return requests.post(f'https://www.beeminder.com/api/v1/users/{bee_user}/goals/{goal}/datapoints.json', data = {
'auth_token': bee_auth_token,
'value': value,
'requestid': mw.col.sched.today, # if we submit multiple datapoints on the same day it replaces the earlier datapoint
'comment': comment
})
def beemind_review_ratio():
send_datapoint('anki', get_review_ratio())
def beemind_anki_journal():
journal_note_count = len(mw.col.find_notes("tag:anki-journal"))
send_datapoint('anki-journal', journal_note_count)
# TODO we also do things that are *not* beeminding # we actually don't yet ignore this
# repeatedly sending datapoints should be idempotent otherwise
# TODO these requests are synchronous, if we make a lot that could get annoying
def beemind_everything():
beemind_review_ratio()
beemind_anki_journal()
gui_hooks.profile_will_close.append(beemind_everything)