Skip to main content

Anki và Obsidian

1)Truy cập Huggingface tạo tài khoản và lấy key API paste key vào templater 2)Vào "File and link" enable "Automatically update internal links" 3)Tạo folder "assets" attachment và set folder attachment 4)Tạo folder template và set folder template 5)Cài đặt plugin "templater" 6)Tạo template để tra cứu từ vựng đồng thời thiết lập shortcut để thuận tiện cho việc tra cứu 7)## Thiết lập kết nối giữa Obsidian và Anki

  • Cài đặt Obsidian_to_Anki
  • Thiết lập AnkiConnect (mã addon: 2055492159)
  • Tạo note type phù hợp với các field tương ứng trên template

Templater

// Nhập API key
const api_key = ""
// Nhập folder attachment
const attachment_folder = "Assets"
// Nhập deck Anki để thêm từ vựng
const deck = `English`

const fs = require('node:fs')


const model_audio = "https://api-inference.huggingface.co/models/espnet/kan-bayashi_ljspeech_vits"

const line = removeLinks(tp.file.content.split("\n")[this.app.workspace.activeEditor?.editor.getCursor().line])
.replace("- ","").trim()

const select = this.app.workspace.activeEditor?.editor.getSelection()
this.app.workspace.activeEditor?.editor?.replaceSelection(`[[▲ ${select}|` + select + `]]`)

// tra nghĩa của từ trong ngữ cảnh
const definition = await lookup(`
Sentence: ${line}
Word/ Phrase: ${select}
`
, "Definition")

// Sau khi có được nghĩa của từ thì yêu cầu model dịch sang Tiếng Việt.
// Khả khăng xử lí ngôn ngữ Tiếng Việt còn nhiều hạn chế, nên có thể xóa function phí dưới để tăng tốc độ tra cứu.

const definition_vn = await lookup(`
English: ${definition}
`
, "Translate into Vietnamese")

// Yêu cầu model đặt câu ví dụ với nghĩa nhất định của từ
const example = await lookup(`
Word/ Phrase: ${select}
Definition: ${definition}
`
, "Example")


// Dịch example tiếng Anh sang tiếng Việt.

const example_vn = await lookup(`
English: ${example}
`
, "Translate into Vietnamese")


// Yêu cầu model tra cứu IPA của từ (không phải lúc nào cũng chính xác)
const ipa = await lookup(`
Word/ Phrase: ${select}
`
, "IPA")



// Nội dung file trả về sau khi tra cứu xong, người dùng nên tùy chỉnh theo nhu cầu của bản thân
// Cú pháp:
// [Anki Field]: ${biến}
// (await textToSpeech(text)) function này sẽ chuyển văn bản thành giọng nói (chỉ hỗ trợ tiếng Anh)

let template = `
English Vocab
Word: ${select}
Definition:
${definition}
Vn:
${definition_vn}
IPA:
${ipa}
Example:
${example}
${example_vn}
Audio:
${(await textToSpeech(select))}
Audio Example:
${(await textToSpeech(example))}

`

template = template + `TARGET DECK: ${deck}\n` + "END\n"
template = "START" + template



let file = this.app.vault.getMarkdownFiles()
.filter(f => f.path.replace(".md","") == `${select}`)
if (file.length !== 0) {
this.app.vault.append(file[0], template)
} else {
const newNote = await app.vault.create(`${select}.md`, template);
}


async function lookup(context, q) {
let prompt = context + `\n${q}:\n>`
let res = await query({"inputs": prompt})
if (res) {
let reg = new RegExp(`${q}:\n>(.*?)\n`,"g")
let r = `${res[0]["generated_text"]}\n`.match(reg)
if (r) return r[0].replace(/\n/g,"").replace(/(.*?)\>/g,"").replace("-","").trim()
}
}

async function query(data) {
const response = await fetch(
"https://api-inference.huggingface.co/models/NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
{
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + api_key
},
method: "POST",
body: JSON.stringify(data),
}
);
const result = await response.json();
return result;
}

function removeLinks(text) {
let links = text.match(/\[\[(.*?)\]\]/g) ? text.match(/\[\[(.*?)\]\]/g) : []
let webs = text.match(/\[(.*?)\]\((.*?)\)/g) ?
text.match(/\[(.*?)\]\((.*?)\)/g) : []
for (let link of links) {
let x = link.replace(/\[\[(.*?)\|/g,"").replace("]]","").replace("[[","")
text = text.replace(link, x)
}
for (let web of webs) {
let x = web.replace(/\](.*?)\)/g,"").replace("\[","")
text = text.replace(web, x)
}
return text
}

async function textToSpeech(text) {
let id = Date.now() + text.length
query({"inputs": text}).then(async (response) => {
let content = Buffer.from((await response.arrayBuffer()))
let path = `${this.app.vault.adapter.getBasePath()}/${attachment_folder}/${id}.flac`
fs.writeFile(path, content, err => {
if (err) {
console.error(err);
}});
});
return `![[${attachment_folder}/${id}.flac]]`

async function query(data) {
const response = await fetch(
model_audio,
{
headers: { Authorization: "Bearer " + api_key },
method: "POST",
body: JSON.stringify(data),
}
);
const result = await response.blob();
return result;
}
}