Skip to content

Commit

Permalink
feat: keep markdown formatting + add link to parent note in chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
aexshafii committed Feb 13, 2025
1 parent 80acdb2 commit dbcdd7e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 19 deletions.
71 changes: 53 additions & 18 deletions packages/plugin/views/assistant/organizer/chunks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from "react";
import { TFile } from "obsidian";
import FileOrganizer from "../../../index";
import { logger } from "../../../services/logger";
import { MarkdownRenderer } from "obsidian";

interface DocumentChunksProps {
plugin: FileOrganizer;
Expand Down Expand Up @@ -29,21 +30,65 @@ export const AtomicNotes: React.FC<DocumentChunksProps> = ({ plugin, activeFile

const createFileInSameFolder = async (title: string, chunkContent: string) => {
try {
// Get the parent folder path of the active file
const folderPath = activeFile.parent?.path || "";

// Create a sanitized filename
const sanitizedTitle = title.replace(/[\\/:*?"<>|]/g, "-");
const newFileName = `${sanitizedTitle}.md`;
const fullPath = `${folderPath}/${newFileName}`;

// Create the new file in the same folder
await plugin.app.vault.create(fullPath, chunkContent);
// Add link to parent note at the top of the content
const parentLink = `> \n\n Source: [[${activeFile.basename}]]`;
const contentWithLink = chunkContent + parentLink;

// Create the new file with the markdown content
await plugin.app.vault.create(fullPath, contentWithLink);
} catch (error) {
logger.error("Error creating file in folder:", error);
}
};

// Render markdown content
const renderMarkdown = React.useCallback(async (content: string, containerEl: HTMLElement) => {
if (!content) return;

try {
await MarkdownRenderer.renderMarkdown(
content,
containerEl,
activeFile.path,
plugin
);
} catch (error) {
logger.error("Error rendering markdown:", error);
containerEl.textContent = content; // Fallback to plain text
}
}, [activeFile, plugin]);

// Use effect to render markdown after component updates
React.useEffect(() => {
const containers = document.querySelectorAll('.chunk-markdown-content');
containers.forEach((container) => {
const content = container.getAttribute('data-content');
if (content) {
renderMarkdown(content, container as HTMLElement);
}
});
}, [chunks, renderMarkdown]);

const renderChunk = (chunk: { concept: string; content: string }, index: number) => (
<div key={index} className="chunk-container p-4 border rounded-md mb-2">
<div
className="chunk-markdown-content mb-3"
data-content={chunk.content}
/>
<button
className="bg-accent text-accent-foreground px-2 py-1"
onClick={() => createFileInSameFolder(chunk.concept, chunk.content)}
>
Create Note
</button>
</div>
);

return (
<div className="document-chunks">
<button
Expand All @@ -54,21 +99,11 @@ export const AtomicNotes: React.FC<DocumentChunksProps> = ({ plugin, activeFile
{loading ? "Parsing..." : "Parse Document"}
</button>
{concepts.map((concept, index) => (
<div key={index}>
<h4>{concept}</h4>
<div key={index} className="mb-4">
<h4 className="text-lg font-medium mb-2">{concept}</h4>
{chunks
.filter(chunk => chunk.concept === concept)
.map((chunk, chunkIndex) => (
<div key={chunkIndex} className="chunk-container">
<p>{chunk.content}</p>
<button
className="bg-accent text-accent-foreground px-2 py-1"
onClick={() => createFileInSameFolder(concept, chunk.content)}
>
Create Note
</button>
</div>
))}
.map((chunk, chunkIndex) => renderChunk(chunk, `${index}-${chunkIndex}`))}
</div>
))}
</div>
Expand Down
11 changes: 10 additions & 1 deletion packages/plugin/views/assistant/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AppContext } from "./provider";
import AIChatSidebar from "./ai-chat/container";
import { TooltipProvider } from "@radix-ui/react-tooltip";
import { Meetings } from "./organizer/meetings/meetings";
import ReactMarkdown from 'react-markdown';

export const ORGANIZER_VIEW_TYPE = "fo2k.assistant.sidebar2";

Expand Down Expand Up @@ -51,6 +52,14 @@ function TabContent({
};
}, [plugin.app.workspace, plugin.app.vault]);

function renderNoteContent(content: string) {
return (
<div className="markdown-preview">
<ReactMarkdown>{content}</ReactMarkdown>
</div>
);
}

return (
<div className="relative h-full">
<div
Expand Down Expand Up @@ -88,7 +97,7 @@ function TabContent({
<Meetings
plugin={plugin}
file={activeFile}
content={noteContent}
content={renderNoteContent(noteContent)}
refreshKey={refreshKey}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions packages/web/app/api/(newai)/concepts-and-chunks/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ async function identifyConceptsAndChunks(content: string, model: LanguageModel)
1. Identify the key concepts in the document.
2. For each concept, extract the most relevant chunk of information.
3. Return a list of concepts, each with its name and associated chunk of information.
4. Preserve all markdown formatting in the extracted chunks.
Aim to split the document into the fewest atomic chunks possible while capturing all key concepts.`,
});
Expand Down

0 comments on commit dbcdd7e

Please sign in to comment.