Skip to content

Commit ed5b71d

Browse files
committed
Better support for reasoning models, subdivision of tasks supports nesting and ignores empty lines, typo fix
1 parent 4df156d commit ed5b71d

File tree

1 file changed

+98
-19
lines changed

1 file changed

+98
-19
lines changed

src/ollama.tsx

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,21 @@ async function promptLLM(prompt: string) {
119119
prompt: prompt,
120120
stream: false,
121121
}),
122-
})
122+
});
123123
if (!response.ok) {
124-
logseq.App.showMsg("Coudln't fulfill request make sure that ollama service is running and make sure there is no typo in host or model name")
125-
throw new Error("Error in Ollama request: " + response.statusText)
124+
logseq.App.showMsg("Couldn't fulfill request. Make sure Ollama service is running and there are no typos in host or model name.");
125+
throw new Error("Error in Ollama request: " + response.statusText);
126126
}
127+
127128
const data = await response.json();
128129

129-
return data.response;
130+
// Remove any <think>…</think> blocks in the response
131+
const filteredResponse = data.response.replace(/<think>[\s\S]*?<\/think>/g, '');
132+
133+
return filteredResponse;
130134
} catch (e: any) {
131-
console.error("ERROR: ", e)
132-
logseq.App.showMsg("Coudln't fulfill request make sure that ollama service is running and make sure there is no typo in host or model name")
135+
console.error("ERROR: ", e);
136+
logseq.App.showMsg("Couldn't fulfill request. Make sure Ollama service is running and there are no typos in host or model name.");
133137
}
134138
}
135139

@@ -277,8 +281,8 @@ export async function askAI(prompt: string, context: string) {
277281

278282
export async function convertToFlashCard(uuid: string, blockContent: string) {
279283
try {
280-
const questionBlock = await logseq.Editor.insertBlock(uuid, "⌛Genearting question....", { before: false })
281-
const answerBlock = await logseq.Editor.insertBlock(questionBlock!.uuid, "⌛Genearting answer....", { before: false })
284+
const questionBlock = await logseq.Editor.insertBlock(uuid, "⌛Generating question....", { before: false })
285+
const answerBlock = await logseq.Editor.insertBlock(questionBlock!.uuid, "⌛Generating answer....", { before: false })
282286
const question = await promptLLM(`Create a question for a flashcard. Provide the question only. Here is the knowledge to check:\n ${blockContent}`)
283287
const answer = await promptLLM(`Given the question ${question} and the context of ${blockContent} What is the answer? be as brief as possible and provide the answer only.`)
284288
await logseq.Editor.updateBlock(questionBlock!.uuid, `${question} #card`)
@@ -302,20 +306,95 @@ export async function convertToFlashCardCurrentBlock() {
302306

303307
export async function DivideTaskIntoSubTasks(uuid: string, content: string) {
304308
try {
305-
const block = await logseq.Editor.insertBlock(uuid, "✅ Genearting todos ...", { before: false })
306-
let i = 0;
307-
const response = await promptLLM(`Divide this task into subtasks with numbers: ${content} `)
308-
for (const todo of response.split("\n")) {
309-
if (i == 0) {
310-
await logseq.Editor.updateBlock(block!.uuid, `TODO ${todo.slice(3)} `)
311-
} else {
312-
await logseq.Editor.insertBlock(uuid, `TODO ${todo.slice(3)} `, { before: false })
309+
// 1) Insert initial placeholder block.
310+
const placeholderBlock = await logseq.Editor.insertBlock(
311+
uuid,
312+
"✅ Generating todos ...",
313+
{ before: false }
314+
);
315+
if (!placeholderBlock) {
316+
throw new Error("Could not insert the placeholder block.");
317+
}
318+
319+
// 2) Fetch LLM response
320+
const response = await promptLLM(
321+
`Divide this task into subtasks with numbers respond with multilevel nested markdown format, no dot notation, one subtask per line, plain text only.: ${content}`
322+
);
323+
324+
// 3) Split on newlines, ignoring empty lines
325+
const lines = response
326+
.split("\n")
327+
.map((line: string) => line.replace(/\r$/, "")) // remove trailing \r if present
328+
.filter((line: string) => line.trim().length > 0);
329+
330+
// If there's nothing, do nothing
331+
if (!lines.length) return;
332+
333+
// 4) Update the placeholder block with the very first line
334+
// preserving its entire text (no slicing or removal).
335+
// Prepend “TODO ” as in your original code structure.
336+
await logseq.Editor.updateBlock(
337+
placeholderBlock.uuid,
338+
`TODO ${lines[0]}`
339+
);
340+
341+
// If there was only one line, we’re done
342+
if (lines.length === 1) return;
343+
344+
// 5) Now set up stack-based nesting for the rest:
345+
// stack top is always the most recent block at a particular level.
346+
// We'll treat the placeholder block as level=0
347+
const stack = [{ uuid: placeholderBlock.uuid, level: 0 }];
348+
349+
// Helper: Determine indent-based nesting level.
350+
// Adjust baseIndent if your model uses different spacing for sub-levels.
351+
function getIndentLevel(line: string): number {
352+
const firstCharIndex = line.search(/\S/);
353+
// no non-whitespace => treat as top-level
354+
if (firstCharIndex < 0) {
355+
return 0;
356+
}
357+
// e.g. baseIndent=2 → each 2 leading spaces => +1 nesting level
358+
const baseIndent = 3;
359+
return Math.floor(firstCharIndex / baseIndent);
360+
}
361+
362+
// 6) Process remaining lines to handle nesting
363+
for (let i = 1; i < lines.length; i++) {
364+
const rawLine = lines[i];
365+
366+
// figure out “level” from indentation
367+
const level = getIndentLevel(rawLine);
368+
369+
// pop the stack until we find a block whose level is < current level
370+
while (stack.length > 0 && stack[stack.length - 1].level >= level) {
371+
stack.pop();
372+
}
373+
374+
// if the stack is empty (all popped), fallback to the placeholder:
375+
if (stack.length === 0) {
376+
stack.push({ uuid: placeholderBlock.uuid, level: 0 });
377+
}
378+
379+
// top of stack is the parent block where we create a child
380+
const parent = stack[stack.length - 1];
381+
382+
// Insert a child block. Trim only leading spaces from the line’s text so we keep the numbering/content
383+
const trimmedText = rawLine.replace(/^\s+/, "");
384+
const newBlock = await logseq.Editor.insertBlock(
385+
parent.uuid,
386+
`TODO ${trimmedText}`,
387+
{ sibling: false }
388+
);
389+
390+
if (newBlock) {
391+
// push newly inserted block at the correct level
392+
stack.push({ uuid: newBlock.uuid, level });
313393
}
314-
i++;
315394
}
316395
} catch (e: any) {
317-
logseq.App.showMsg(e.toString(), 'warning')
318-
console.error(e)
396+
logseq.App.showMsg(e.toString(), "warning");
397+
console.error(e);
319398
}
320399
}
321400

0 commit comments

Comments
 (0)