I built Endless Academy because I was frustrated by not having the right vocabulary to search Google/ask ChatGPT when learning new topics.<p>Endless (<a href="https://www.endless.academy" rel="nofollow noreferrer">https://www.endless.academy</a>) will build a course for you, on any topic. You can customize what's taught and the teaching style. It's an efficient way to learn something enough to start using it.<p>There are a LOT of projects like this. Endless is different in important ways:<p><pre><code> - It's block-based, like Notion. You can use this to customize the teaching style, by adding video, exercise, or other blocks.
- Courses are dynamic. You can add new blocks to an existing course, and even edit the course.
- AI chat blocks let you get help. I think chat should be integrated into the flow of the course, not separated into a different window. This lets you have multiple chats going, and preserve the context in each one.
- Steer how the AI develops the course by editing the outline.
</code></pre>
Endless works by leveraging multiple AI models:<p><pre><code> - Endless looks up information from high-quality educational resources (you can see the sources)
- It uses that information to prompt an LLM to write the learning blocks
- If necessary, it uses other models and services to post-process each block (for example, to find a video)
</code></pre>
The backend is FastAPI, and the frontend is SvelteKit. Some learnings:<p><pre><code> - I wanted the interface to feel dynamic, with information from the LLM streaming in realtime. This meant I had to rip everything apart halfway through and make the backend mostly async (a paradigm I hadn't used before).
- SvelteKit is fantastic - everything being plain Javascript/HTML makes creating components fast. I only ran into a couple of issues where the magic made it hard to understand errors. That said, there are so many off the shelf React components that overall productivity may not have been that different.
- I used TipTap for the block editor, and I mostly like it. My main issue is handling state across multiple TipTap instances interspersed with Svelte components. The "correct" way seems to be using nodeviews and a single TipTap instance, but that trades off data model flexibility (since TipTap imposes its own schema).
- I did not use Langchain/LlamaIndex/etc. In production, the need for reliability and observability meant that I just wrote my own light wrappers instead.</code></pre>