Skip to content

Commit f7a97ce

Browse files
committed
wip: Make sense of everything
1 parent 6fd364c commit f7a97ce

File tree

5 files changed

+40
-36
lines changed

5 files changed

+40
-36
lines changed

README.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ This collection of scripts is the culmination of my efforts to contributes the A
2727

2828
## Tools
2929

30-
### Illustrator
30+
### Illustrator
3131
Creates custom mnemonic images for your cards using AI image generation. It:
3232
- Analyzes card content to identify key concepts
3333
- Generates creative visual memory hooks
@@ -387,14 +387,24 @@ Dataset files (like `explainer_dataset.txt`, `reformulator_dataset.txt`, etc.) a
387387
Click to read more
388388
</summary>
389389

390+
First, create an _API_KEYS/_ directory and place your API key in a separate file.
391+
392+
Next, install the [AnkiConnect](https://ankiweb.net/shared/info/2055492159) Anki addon if you don't already have it.
393+
390394
#### Reformulator
395+
396+
Next... create a database? it expects a sqlite db in databases/reformulator/reformulator?
397+
398+
Next... something about adding a field called `AnkiReformulator` to notes you want to change?
399+
* Do you have to create a special note type for this to work?
400+
391401
The Reformulator can be run from the command line:
392402

393403
```bash
394404
python reformulator.py \
395405
--query "(rated:2:1 OR rated:2:2) -is:suspended" \
396-
--dataset_path "data/reformulator_dataset.txt" \
397-
--string_formatting "data/string_formatting.py" \
406+
--dataset_path "examples/reformulator_dataset.txt" \
407+
--string_formatting "examples/string_formatting.py" \
398408
--ntfy_url "ntfy.sh/YOUR_TOPIC" \
399409
--main_field_index 0 \
400410
--llm "openai/gpt-4" \

reformulator.py

+25-31
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
d = datetime.datetime.today()
5252
today = f"{d.day:02d}_{d.month:02d}_{d.year:04d}"
5353

54+
whi("Loading api keys")
5455
load_api_keys()
5556

5657

@@ -184,7 +185,7 @@ def handle_exception(exc_type, exc_value, exc_traceback):
184185
[print(line) for line in traceback.format_tb(exc_traceback)]
185186
print(str(exc_value))
186187
print(str(exc_type))
187-
print("\n--verbose was used so opening debug console at the "
188+
print("\n--debug was used so opening debug console at the "
188189
"appropriate frame. Press 'c' to continue to the frame "
189190
"of this print.")
190191
pdb.post_mortem(exc_traceback)
@@ -203,13 +204,14 @@ def handle_exception(exc_type, exc_value, exc_traceback):
203204
print(json.dumps(db_content, ensure_ascii=False, indent=4))
204205
return
205206
else:
206-
sync_anki()
207+
# sync_anki()
207208
assert query is not None, "Must specify --query"
208209
assert dataset_path is not None, "Must specify --dataset_path"
209210
litellm.set_verbose = verbose
210211

211212
# arg sanity check and storing
212-
assert "note:" in query, "You have to specify a notetype in the query"
213+
# TODO: Is this needed? The example in the readme doesn't set it
214+
# assert "note:" in query, f"You have to specify a notetype in the query ({query})"
213215
assert mode in ["reformulate", "reset"], "Invalid value for 'mode'"
214216
assert isinstance(exclude_done, bool), "exclude_done must be a boolean"
215217
assert isinstance(exclude_version, bool), "exclude_version must be a boolean"
@@ -225,7 +227,7 @@ def handle_exception(exc_type, exc_value, exc_traceback):
225227
main_field_index = int(main_field_index)
226228
assert main_field_index >= 0, "invalid field_index"
227229
self.mode = mode
228-
if string_formatting is not None:
230+
if string_formatting:
229231
red(f"Loading specific string formatting from {string_formatting}")
230232
cloze_input_parser, cloze_output_parser = load_formatting_funcs(
231233
path=string_formatting,
@@ -264,14 +266,14 @@ def handle_exception(exc_type, exc_value, exc_traceback):
264266
query += f" -AnkiReformulator:\"*version*=*'{self.VERSION}'*\""
265267

266268
# load db just in case
267-
self.db_content = self.load_db()
268-
if not self.db_content:
269-
red(
270-
"Empty database. If you have already ran anki_reformulator "
271-
"before then something went wrong!"
272-
)
273-
else:
274-
self.compute_cost(self.db_content)
269+
270+
# TODO: How is the user supposed to create the database in the first place?
271+
# self.db_content = self.load_db()
272+
# if not self.db_content:
273+
# red("Empty database. If you have already ran anki_reformulator "
274+
# "before then something went wrong!")
275+
# else:
276+
# self.compute_cost(self.db_content)
275277

276278
# load dataset
277279
dataset = load_dataset(dataset_path)
@@ -286,9 +288,7 @@ def handle_exception(exc_type, exc_value, exc_traceback):
286288
nids = anki(action="findNotes",
287289
query="tag:AnkiReformulator::RESETTING")
288290
if nids:
289-
red(
290-
f"Found {len(nids)} notes with tag AnkiReformulator::RESETTING : {nids}"
291-
)
291+
red(f"Found {len(nids)} notes with tag AnkiReformulator::RESETTING : {nids}")
292292
nids = anki(action="findNotes", query="tag:AnkiReformulator::DOING")
293293
if nids:
294294
red(f"Found {len(nids)} notes with tag AnkiReformulator::DOING : {nids}")
@@ -298,13 +298,10 @@ def handle_exception(exc_type, exc_value, exc_traceback):
298298
assert nids, f"No notes found for the query '{query}'"
299299

300300
# find the model field names
301-
fields = anki(
302-
action="notesInfo",
303-
notes=[int(nids[0])]
304-
)[0]["fields"]
305-
assert (
306-
"AnkiReformulator" in fields.keys()
307-
), "The notetype to edit must have a field called 'AnkiReformulator'"
301+
fields = anki(action="notesInfo",
302+
notes=[int(nids[0])])[0]["fields"]
303+
# assert "AnkiReformulator" in fields.keys(), \
304+
# "The notetype to edit must have a field called 'AnkiReformulator'"
308305
self.field_name = list(fields.keys())[0]
309306

310307
if self.exclude_media:
@@ -328,9 +325,8 @@ def handle_exception(exc_type, exc_value, exc_traceback):
328325
self.notes = self.notes.loc[nids]
329326
assert not self.notes.empty, "Empty notes df"
330327

331-
assert (
332-
len(set(self.notes["modelName"].tolist())) == 1
333-
), "Contains more than 1 note type"
328+
assert len(set(self.notes["modelName"].tolist())) == 1, \
329+
"Contains more than 1 note type"
334330

335331
# check absence of image and sounds in the main field
336332
# as well incorrect tags
@@ -358,11 +354,9 @@ def handle_exception(exc_type, exc_value, exc_traceback):
358354
else:
359355
assert not tag.lower().startswith("ankireformulator")
360356

361-
362357
# check if too many tokens
363358
tkn_sum = sum([tkn_len(d["content"]) for d in self.dataset])
364359
tkn_sum += sum(
365-
[
366360
tkn_len(
367361
replace_media(
368362
content=note["fields"][self.field_name]["value"],
@@ -371,7 +365,7 @@ def handle_exception(exc_type, exc_value, exc_traceback):
371365
)[0]
372366
)
373367
for _, note in self.notes.iterrows()
374-
])
368+
)
375369
if tkn_sum > tkn_warn_limit:
376370
raise Exception(
377371
f"Found {tkn_sum} tokens to process, which is "
@@ -983,7 +977,7 @@ def load_db(self) -> Dict:
983977
All log dictionaries from the database, or False if database not found
984978
"""
985979
if not (REFORMULATOR_DIR / "reformulator.db").exists():
986-
red("db not found: '$REFORMULATOR_DIR/reformulator.db'")
980+
red(f"db not found: '{REFORMULATOR_DIR}/reformulator.db'")
987981
return False
988982
conn = sqlite3.connect(str((REFORMULATOR_DIR / "reformulator.db").absolute()))
989983
cursor = conn.cursor()
@@ -1000,10 +994,10 @@ def load_db(self) -> Dict:
1000994
try:
1001995
args, kwargs = fire.Fire(lambda *args, **kwargs: [args, kwargs])
1002996
if "help" in kwargs:
1003-
print(help(AnkiReformulator))
997+
print(help(AnkiReformulator), file=sys.stderr)
1004998
else:
1005999
whi(f"Launching reformulator.py with args '{args}' and kwargs '{kwargs}'")
10061000
AnkiReformulator(*args, **kwargs)
1001+
sync_anki()
10071002
except Exception:
1008-
sync_anki()
10091003
raise

utils/llm.py

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def load_api_keys() -> Dict:
2828
Path("API_KEYS").mkdir(exist_ok=True)
2929
if not list(Path("API_KEYS").iterdir()):
3030
shared.red("## No API_KEYS found in API_KEYS")
31+
raise Exception("Need to write API KEYS to API_KEYS/")
3132
api_keys = {}
3233
for apifile in Path("API_KEYS").iterdir():
3334
keyname = f"{apifile.stem.upper()}_API_KEY"

utils/logger.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,6 @@ def create_loggers(local_file: Union[str, PosixPath], colors: List[str]):
8585
out = []
8686
for col in colors:
8787
log = coloured_logger(col)
88-
setattr(shared, "col", log)
88+
setattr(shared, col, log)
8989
out.append(log)
9090
return out

utils/shared.py

-1
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,3 @@ def __setattr__(self, name: str, value) -> None:
3939
raise TypeError(f'SharedModule forbids the creation of unexpected attribute "{name}"')
4040

4141
shared = SharedModule()
42-

0 commit comments

Comments
 (0)