Dynamic Learning Platform

tl;dr: AI-native learning platform for acquiring languages dynamically

Why?

Current language learning tools are still mostly software 1.0, or not very user-friendly for the masses

What?

  • Pages (can be opened by clicking small ribbon items on the left side; like in vs code or obsidian):
    • Chat (main tab)
    • Knowledge

Chat (main page)

The chat tab is a basic AI-Chat that offers all the features you would expect

Special features:

  • two modes: normal and โ€œknowledgeโ€ mode

Knowledge mode:

  • when enabled, the chat will automatically interact with the knowledge base to:
    • enrich answers with additional information from the knowledge base
    • automatically (or ask the user) update the knowledge base with information from the chat
Example (explain):

Prompt: โ€œexplain โ€˜ไปŠๆ—ฅใ€ๅคงๅญฆใซ่กŒใฃใŸใ€‚โ€˜โ€ Response:

**TL;DR:**  
The sentence _ไปŠๆ—ฅใ€ๅคงๅญฆใซ่กŒใฃใŸ_ means **"I went to university today."**

**Knowledge:**

- **[[ไปŠๆ—ฅ๏ผˆใใ‚‡ใ†๏ผ‰]]** = today
    
- **[[ๅคงๅญฆ๏ผˆใ ใ„ใŒใ๏ผ‰]]** = university
    
- **[[ใซ]]** = particle indicating direction or destination ("to")
    
- **[[่กŒใฃใŸ๏ผˆใ„ใฃใŸ๏ผ‰]]** = past tense of _่กŒใ๏ผˆใ„ใ๏ผ‰_, meaning "to go"

Note: [[]] marks a knowledge here; in the real response it should probably be some html element that contains all the information required to either retrieve the info of it or create it

Furthermore, the response allows the following actions:

  • you can click on words or grammar points (automatically highlighted and recognized as such) to save them in your knowledge base (or if they already exist, you open them up)
Example (write):

Prompt: โ€œhow to say โ€˜I went to university todayโ€™?โ€ Response:

**TL;DR** โ€“ The natural way to say โ€œI went to university todayโ€ in Japanese is:

> **ไปŠๆ—ฅใฏๅคงๅญฆใซ่กŒใใพใ—ใŸใ€‚**
> *Kyล wa daigaku ni ikimashita.*

Below is a quick breakdown in โ€œTranslateโ€ format.

**Full Translation**

| ๆ–‡                | ่ชญใฟ                 | ๆ„ๅ‘ณ                          |
| ---------------- | ------------------ | --------------------------- |
| **ไปŠๆ—ฅใฏๅคงๅญฆใซ่กŒใใพใ—ใŸใ€‚** | ใใ‚‡ใ† ใฏ ใ ใ„ใŒใ ใซ ใ„ใใพใ—ใŸ | I went to university today. |


**Knowledge**

| ่ฆ็ด         | ่ชฌๆ˜Ž                                                                                                                                                                |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[[ไปŠๆ—ฅใฏ]]**   | Sets โ€œtodayโ€ (ใใ‚‡ใ†) as the topic with **ใฏ**. It frames the sentence as โ€œAs for todayโ€ฆโ€.                                                                            |
| **[[ๅคงๅญฆ]]**    | โ€œUniversity.โ€                                                                                                                                                     |
| **[[ใซ]]**     | Target/destination particle. You can also use **ใธ** (e.g. ไปŠๆ—ฅใฏๅคงๅญฆใธ่กŒใใพใ—ใŸ) โ€“ nuance difference is tiny; **ใซ** feels a bit more factual, **ใธ** a bit more directional. |
| **[[่กŒใใพใ—ใŸ]]** | Past-polite form of ่กŒใ *iku* โ€œto go.โ€<br>- Dictionary: ่กŒใ<br>- Stem: ่กŒใ<br>- +ใพใ—ใŸ (polite past)                                                                   |

The answer is generated preferably on grammar/words the user already knows); Furthermore it may also suggest better solution if appropriate. All these knowledge items are also clickable like in the first example.

Knowledge Page

A table, containing all list of all knowledge types as spoiler items (title = type)

when expanding a spoiler, it shows a table with all the knowledge items of that type (one col per property)

For now, the knowledge page is readonly.

How?

Data Schema

Knowledge is stored in a table with fields:

  • id
  • type (= user defined enum)
  • content (jsonb, which fits schema of the knowledge type)

knowledge types (user defined)

  • id
  • name
  • description (what it is in natural language)
  • definition (json schema definition)
    • e.g. โ€œjapanese grammarโ€, { grammar: { type: string, description: 'the grammatical concept in japanese' }, example: { type: string, description: 'an example application of the grammatical concept' }, explanation: { type: string, description: 'explanation of how to use the grammatical concept'} }

chats & messages are also stored in separate tables

Embeddings

Knowledge (from knowledge table) can also be queried in natural language (use postgres embeddings directly on the table or alternatively another vector db with embeddings)

How updating knowledge works

When โ€œknowledge modeโ€ is enabled (and works as explained in the examples), the chat has access to new tools provided by an (internal) mcp server; it exposes:

  • getKnowledgeTypes -> returns all knowledge types + their descriptions
    • using this information, the agent can then decide whether to look up knowledge
  • getKnowledge(queries[])
    • query:
      • searchTerm: natural language search
      • knowledgeType?: optional knowledge type that must match
    • -> returns all knowledge items that match (via vector search on content of knowledge items)
  • addKnowledge(knowledge[])
    • function to add new knowledge items

Furthermore, the system prompt is adjusted to tell the agent that it should use these tools to enrich answers as e.g. described for the 2 use cases before (however, keep it generalized)

General Architecture

  • postgres DB by supabase (+ auth etc)
  • backend: typescript server (nextjs?!)
    • uses supabase types
    • supabase is configured as far as possible via code
      • migrations are declaratively managed in the repo as well
  • frontend: typescript react app
    • shadcn components
    • state management via zustand