mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-30 21:59:46 +02:00
feat: integrate notion-markdown for markdown conversion in NotionHistoryConnector
- Added notion-markdown dependency to pyproject.toml. - Refactored _markdown_to_blocks method to utilize notion-markdown for converting markdown content to Notion blocks. - Updated create-notion-page component to replace Loader2Icon with Spinner for improved loading indication.
This commit is contained in:
parent
39ce597907
commit
0b8bee0076
4 changed files with 4254 additions and 4313 deletions
|
|
@ -6,6 +6,7 @@ from collections.abc import Awaitable, Callable
|
||||||
from typing import Any, TypeVar
|
from typing import Any, TypeVar
|
||||||
|
|
||||||
from notion_client import AsyncClient
|
from notion_client import AsyncClient
|
||||||
|
from notion_markdown import to_notion
|
||||||
from notion_client.errors import APIResponseError
|
from notion_client.errors import APIResponseError
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
@ -834,106 +835,8 @@ class NotionHistoryConnector:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _markdown_to_blocks(self, markdown: str) -> list[dict[str, Any]]:
|
def _markdown_to_blocks(self, markdown: str) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Convert markdown content to Notion blocks using notion-markdown."""
|
||||||
Convert markdown content to Notion blocks.
|
return to_notion(markdown)
|
||||||
|
|
||||||
This is a simple converter that handles basic markdown.
|
|
||||||
For more complex markdown, consider using a proper markdown parser.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
markdown: Markdown content
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of Notion block objects
|
|
||||||
"""
|
|
||||||
blocks = []
|
|
||||||
lines = markdown.split("\n")
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
line = line.strip()
|
|
||||||
|
|
||||||
if not line:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Heading 1
|
|
||||||
if line.startswith("# "):
|
|
||||||
blocks.append(
|
|
||||||
{
|
|
||||||
"object": "block",
|
|
||||||
"type": "heading_1",
|
|
||||||
"heading_1": {
|
|
||||||
"rich_text": [
|
|
||||||
{"type": "text", "text": {"content": line[2:]}}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Heading 2
|
|
||||||
elif line.startswith("## "):
|
|
||||||
blocks.append(
|
|
||||||
{
|
|
||||||
"object": "block",
|
|
||||||
"type": "heading_2",
|
|
||||||
"heading_2": {
|
|
||||||
"rich_text": [
|
|
||||||
{"type": "text", "text": {"content": line[3:]}}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Heading 3
|
|
||||||
elif line.startswith("### "):
|
|
||||||
blocks.append(
|
|
||||||
{
|
|
||||||
"object": "block",
|
|
||||||
"type": "heading_3",
|
|
||||||
"heading_3": {
|
|
||||||
"rich_text": [
|
|
||||||
{"type": "text", "text": {"content": line[4:]}}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Bullet list
|
|
||||||
elif line.startswith("- ") or line.startswith("* "):
|
|
||||||
blocks.append(
|
|
||||||
{
|
|
||||||
"object": "block",
|
|
||||||
"type": "bulleted_list_item",
|
|
||||||
"bulleted_list_item": {
|
|
||||||
"rich_text": [
|
|
||||||
{"type": "text", "text": {"content": line[2:]}}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Numbered list
|
|
||||||
elif match := re.match(r"^(\d+)\.\s+(.*)$", line):
|
|
||||||
content = match.group(2) # Extract text after "number. "
|
|
||||||
blocks.append(
|
|
||||||
{
|
|
||||||
"object": "block",
|
|
||||||
"type": "numbered_list_item",
|
|
||||||
"numbered_list_item": {
|
|
||||||
"rich_text": [
|
|
||||||
{"type": "text", "text": {"content": content}}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Regular paragraph
|
|
||||||
else:
|
|
||||||
blocks.append(
|
|
||||||
{
|
|
||||||
"object": "block",
|
|
||||||
"type": "paragraph",
|
|
||||||
"paragraph": {
|
|
||||||
"rich_text": [{"type": "text", "text": {"content": line}}]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return blocks
|
|
||||||
|
|
||||||
async def create_page(
|
async def create_page(
|
||||||
self, title: str, content: str, parent_page_id: str | None = None
|
self, title: str, content: str, parent_page_id: str | None = None
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ dependencies = [
|
||||||
"deepagents>=0.4.3",
|
"deepagents>=0.4.3",
|
||||||
"langchain-daytona>=0.0.2",
|
"langchain-daytona>=0.0.2",
|
||||||
"pypandoc>=1.16.2",
|
"pypandoc>=1.16.2",
|
||||||
|
"notion-markdown>=0.7.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|
|
||||||
8420
surfsense_backend/uv.lock
generated
8420
surfsense_backend/uv.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { makeAssistantToolUI } from "@assistant-ui/react";
|
import { makeAssistantToolUI } from "@assistant-ui/react";
|
||||||
import { CornerDownLeftIcon, Loader2Icon, Pen } from "lucide-react";
|
import { CornerDownLeftIcon, Pen } from "lucide-react";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { PlateEditor } from "@/components/editor/plate-editor";
|
import { PlateEditor } from "@/components/editor/plate-editor";
|
||||||
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
import { openHitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";
|
import { openHitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";
|
||||||
|
|
||||||
|
|
@ -288,31 +289,25 @@ function ApprovalCard({
|
||||||
|
|
||||||
{/* Content preview */}
|
{/* Content preview */}
|
||||||
<div className="mx-5 h-px bg-border/50" />
|
<div className="mx-5 h-px bg-border/50" />
|
||||||
<div className="px-5 pt-4 space-y-3">
|
<div className="px-5 pt-3">
|
||||||
{args.title != null && (
|
{args.title != null && (
|
||||||
<div>
|
<p className="text-sm font-medium text-foreground">{String(args.title)}</p>
|
||||||
<p className="text-xs font-medium text-muted-foreground">Title</p>
|
|
||||||
<p className="mt-0.5 text-sm text-foreground">{String(args.title)}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
{args.content != null && (
|
{args.content != null && (
|
||||||
<div>
|
<div
|
||||||
<p className="text-xs font-medium text-muted-foreground">Content</p>
|
className="max-h-[7rem] overflow-hidden text-sm"
|
||||||
<div
|
style={{
|
||||||
className="mt-0.5 max-h-[7rem] overflow-hidden text-sm"
|
maskImage: "linear-gradient(to bottom, black 50%, transparent 100%)",
|
||||||
style={{
|
WebkitMaskImage: "linear-gradient(to bottom, black 50%, transparent 100%)",
|
||||||
maskImage: "linear-gradient(to bottom, black 50%, transparent 100%)",
|
}}
|
||||||
WebkitMaskImage: "linear-gradient(to bottom, black 50%, transparent 100%)",
|
>
|
||||||
}}
|
<PlateEditor
|
||||||
>
|
markdown={String(args.content)}
|
||||||
<PlateEditor
|
readOnly
|
||||||
markdown={String(args.content)}
|
preset="readonly"
|
||||||
readOnly
|
editorVariant="none"
|
||||||
preset="readonly"
|
className="h-auto [&_[data-slate-editor]]:!min-h-0 [&_[data-slate-editor]>*:first-child]:!mt-0"
|
||||||
editorVariant="none"
|
/>
|
||||||
className="h-auto [&_[data-slate-editor]]:!min-h-0"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -407,7 +402,7 @@ export const CreateNotionPageToolUI = makeAssistantToolUI<
|
||||||
if (status.type === "running") {
|
if (status.type === "running") {
|
||||||
return (
|
return (
|
||||||
<div className="my-4 flex max-w-lg items-center gap-3 rounded-2xl border bg-muted/30 px-5 py-4">
|
<div className="my-4 flex max-w-lg items-center gap-3 rounded-2xl border bg-muted/30 px-5 py-4">
|
||||||
<Loader2Icon className="size-4 animate-spin text-muted-foreground" />
|
<Spinner size="sm" className="text-muted-foreground" />
|
||||||
<p className="text-sm text-muted-foreground">Preparing Notion page...</p>
|
<p className="text-sm text-muted-foreground">Preparing Notion page...</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue