Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More Basic (and reversed card) #5

Open
inefg opened this issue Aug 2, 2024 · 9 comments
Open

More Basic (and reversed card) #5

inefg opened this issue Aug 2, 2024 · 9 comments
Assignees
Labels
enhancement New feature or request

Comments

@inefg
Copy link

inefg commented Aug 2, 2024

hi,

Is it possible to implement three or more reversed ?

test1

---
---
test2

---
---
test3
@kitschpatrol
Copy link
Owner

Hi, thanks for this suggestion.

It's very tempting to implement this, but I don't have time in the near term.

Yanki's focus for now is on simplicity and support for the default note types that ship with Anki. If you need additional note types and customization options, I suggest taking a look at some of the alternatives.

@kitschpatrol kitschpatrol added the enhancement New feature or request label Aug 2, 2024
@inefg
Copy link
Author

inefg commented Aug 2, 2024

The temporary alternative is to split it into 3 files, simple but not elegant, I look forward to your subsequent updates!

test1

test1

---
---
test2

test2

test2

---
---
test3

test3

test3

---
---
test1

@kitschpatrol kitschpatrol self-assigned this Aug 11, 2024
@kitschpatrol
Copy link
Owner

kitschpatrol commented Aug 15, 2024

Hi @inefg, I've been thinking about this a bit more and poking at an implementation.

A couple points / questions

  1. It seems like this could be useful for memorizing both "directional" and "bidirectional" relationships, so theoretically you'd want a variation on the Basic and Basic (and reversed card) as well. Though in some ways a directional variation (a sequence of Basic-style cards) seems more frequently useful?

  2. Hard-coding this to support just three items might be limiting. Use cases might involve learning the order of an alphabet or steps in a checklist, where items counts could run into the dozens.

  3. In your work-around example, the reverse card "wraps back" to the start with the test1 ↔ test3 cards, this seems a little unexpected to me since they're far apart in the source note. If you had four items, are you imagining that every possible connection between all four items would be represented? Let's call it omnidirectional, e.g. 4 items in the note would generate 12 cards in total, growing quadratically from there as the number of items increases? Or are you imagining the first / last items as a special case?

Possible approach

Basic Card

For the basic card, it could make sense to support "chained" syntax useful for memorizing directional associations. This could scale up to an arbitrary number of items, but for the sake of demonstration I will show four:

Item 1

---

Item 2

---

Item 3

---

Item 4

Which would generate the cards:

  • Item 1 → Item 2
  • Item 2 → Item 3
  • Item 3 → Item 4

Basic (and reversed card)

Same as above, but useful for memorizing bidirectional associations... however I'd propose not to support omni-directionality because of the quadratic complexity issue, or the "wrapped last item" because it seems unusual to have a looped graph like that, and if you really needed it for an edge case then you could duplicate the first item at the bottom of the list.

This would look like:

Item 1

---
---

Item 2

---
---

Item 3

---
---

Item 4

Generating the cards:

  • Item 1 → Item 2
  • Item 2 → Item 1
  • Item 2 → Item 3
  • Item 3 → Item 2
  • Item 3 → Item 4
  • Item 4 → Item 3

This all seems a bit complex, but arguably it stacks reasonably on top of the existing Markdown syntax and would stay out of the way.

In terms of deciding on a max item count, I'd really rather not generate models / card types dynamically (it just seems too brittle)... so that would mean hard-coding some upper item limit. Thinking perhaps 50 items.

I welcome your thoughts on all of the above.

@kitschpatrol kitschpatrol changed the title [Feature request] More Basic (and reversed card) More Basic (and reversed card) Sep 1, 2024
@inefg
Copy link
Author

inefg commented Nov 21, 2024

Hi,

I’ve been thinking about situations where it’s necessary to record more than three related items on a single card, which can all be used as reminders.

I wanted to find a practical example to demonstrate this, but unfortunately, I couldn’t find one.

However, when two languages are involved, having three items is feasible.

In such cases, I considered the solution of using Cloze.

Using Basic (and reversed card) made the simple problem more complicated, and I apologize for that.

My thinking is as follows:

SAT
Site Acceptance Testing
现场验收测试
Site acceptance occurs after the equipment is installed at the user's site.

SAT, Site Acceptance Testing, and 现场验收测试 all describe "site acceptance occurs after the equipment is installed at the user's site."

For me, SAT, Site Acceptance Testing, and 现场验收测试 are equally important, and I need to see one of them to recall the others, as they are interconnected.

This example works in a single language, and it can be solved as follows:

SAT

---
---

Site Acceptance Testing

---

Site acceptance occurs after the equipment is installed at the user's site.

When dealing with multiple languages, Basic (and reversed card) creates duplicate cards, like columns M and O, Item 1 → Item 2, Item 1 → Item 3, which can be combined into column Q.

e2d555eec8a7aecf28608984887caba

If there are really four equally important items, the combinations can be reduced to column G.

3f9d719d958c5f6c79afdf53a970286

As you can see, in Anki, I would see four Items, and then recall the other three. This is the same effect as using Cloze, where recalling three other pieces of information leads to recalling one item.

@kitschpatrol
Copy link
Owner

Thanks for the detailed illustrations.

To make sure I understand column G, when you write:

Item 1
Item 2
Item 3
Item 4

You want Item 1 as the front of the resulting card, and then Item 2, Item 3, Item 4 all shown simultaneously on the back of the card? (Plus the other permutations in column G.)

If that's correct, maybe this use case really is better served by clozes?

@kitschpatrol
Copy link
Owner

For example, this approach prompts you to remember the correlation between Site Acceptance Testing and 现场验收测试, and then reveals the definition in English:

~~Site Acceptance Testing~~

~~现场验收测试~~

---

Site acceptance occurs after the equipment is installed at the user's site. 

Creating cards:

  • Item 1 → Item 2 + Item 3
  • Item 2 → Item 1 + Item 3

Or, using clozes for everything:

~~Site Acceptance Testing~~

~~现场验收测试~~

~~Site acceptance occurs after the equipment is installed at the user's site.~~

Creating cards:

  • Item 1 + Item 2 → Item 3
  • Item 1 + Item 3 → Item 2
  • Item 2 + Item 3 → Item 1

@twtu
Copy link

twtu commented Dec 30, 2024

I hope you don't mind me jumping in on this issue. I really like what you've done here with yanki other than only supporting basic card types. I have looked at all the alternatives but none do what I want. In particular, I think a major advantage of "One Obsidian note maps to one Anki note." is that it makes sense when you have complex anki note types.

Regarding your discussion above, I think that yanki should not know or care about what cards are created - only about what notes are created. Therefore, for example, whether a card that "wraps back" is created or not would be entirely handled in anki. Yanki would just make the note with, for example, three fields containing test1, test2, and test3 and anki would make the appropriate cards for those 3 fields without yanki caring.

The two main problems I see are 1. determining which anki note type to use for each obsidian file and 2. determining which part of each obsidian file maps to which anki field.

I will discuss problem 2 first, since I think the solution is more obvious - that is, I think you should use syntax the same as other obsidian plugins, most likely  using dataview metadata (see https://blacksmithgu.github.io/obsidian-dataview/annotation/add-metadata/). For example, let's say you wanted to store the data from the anki Ultimate Geography v5.2 deck (https://ankiweb.net/shared/info/2109889812). The obsidan file could be mostly yaml e.g.

Saint Lucia.md

---
Country: Saint Lucia
Capital: Castries
Flag: <url/filename>
Map: <different url/filename>
---

or it could be inline, e.g.

Saint Lucia.md

(Capital:: Castries) is the capital of (Country:: Saint Lucia). The flag looks like
Flag:: <url/filename>

Note that yanki could potentially use dataview to get the metadata, or yanki could do the parsing (and potentially restrict which ways metadata can be written). alternatively only allow one or two ways of defining metadata (this would also make the data available to dataview which would be nice).

If you want fields that can have multiple lines/more formating, perhaps a heading could become a field name, e.g. an anki field called "Extra context" could be filled in by the content below a# Extra contextheading in obsidian.

For problem 1 (determining which anki note type to use for each obsidian file):
In theory, you could just have a note type with, say, 50 fields that yanki fills in until it runs out of data in the obsidian file, but that means that all your data is not "typed" and you can not have different note types made based on different types of obsidian notes. It also means the notes in obsidian have no information about what should be in field 1 vs field 8 or whatever which could get confusing, so I don't think this is a good idea.

There are plenty of other ways to map obsidian files to note types, for example you could look at all the field names in the obsidian file and find a matching note type, but that might be too difficult/fragile. Another way would be to have the note type in yaml but that is also a bit ugly. Perhaps the simplest way might be to have the note type in the directory hierarchy. If that directory doesn't contain any notes directly, it won't be created. Also most of the time all flashcards in a single deck in anki have the same note type.
e.g.
/Flashcards
/Flashcards/GenericNoteType <- not created in anki
/Flashcards/GenericNoteType/Subdeck
/Flashcards/GenericNoteType/Subdeck B
/Flashcards/GeographyNoteType <- not created in anki
/Flashcards/GeographyNoteType/Ultimate Geography

@twtu
Copy link

twtu commented Dec 30, 2024

Feel free to ignore this comment, I am just outlining my use case in case it is helpful.

What I am aiming for is something similar to some of the template in https://ankiweb.net/shared/info/163606663 where I can add new questions as described at https://eshapard.github.io/anki/the-power-of-making-new-cards-on-the-fly-in-anki.html. The main advantages I am looking for are 1. common contextual information on the back of many cards about the same topic, 2. questions about the topic are automatically spaced by anki (because they are part of the same note) and 3. the ability to add new questions about a topic easily on the fly.

For example an obsidian file might be

The Wonderful Wizard of Oz.md

# Context (this will be shown on the back of every card as additional context)
<picture> The Wonderful Wizard of Oz is a 1900 children's novel written by author L. Frank Baum. A Kansas farm girl named Dorothy ends up in the magical Land of Oz after she and her pet dog Toto are swept away from their home by a cyclone.

Q1:: What is the name of the girl in The Wonderful Wizard of Oz
A1:: Dorothy
Q7:: When was The Wonderful Wizard of Oz published?
A7:: 1900
Q2:: L. Frank Baum is best known for writing which book?
A2:: The Wonderful Wizard of Oz

(the corresponding anki note type may have up to Q20 or Q50).

Another example (if I had a note type for classical music because I wanted more structured data and not to have to write out each question)

Nutcracker.md

opus:: 71
date:: 1892
audio1:: <filename.mp3>
name1:: Dance of the Sugar Plum Fairy
audio2:: <file2.mp3>
name2:: Trepak (Russian Dance)
etc 

# Summary (this will be shown on the back of every card as additional context)
(workname:: The Nutcracker) is a classical (genre:: ballet) in two acts composed by (composer:: Pyotr Ilyich Tchaikovsky). It is based on E.T.A. Hoffmann's 1816 fairy tale The Nutcracker and the Mouse King. <picture of Tchaikovsky> <picture of a nutcracker>

Again, the corresponding note type would have audio3 and audio4 etc as well as probably Q1, A1, Q2, A2 etc. From this I could make all sorts of cards, e.g. from audio1 -> composer, from audio1 -> genre, from name2 -> workname etc etc. Note that if a card front would be empty, the card is not created (that is, even if there is a card template for audio3 -> name3, if the field audio3 is empty for a particular note, the card will not be created).

@kitschpatrol
Copy link
Owner

kitschpatrol commented Dec 30, 2024

Hi twtu, thank you for your interest in the project!

I appreciate the thought you've put into your points, and they are valid, but they introduce trade-offs that aren't consistent with my objectives for the project and the amount of free time I have to devote to it. The entire Yanki stack is MIT licensed and you're absolutely welcome to fork and implement your vision!

I can speak to a few things from your comments:

Defining models in Anki

I think that yanki should not know or care about what cards are created - only about what notes are created. Therefore, for example, whether a card that "wraps back" is created or not would be entirely handled in anki.

Safety issues

One important goal of the project is to never touch notes that weren't created by Yanki, so that you're free to create Anki notes by other means without worry of interference from Yanki. Accomplishing this requires a specific ("Yanki Namespace") field in the Anki model to store this metadata, which means Yanki has to be in charge of creating its own models in Anki with this field. There are other ways to accomplish this (tags, decks), but they all seemed too brittle to me given the risks of data loss if something goes wrong.

Technically, Yanki already only cares about notes and leaves it up to Anki to create cards as appropriate, but the cards Anki creates are defined by the model and its associated card templates — and since Yanki needs to define models the models it's going to interact with, it's implicitly defining cards that way.

Validation issues

Further, the API calls that Yanki uses to create depend on knowing the "destination" model for a note, and on having valid data for each field in a specific model — so you can't just throw data at Anki and let it figure out the model, you have to know the right destination model before making the API call. Yes, I could do some kind of fuzzy search for the existing model in Anki that most closely matches the fields extracted from the Markdown note, or create / modify models in Anki to match the Markdown on the fly, but this adds complexity and risk that I don't want to deal with.

The "one note type to rule them all" approach you describe where Yanki just fills in fields in a single mega-model could theoretically work, but as you point out this would be messy and push a bunch of logic into the card templates — but this would break semantics when browsing notes in Anki, and I think it would limit the ability for other note types like clozes and type-in-the-blank which require different card template markup. (Though maybe there are clever ways around this with conditionals in the card templates...)

Maintaining a single point of truth

Another goal of the project is to "just work" out of the box and to concentrate as much "truth" as possible in Markdown instead of Anki. The scenarios you've outlined would require elaborate Anki models to be created (presumably by hand or by other Anki plugins instead of by Yanki), and for the the user to maintain perfect sync between the model in one place and their Markdown in another. Power users can handle this, but it would make the out-of-the-box experience of using Yanki (which is designed for simplicity) much more fraught.

Explicit vs. implicit destination model specification

When designing Yanki I was definitely tempted to have users define the target model explicitly by name in the Markdown frontmatter, but this creates work for the user, and introduces model migration and note validation risks. One advantage of Yanki's current design is that there's no such things as an "invalid" note that can't somehow be synced to Anki. (It might not do exactly what you want / expect, but you'll always get some kind of Anki note!) This way, users doesn't have to deal with the partial synchronization state that would result from notes that fail to validate against an explicitly defined model.

Using the file paths / deck names as a way to explicitly define the destination model for a group of notes faces the same validation issues described above, in addition to leaking implementation metadata into "content" space in a way that I want to avoid. (Personally, I also often mix note types in a single folder.)

Inferring fields from Markdown

I think you should use syntax the same as other obsidian plugins, most likely using dataview metadata

(etc.)

Legibility in Obsidian and other Markdown tools

One goal of Yanki is to use Markdown in a way that the HTML-rendered Markdown still "looks" like a notecard in Obsidian or elsewhere, and is still useful to review and study even outside the context of an Anki deck. This means aligning the style of the Markdown syntax with the semantic intent in the Anki context... that's why elements like --- are used to divide the front / back of a note, and strike throughs are used for clozes — because the rendered Markdown looks at least something like what it means in Anki.

Legibility also requires keeping as much "content" data out of the frontmatter as possible. From both a philosophical and visual standpoint, I want to use frontmatter for metadata, and the rest of the note for the actual content. Pushing content up into the frontmatter makes it less legible in Obsidian, and can make it completely invisible in some other rendered-Markdown contexts that don't know what to do with frontmatter.

Moving this metadata inline with syntax like (Country:: Saint Lucia) is convenient and I think cleaner than frontmatter, but it's not parsed as anything beyond plain text by Markdown, so it won't render with any visual differentiation in Obsidian (without additional plugins), and it adds additional complexity since it won't end up in the Markdown AST without extending the parser. (Yanki already implements some custom parsing on top of the CommonMark standard to do things like custom cloze numbering, but I don't love this — it's brittle and creates maintenance liabilities.)

Avoiding inter-plugin dependencies

I use Dataview myself, and I agree that it would be useful for including dynamic data — but I don't want Yanki to depend on other Obsidian-specific plugins for core functionality. At one point I looked into the feasibility of rendering Dataview markup separately from Obsidian, with the hope of building support into Yanki such that the Dataview is rendered out right before syncing to Anki, but couldn't find a clean way to get this working on arbitrary Markdown files outside of Obsidian. (This possibility came up in the Dataview issues a while ago, without resolution.)

Where possible, I'm happy to have Yanki "get along" with other plugins if present (like it does with Folder Notes and Markdown Furigana), but this is different from requiring other plugins for core functionality. (Incidentally, Obsidian's plugin APIs don't provide a standard way to define / enforce inter-plugin dependencies.)

Portability beyond Obsidian

The Yanki Obsidian plugin is just an extension of the underlying CLI-based and Obsidian-agnostic Yanki project, so I'm trying to avoid anything that ties Yanki to Obsidian in a way that can't also be supported on stand-alone Markdown files — Obsidian-specific things like Dataview contradict this objective. (This objective is discussed a bit further in the readme.)


Sorry if I missed some of the finer nuances in your examples, but I hope the above helps illuminate some of the reasoning behind Yanki's current design!

Regarding the original issue in this thread specifically, I'd still like to implement some kind of 3+ basic / reversed support at some point, but don't have enough time in the near-term to promise a delivery date.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants