[Plugin] AI Title Generator #7123
129s
started this conversation in
Show and tell
Replies: 1 comment
-
|
Great plugin! I noticed that when switching between multiple tabs, duplicate buttons occasionally appear. I've fixed this bug, and here's my patched version. class TitleEnhancerWidget extends api.NoteContextAwareWidget {
get parentWidget() { return 'note-detail-pane'; }
get position() { return 100; }
constructor() {
super();
this.settingsPromise = null;
this.isLoading = false;
this.buttonId = 'title-enhancer-btn-' + api.randomString(6);
this.buttonClass = 'title-enhancer-btn';
}
getSettings() {
if (this.settingsPromise) return this.settingsPromise;
this.settingsPromise = (async () => {
const selfNote = await api.searchForNote('#titleEnhancerScript');
if (!selfNote) {
console.log("Title Enhancer script note with #titleEnhancerScript label not found!");
return null;
}
const apiUrl = selfNote.getLabelValue('baseUrl');
const apiKey = selfNote.getLabelValue('apiKey');
const model = selfNote.getLabelValue('modelName');
if (!apiUrl || !apiKey || !model) {
console.log("Please configure baseUrl, apiKey, and modelName attributes on the TitleEnhancer script note.");
return null;
}
return { apiUrl, apiKey, model };
})();
return this.settingsPromise;
}
doRender() {
if (!document.getElementById('title-enhancer-styles')) {
const styles = `
@keyframes spin-fast-animation {
0% { transform: rotate(0deg); }
100% { transform: rotate(720deg); }
}
.spin-fast {
animation: spin-fast-animation 0.5s linear infinite;
}
.loading-style {
border-radius: 50% !important;
}
.input-loading-bar {
position: relative;
overflow: hidden;
}
.input-loading-bar::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 2px;
width: 100%;
background-color: var(--main-text-color, #FFFFFF);
animation: loading-bar-animation 1.0s linear infinite;
}
@keyframes loading-bar-animation {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
`;
const styleSheet = document.createElement("style");
styleSheet.id = 'title-enhancer-styles';
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
}
this.$widget = $('<div class="title-enhancer-placeholder" style="display: none;"></div>');
return this.$widget;
}
async refreshWithNote(note) {
$('.' + this.buttonClass).remove();
$('#' + this.buttonId).remove();
const isApplicable = ['text', 'code', 'markdown'].includes(note.type) && !note.isProtected;
if (isApplicable) {
const $spacer = $('.title-row > .spacer');
if ($spacer.length > 0) {
this.$button = $(`<button id="${this.buttonId}" class="${this.buttonClass} button-widget bx component icon-action bxs-magic-wand" title="Enhance Title with AI"></button>`);
this.$button.on('click', () => this.enhanceTitle());
$spacer.after(this.$button);
}
}
}
onunload() {
$('.' + this.buttonClass).remove();
$('#' + this.buttonId).remove();
}
setLoadingState(isLoading) {
this.isLoading = isLoading;
if (!this.$button) return;
const $titleContainer = $('.note-title-widget');
if (isLoading) {
this.$button
.removeClass('bxs-magic-wand')
.addClass('bx-loader-alt spin-fast loading-style')
.prop('disabled', true);
$titleContainer.addClass('input-loading-bar');
} else {
this.$button
.removeClass('bx-loader-alt spin-fast loading-style')
.addClass('bxs-magic-wand')
.prop('disabled', false);
$titleContainer.removeClass('input-loading-bar');
}
}
async enhanceTitle() {
if (this.isLoading) return;
this.setLoadingState(true);
void this.$button[0].offsetHeight;
const settings = await this.getSettings();
if (!settings) {
this.setLoadingState(false);
return;
}
const note = this.note;
try {
const content = await note.getContent();
if (!content || content.trim().length < 50) {
console.log("Note content is too short to generate a meaningful title.");
this.setLoadingState(false);
return;
}
const backendApiCall = async (settings, content) => {
const { apiUrl, apiKey, model } = settings;
const seed = Math.random();
const payload = {
model: model,
messages: [
{ role: "system", content: "You are an expert at writing concise, creative and engaging titles for notes based on their content. The title should be short and not enclosed in quotation marks." },
{ role: "user", content: `#${seed}\n${content}` }
],
temperature: 1,
top_p: 0.7,
max_tokens: 28,
stream: false
};
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
body: JSON.stringify(payload)
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API request failed with status ${response.status}: ${errorText}`);
}
const data = await response.json();
const newTitle = data.choices[0]?.message?.content?.trim().replace(/^"|"$/g, '');
if (!newTitle) {
throw new Error("API response did not contain a valid title.");
}
return newTitle;
};
const newTitle = await api.runAsyncOnBackendWithManualTransactionHandling(
backendApiCall,
[settings, content]
);
await api.runOnBackend((noteId, title) => {
const note = api.getNote(noteId);
if (note) {
note.title = title;
note.save()
}
}, [note.noteId, newTitle]);
} catch (e) {
console.log(`TitleEnhancer Error: ${e.message}`);
} finally {
this.setLoadingState(false);
}
}
}
if (!window.titleEnhancerInstance) {
window.titleEnhancerInstance = new TitleEnhancerWidget();
}
module.exports = window.titleEnhancerInstance; |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Features:
How to use:
Beta Was this translation helpful? Give feedback.
All reactions