This is a good topic, actually, for bilingual users who are accustomed to add titles and carry out searches in English.
As you can run Javascript in Templater templates, implementing this is definitely feasible (even though LLMās are more often used with Python).
The script would create the alias in native language if the title is in English and in English if the title is in native or any other language.
There would be a CONFIG setting on top where users would add
native_language: something;
ātrueā or āfalseā if they wanted conjugations, declinations etc. to go into aliases as wellā¦
ā¦so Cat ā cats, go ā goes, going, went, gone, and the same in native languages.
But this can become rather unrulyā¦having 10-12 aliases would be too much IMO.
Two scripts would be needed:
Online model implementation
Offline (local) model implementation
Would need voting for good multi language models first for this to work fast and reliably on any low-end PCās as well.
I would definitely be interested in hacking together (with claude.ai) the online version, when I have the time. As I seem to have various bits of code I could mash together to make this work in Templater js.
But if I was to do it, it will be a sample template ā I mean everyone has different needs ā where they move their note on creation, etc.
So note to self: tp.user scripts needed for any kind of template.
Okay, I looked into it last night.
It was working almost straight away.
But there are caveats.
I tried to have a different method created but never could spare post-processing replacements.
The caveat is that if there is another tp.user script oneās template calls and that other one is using Obsidian APIās processFrontmatter function then one needs to clean up the aliases list.
The current implementation does a simple insertion of AI generated list below the aliases frontmatter key. ā As I said, I didnāt like this and wanted to pursue a āget AI to generate strings without dashes we put in an array and we push thatā solution but lost my patience with it.
So what I did was tweak my more elaborate template with post-processing replacements, which I know is not a good programming solutionā¦
So when I said we need a solution that works for everyone with any template sounded doable but if users have different templates with different creation mechanisms, then they would run into problems anyway. So I reverted to the original method in the end. (Simple reason: I made it work for all my templates.)
So I am offering this original method thatāll work in normal Templater scripts that donāt call other scripts with their own logic of frontmatter value merges:
Save this script as getAliases.js and place it in the user scripts folder of your choice (of Templater):
Templater will automatically see it, but there is a refresh button you can press as well if you had your Obsidian open when you added the script in your file explorer.
There are options at the top of the script you can modify:
// FILE: getAliases.js
// This script should be placed in Templater's User scripts directory
// and can be called with 'tp.user.getAliases(title)' from Templater
// CONFIG - Modify these settings as needed
const CONFIG = {
native_language: "German", // Change to your preferred language
INFLECT: false, // Set to false if you don't want inflections
include_original: true, // Whether to include original title as alias
model1: "gemini-2.0-flash-thinking-exp",
model2: "gemini-2.0-flash",
API_key: "YOUR_KEY_HERE",
max_retries: 2 // Maximum number of retry attempts
};
async function getAliases(title, tp) {
try {
// If no title provided, get it from tp.file.title
if (!title && tp?.file?.title) {
title = tp.file.title;
}
const prompt = createPrompt(title);
const aliases = await communicateWithGemini(prompt);
return formatAliases(aliases, title);
} catch (error) {
console.error("Error generating aliases:", error);
return " - ERROR: Could not generate aliases";
}
}
function createPrompt(title) {
// Check if the title contains spaces
const isSingleWord = !title.includes(' ');
return `Generate aliases for "${title}" with these rules:
1. If "${title}" is in English, provide translations in ${CONFIG.native_language}.
2. If "${title}" is in ${CONFIG.native_language} or any other language, provide English translations.
3. Include inflections: ${isSingleWord && CONFIG.INFLECT ? "yes" : "no"}.
4. Format as a simple list with each alias on a new line prefixed with a dash (-).
5. For multiple word phrases, include variations with each significant word.
6. Include singulars and plurals where applicable.
7. Include common synonyms in both languages.
8. Include a maximum of 6 most relevant aliases.
9. DO NOT include variations on names of people but if they are well-known, you can add 'Aristotle, the Greek philosopher', or similar handles
10. DO NOT include any extra formatting, backticks, code blocks or yaml tags in your response.`;
}
async function communicateWithGemini(message) {
let lastError = null;
const models = [CONFIG.model1, CONFIG.model2];
for (const model of models) {
for (let attempt = 0; attempt < CONFIG.max_retries; attempt++) {
try {
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-goog-api-key': CONFIG.API_key
},
body: JSON.stringify({
contents: [{
role: 'user',
parts: [{ text: message }]
}],
generationConfig: {
temperature: 0.1,
maxOutputTokens: 2048,
topP: 1
}
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.candidates && data.candidates.length > 0) {
return data.candidates[0].content.parts[0].text;
}
throw new Error('No valid response from the API');
} catch (error) {
lastError = error;
if (attempt < CONFIG.max_retries - 1) {
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));
continue;
}
}
}
}
throw lastError || new Error('Failed to get response from all models');
}
function formatAliases(response, title) {
// Clean up the response
let cleanedResponse = response.trim();
// Remove various markdown and YAML markers
cleanedResponse = cleanedResponse.replace(/^```(?:yaml|)\s*|\s*```$/gm, '');
cleanedResponse = cleanedResponse.replace(/^aliases:\s*$/im, '');
// Process each line
const lines = cleanedResponse.split('\n')
.map(line => line.trim())
.filter(line => line) // Remove empty lines
.map(line => {
// Remove any existing dashes and spaces
line = line.replace(/^[-\s]+/, '').trim();
return ` - ${line}`;
});
// Add original title as an alias if configured
if (CONFIG.include_original && title) {
if (!lines.includes(` - ${title}`)) {
lines.unshift(` - ${title}`);
}
// Add first-char lowercase version if different
const firstCharLowerCase = title.charAt(0).toLowerCase() + title.slice(1);
if (firstCharLowerCase !== title && !lines.includes(` - ${firstCharLowerCase}`)) {
lines.push(` - ${firstCharLowerCase}`);
}
}
return lines.join('\n');
}
module.exports = getAliases;
If the title is a single word, then it will add inflections, but since we have Include a maximum of 6 most relevant aliases in the prompt and also ask for synonyms, they are likely drowned out. You can increase 6 if you want. The inflections can be turned off or the system prompt rewritten to have custom results. Feel free to experiment.
Inflections I wanted to add because I remember Feature Requests regarding this in the past.
I always want the original title and its lowercase version added as well. There is a setting for that too.
We are using free Gemini, for which you can get API keys from Google. Check how here:
In the template you are using (it means every template you want to use AI generated aliases in) you need to add the script caller below the aliases key line:
If you had let title = tp.file.title; in your script, simple title is enough in the brackets.
I am only mentioning this because there may be cases when tp.file.title will give (partly) wrong results, if one uses a tp.user script that cleans titles for example (like mine).
The models can be also changed in an effort to make the process slightly faster. So gemini-2.0-flash-thinking-exp could be used as model2, but named gemini-2.0-pro or some other model that is efficient enough but faster. (The current note generation takes something like 3 seconds.)
I cannot experiment enough with this now to suit everyoneās needs.
Works on mobile as well!
The script can be enhanced:
Using the other way, where we push values and merge into frontmatter with Obs. API
Checks for internet connection and if none found, uses some local LLM (but youād need to load the model manually with Ollama or LM Studio before).
You are sent from heaven, Yurcee!! I canāt thank you enough! Itās just wonderful that youāve not only found a solution for this, but have also written instructions for implementing it and made sure that everyone understands it, no matter what skill level they come from.
More and more I realize how Obsidian as a platform brings to light secondary educational effects: For, this software does not provide solutions for particularly special interests, and accordingly the audience is just as diverse as one would imagine when thinking of the group of people who take notes. And because the community manages to make itself visible as a relevant factor for the use of Obsidian, contacts between the users and such a learning field as āprogrammingā build up very organically and with a low threshold!
Thank you very much for your efforts, Yurcee! And for allowing me to learn from you how to take my first productive step in AI and LLMs as a layman! Iām very grateful for this community
My experience ā as another layman ā is that you need ideas (a target to achieved), the implementation (whether from forum posts and now AI that can generate code), and then from one script, using that as a sample, you can have more created, and over time some of this programming will become somehow familiarā¦even for non-coders.
So in this case the script above can be tweaked to be used in the same template calling another user script in which AI would also write a summary (of oneās own language) of the newly created noteās title as topic. You donāt necessarily want to keep that (and I firmly belive that Obsidian notes should be personal notes, from personal experience and I donāt want to endorse AI generated note content as such), but before writing your own lines, these generated lines can be used for perspective or mood-setter, etc.
They can be used as a web searcherā¦new note with some title ā get response, you may even delete the note. Yes, generally Google browser is better, as you get up-to-date information. But in other cases youād need to do more than just browse and get what you want from the first page of Google (Bing, etc.) results.
And then, this can be taken furtherā¦generate a list of topics in txt file, then with a Python script go through the topics line by line and open the lines as files in your vault (there are some CLI utilities), where they would be automatically created, with AI summaries, etc.
Creation starts with the idea first. Idea can be 10 or 90 percent of the job done. Depending on how well prepared you are for the implementation (tweaking, if you do this the 2nd, 3rd time). And with the expertise garnered in the second phase, more ideas can pop up, waiting for implementation.
Obsidian with its 3rd party plugins is a great tool for this. I cannot think there is another ecosystem that can currently surpass it (for customization functionality).