lesson 23 LLM sentence explainer

This commit is contained in:
polv committed 2026-08-25 14:29:00 +07:00
1 parent 075fe19382
commit e734d09039
10 files changed
+744 -25

No files matched your search

@@ -66,6 +66,15 @@
</div>
<div v-else v-html="v.notes"></div>
</blockquote>
<div v-if="example">
<blockquote
v-if="exNotes"
v-html="markdownIt.render(exNotes)"
></blockquote>
<button type="button" v-else @click="explainSentence(example.ko)">
Explain sentence
</button>
</div>
</details>
</nav>
<details :class="$style.options">
@@ -125,6 +134,8 @@ import yaml from "yaml";
import SentenceAudio from "./SentenceAudio.vue";
import { supabase } from "../supabase.ts";
import { IVoc, Voc } from "../types.ts";
import { LLMstream } from "../llm.ts";
import MarkdownIt from "markdown-it";
const { fmKey = "vocabulary", category } = defineProps<{
fmKey?: string;
@@ -140,6 +151,8 @@ const exIndex = ref(0);
const isEdit = ref(false);
const vEditContent = ref("");
const exNotes = ref("");
const quizState = reactive({
vChosenCats: [] as string[],
isAutoplayAudio: true,
@@ -275,6 +288,8 @@ function makeNewExIndex() {
}
function mark(isRight: boolean) {
exNotes.value = "";
nextTick(() => {
if (sentenceDetails.value) {
sentenceDetails.value.open = false;
@@ -378,6 +393,32 @@ async function onVContentSave() {
isEdit.value = false;
}
const markdownIt = new MarkdownIt({
html: false,
breaks: true,
linkify: true,
typographer: true,
});
async function explainSentence(s: string) {
for await (const data of LLMstream({
model: "deepseek-v4-flash",
messages: [
{
role: "system",
content:
"Explain how this sentence works in 500 characters. Give key vocabularies.",
},
{ role: "user", content: s },
],
})) {
if (data.done) return;
if (data.content) {
exNotes.value += data.content;
}
}
}
function onModalClickOutside(ev: MouseEvent) {
if (!(ev.target instanceof HTMLElement)) return;
if (ev.target.matches('[name="edit"]')) return;