notionary 0.2.19__py3-none-any.whl → 0.2.21__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- notionary/__init__.py +8 -4
- notionary/base_notion_client.py +3 -1
- notionary/blocks/__init__.py +2 -91
- notionary/blocks/_bootstrap.py +263 -0
- notionary/blocks/audio/__init__.py +8 -2
- notionary/blocks/audio/audio_element.py +42 -104
- notionary/blocks/audio/audio_markdown_node.py +3 -1
- notionary/blocks/audio/audio_models.py +6 -55
- notionary/blocks/base_block_element.py +30 -0
- notionary/blocks/bookmark/__init__.py +9 -2
- notionary/blocks/bookmark/bookmark_element.py +46 -139
- notionary/blocks/bookmark/bookmark_markdown_node.py +3 -1
- notionary/blocks/bookmark/bookmark_models.py +15 -0
- notionary/blocks/breadcrumbs/__init__.py +17 -0
- notionary/blocks/breadcrumbs/breadcrumb_element.py +39 -0
- notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +32 -0
- notionary/blocks/breadcrumbs/breadcrumb_models.py +12 -0
- notionary/blocks/bulleted_list/__init__.py +12 -2
- notionary/blocks/bulleted_list/bulleted_list_element.py +40 -55
- notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +2 -1
- notionary/blocks/bulleted_list/bulleted_list_models.py +18 -0
- notionary/blocks/callout/__init__.py +9 -2
- notionary/blocks/callout/callout_element.py +40 -89
- notionary/blocks/callout/callout_markdown_node.py +3 -1
- notionary/blocks/callout/callout_models.py +33 -0
- notionary/blocks/child_database/__init__.py +7 -0
- notionary/blocks/child_database/child_database_models.py +19 -0
- notionary/blocks/child_page/__init__.py +9 -0
- notionary/blocks/child_page/child_page_models.py +12 -0
- notionary/blocks/{shared/block_client.py → client.py} +55 -54
- notionary/blocks/code/__init__.py +6 -2
- notionary/blocks/code/code_element.py +53 -187
- notionary/blocks/code/code_markdown_node.py +13 -13
- notionary/blocks/code/code_models.py +94 -0
- notionary/blocks/column/__init__.py +25 -1
- notionary/blocks/column/column_element.py +40 -314
- notionary/blocks/column/column_list_element.py +37 -0
- notionary/blocks/column/column_list_markdown_node.py +50 -0
- notionary/blocks/column/column_markdown_node.py +59 -0
- notionary/blocks/column/column_models.py +26 -0
- notionary/blocks/divider/__init__.py +9 -2
- notionary/blocks/divider/divider_element.py +26 -49
- notionary/blocks/divider/divider_markdown_node.py +2 -1
- notionary/blocks/divider/divider_models.py +12 -0
- notionary/blocks/embed/__init__.py +9 -2
- notionary/blocks/embed/embed_element.py +47 -114
- notionary/blocks/embed/embed_markdown_node.py +3 -1
- notionary/blocks/embed/embed_models.py +14 -0
- notionary/blocks/equation/__init__.py +14 -0
- notionary/blocks/equation/equation_element.py +80 -0
- notionary/blocks/equation/equation_element_markdown_node.py +36 -0
- notionary/blocks/equation/equation_models.py +11 -0
- notionary/blocks/file/__init__.py +25 -0
- notionary/blocks/file/file_element.py +93 -0
- notionary/blocks/file/file_element_markdown_node.py +35 -0
- notionary/blocks/file/file_element_models.py +39 -0
- notionary/blocks/heading/__init__.py +16 -2
- notionary/blocks/heading/heading_element.py +67 -72
- notionary/blocks/heading/heading_markdown_node.py +2 -1
- notionary/blocks/heading/heading_models.py +29 -0
- notionary/blocks/image_block/__init__.py +13 -0
- notionary/blocks/image_block/image_element.py +84 -0
- notionary/blocks/{image → image_block}/image_markdown_node.py +3 -1
- notionary/blocks/image_block/image_models.py +10 -0
- notionary/blocks/models.py +172 -0
- notionary/blocks/numbered_list/__init__.py +12 -2
- notionary/blocks/numbered_list/numbered_list_element.py +33 -58
- notionary/blocks/numbered_list/numbered_list_markdown_node.py +3 -1
- notionary/blocks/numbered_list/numbered_list_models.py +17 -0
- notionary/blocks/paragraph/__init__.py +12 -2
- notionary/blocks/paragraph/paragraph_element.py +27 -69
- notionary/blocks/paragraph/paragraph_markdown_node.py +2 -1
- notionary/blocks/paragraph/paragraph_models.py +16 -0
- notionary/blocks/pdf/__init__.py +13 -0
- notionary/blocks/pdf/pdf_element.py +91 -0
- notionary/blocks/pdf/pdf_markdown_node.py +35 -0
- notionary/blocks/pdf/pdf_models.py +11 -0
- notionary/blocks/quote/__init__.py +11 -2
- notionary/blocks/quote/quote_element.py +31 -65
- notionary/blocks/quote/quote_markdown_node.py +4 -1
- notionary/blocks/quote/quote_models.py +18 -0
- notionary/blocks/registry/__init__.py +4 -0
- notionary/blocks/registry/block_registry.py +75 -91
- notionary/blocks/registry/block_registry_builder.py +107 -59
- notionary/blocks/rich_text/__init__.py +33 -0
- notionary/blocks/rich_text/rich_text_models.py +188 -0
- notionary/blocks/rich_text/text_inline_formatter.py +125 -0
- notionary/blocks/table/__init__.py +16 -2
- notionary/blocks/table/table_element.py +48 -241
- notionary/blocks/table/table_markdown_node.py +2 -1
- notionary/blocks/table/table_models.py +28 -0
- notionary/blocks/table_of_contents/__init__.py +19 -0
- notionary/blocks/table_of_contents/table_of_contents_element.py +51 -0
- notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +35 -0
- notionary/blocks/table_of_contents/table_of_contents_models.py +18 -0
- notionary/blocks/todo/__init__.py +9 -2
- notionary/blocks/todo/todo_element.py +38 -95
- notionary/blocks/todo/todo_markdown_node.py +2 -1
- notionary/blocks/todo/todo_models.py +19 -0
- notionary/blocks/toggle/__init__.py +13 -3
- notionary/blocks/toggle/toggle_element.py +57 -264
- notionary/blocks/toggle/toggle_markdown_node.py +24 -14
- notionary/blocks/toggle/toggle_models.py +17 -0
- notionary/blocks/toggleable_heading/__init__.py +6 -2
- notionary/blocks/toggleable_heading/toggleable_heading_element.py +74 -244
- notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +26 -18
- notionary/blocks/types.py +61 -0
- notionary/blocks/video/__init__.py +8 -2
- notionary/blocks/video/video_element.py +67 -143
- notionary/blocks/video/video_element_models.py +10 -0
- notionary/blocks/video/video_markdown_node.py +3 -1
- notionary/database/client.py +3 -8
- notionary/database/database.py +13 -14
- notionary/database/database_filter_builder.py +2 -2
- notionary/database/database_provider.py +5 -4
- notionary/database/models.py +337 -0
- notionary/database/notion_database.py +6 -7
- notionary/file_upload/client.py +5 -7
- notionary/file_upload/models.py +2 -1
- notionary/file_upload/notion_file_upload.py +2 -3
- notionary/markdown/markdown_builder.py +722 -0
- notionary/markdown/markdown_document_model.py +228 -0
- notionary/{blocks → markdown}/markdown_node.py +1 -0
- notionary/models/notion_database_response.py +0 -338
- notionary/page/client.py +9 -10
- notionary/page/models.py +327 -0
- notionary/page/notion_page.py +99 -52
- notionary/page/notion_text_length_utils.py +119 -0
- notionary/page/{content/page_content_writer.py → page_content_writer.py} +88 -38
- notionary/page/reader/handler/__init__.py +17 -0
- notionary/page/reader/handler/base_block_renderer.py +44 -0
- notionary/page/reader/handler/block_processing_context.py +35 -0
- notionary/page/reader/handler/block_rendering_context.py +43 -0
- notionary/page/reader/handler/column_list_renderer.py +51 -0
- notionary/page/reader/handler/column_renderer.py +60 -0
- notionary/page/reader/handler/line_renderer.py +60 -0
- notionary/page/reader/handler/toggle_renderer.py +69 -0
- notionary/page/reader/handler/toggleable_heading_renderer.py +89 -0
- notionary/page/reader/page_content_retriever.py +69 -0
- notionary/page/search_filter_builder.py +2 -1
- notionary/page/writer/handler/__init__.py +22 -0
- notionary/page/writer/handler/code_handler.py +100 -0
- notionary/page/writer/handler/column_handler.py +141 -0
- notionary/page/writer/handler/column_list_handler.py +139 -0
- notionary/page/writer/handler/line_handler.py +35 -0
- notionary/page/writer/handler/line_processing_context.py +54 -0
- notionary/page/writer/handler/regular_line_handler.py +92 -0
- notionary/page/writer/handler/table_handler.py +130 -0
- notionary/page/writer/handler/toggle_handler.py +153 -0
- notionary/page/writer/handler/toggleable_heading_handler.py +167 -0
- notionary/page/writer/markdown_to_notion_converter.py +76 -0
- notionary/telemetry/__init__.py +2 -2
- notionary/telemetry/service.py +4 -3
- notionary/user/__init__.py +2 -2
- notionary/user/base_notion_user.py +2 -1
- notionary/user/client.py +2 -3
- notionary/user/models.py +1 -0
- notionary/user/notion_bot_user.py +4 -5
- notionary/user/notion_user.py +3 -4
- notionary/user/notion_user_manager.py +3 -2
- notionary/user/notion_user_provider.py +1 -1
- notionary/util/__init__.py +3 -2
- notionary/util/fuzzy.py +2 -1
- notionary/util/logging_mixin.py +2 -2
- notionary/util/singleton_metaclass.py +1 -1
- notionary/workspace.py +3 -2
- {notionary-0.2.19.dist-info → notionary-0.2.21.dist-info}/METADATA +12 -8
- notionary-0.2.21.dist-info/RECORD +185 -0
- notionary/blocks/document/__init__.py +0 -7
- notionary/blocks/document/document_element.py +0 -102
- notionary/blocks/document/document_markdown_node.py +0 -31
- notionary/blocks/image/__init__.py +0 -7
- notionary/blocks/image/image_element.py +0 -151
- notionary/blocks/markdown_builder.py +0 -356
- notionary/blocks/mention/__init__.py +0 -7
- notionary/blocks/mention/mention_element.py +0 -229
- notionary/blocks/mention/mention_markdown_node.py +0 -38
- notionary/blocks/prompts/element_prompt_builder.py +0 -83
- notionary/blocks/prompts/element_prompt_content.py +0 -41
- notionary/blocks/shared/__init__.py +0 -0
- notionary/blocks/shared/models.py +0 -713
- notionary/blocks/shared/notion_block_element.py +0 -37
- notionary/blocks/shared/text_inline_formatter.py +0 -262
- notionary/blocks/shared/text_inline_formatter_new.py +0 -139
- notionary/blocks/toggleable_heading/toggleable_heading_models.py +0 -0
- notionary/database/models/page_result.py +0 -10
- notionary/elements/__init__.py +0 -0
- notionary/models/notion_block_response.py +0 -264
- notionary/models/notion_page_response.py +0 -78
- notionary/models/search_response.py +0 -0
- notionary/page/__init__.py +0 -0
- notionary/page/content/notion_text_length_utils.py +0 -87
- notionary/page/content/page_content_retriever.py +0 -60
- notionary/page/formatting/line_processor.py +0 -153
- notionary/page/formatting/markdown_to_notion_converter.py +0 -153
- notionary/page/markdown_syntax_prompt_generator.py +0 -114
- notionary/page/notion_to_markdown_converter.py +0 -179
- notionary/page/properites/property_value_extractor.py +0 -0
- notionary-0.2.19.dist-info/RECORD +0 -150
- /notionary/{blocks/document/document_models.py → markdown/___init__.py} +0 -0
- /notionary/{blocks/image/image_models.py → markdown/makdown_document_model.py} +0 -0
- /notionary/page/{content/markdown_whitespace_processor.py → markdown_whitespace_processor.py} +0 -0
- /notionary/{blocks/mention/mention_models.py → page/reader/handler/context.py} +0 -0
- {notionary-0.2.19.dist-info → notionary-0.2.21.dist-info}/LICENSE +0 -0
- {notionary-0.2.19.dist-info → notionary-0.2.21.dist-info}/WHEEL +0 -0
notionary/__init__.py
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
from .
|
1
|
+
from notionary.blocks import bootstrap_blocks
|
2
|
+
|
3
|
+
bootstrap_blocks()
|
4
|
+
|
5
|
+
from .database import DatabaseFilterBuilder, NotionDatabase
|
6
|
+
from .file_upload import NotionFileUpload
|
7
|
+
from .markdown.markdown_builder import MarkdownBuilder
|
2
8
|
from .page.notion_page import NotionPage
|
9
|
+
from .user import NotionBotUser, NotionUser, NotionUserManager
|
3
10
|
from .workspace import NotionWorkspace
|
4
|
-
from .user import NotionUser, NotionUserManager, NotionBotUser
|
5
|
-
from .file_upload import NotionFileUpload
|
6
|
-
from .blocks.markdown_builder import MarkdownBuilder
|
7
11
|
|
8
12
|
__all__ = [
|
9
13
|
"NotionDatabase",
|
notionary/base_notion_client.py
CHANGED
@@ -2,9 +2,11 @@ import asyncio
|
|
2
2
|
import os
|
3
3
|
from abc import ABC
|
4
4
|
from enum import Enum
|
5
|
-
from typing import
|
5
|
+
from typing import Any, Dict, Optional, Union
|
6
|
+
|
6
7
|
import httpx
|
7
8
|
from dotenv import load_dotenv
|
9
|
+
|
8
10
|
from notionary.util import LoggingMixin
|
9
11
|
|
10
12
|
load_dotenv()
|
notionary/blocks/__init__.py
CHANGED
@@ -1,92 +1,3 @@
|
|
1
|
-
|
2
|
-
from .prompts.element_prompt_content import ElementPromptContent
|
3
|
-
from .prompts.element_prompt_builder import ElementPromptBuilder
|
1
|
+
from ._bootstrap import bootstrap_blocks
|
4
2
|
|
5
|
-
|
6
|
-
NotionBlockElement,
|
7
|
-
NotionBlockResult,
|
8
|
-
NotionBlock,
|
9
|
-
)
|
10
|
-
|
11
|
-
from .audio import AudioElement, AudioMarkdownNode
|
12
|
-
from .bulleted_list import BulletedListElement, BulletedListMarkdownNode
|
13
|
-
from .callout import CalloutElement, CalloutMarkdownNode
|
14
|
-
from .code import CodeElement, CodeMarkdownNode
|
15
|
-
from .column.column_element import ColumnElement
|
16
|
-
from .divider import DividerElement, DividerMarkdownNode
|
17
|
-
from .embed import EmbedElement, EmbedMarkdownNode
|
18
|
-
from .heading import HeadingElement, HeadingMarkdownNode
|
19
|
-
from .image import ImageElement, ImageMarkdownNode
|
20
|
-
from .numbered_list import NumberedListElement, NumberedListMarkdownNode
|
21
|
-
from .paragraph import ParagraphElement, ParagraphMarkdownNode
|
22
|
-
from .table import TableElement, TableMarkdownNode
|
23
|
-
from .toggle import ToggleElement, ToggleMarkdownNode
|
24
|
-
from .todo import TodoElement, TodoMarkdownNode
|
25
|
-
from .video import VideoElement, VideoMarkdownNode
|
26
|
-
from .toggleable_heading import ToggleableHeadingElement, ToggleableHeadingMarkdownNode
|
27
|
-
from .bookmark import BookmarkElement, BookmarkMarkdownNode
|
28
|
-
from .divider import DividerElement, DividerMarkdownNode
|
29
|
-
from .heading import HeadingElement, HeadingMarkdownNode
|
30
|
-
from .mention import MentionElement, MentionMarkdownNode
|
31
|
-
from .quote import QuoteElement, QuoteMarkdownNode
|
32
|
-
from .document import DocumentElement, DocumentMarkdownNode
|
33
|
-
from .shared.text_inline_formatter import TextInlineFormatter
|
34
|
-
|
35
|
-
from .markdown_node import MarkdownNode
|
36
|
-
|
37
|
-
from .registry.block_registry import BlockRegistry
|
38
|
-
from .registry.block_registry_builder import BlockRegistryBuilder
|
39
|
-
|
40
|
-
from .shared.block_client import NotionBlockClient
|
41
|
-
|
42
|
-
__all__ = [
|
43
|
-
"MarkdownNode",
|
44
|
-
"ElementPromptContent",
|
45
|
-
"ElementPromptBuilder",
|
46
|
-
"NotionBlockElement",
|
47
|
-
"AudioElement",
|
48
|
-
"AudioMarkdownNode",
|
49
|
-
"BulletedListElement",
|
50
|
-
"BulletedListMarkdownNode",
|
51
|
-
"CalloutElement",
|
52
|
-
"CalloutMarkdownNode",
|
53
|
-
"CodeElement",
|
54
|
-
"CodeMarkdownNode",
|
55
|
-
"ColumnElement",
|
56
|
-
"DividerElement",
|
57
|
-
"DividerMarkdownNode",
|
58
|
-
"EmbedElement",
|
59
|
-
"EmbedMarkdownNode",
|
60
|
-
"HeadingElement",
|
61
|
-
"HeadingMarkdownNode",
|
62
|
-
"ImageElement",
|
63
|
-
"ImageMarkdownNode",
|
64
|
-
"NumberedListElement",
|
65
|
-
"NumberedListMarkdownNode",
|
66
|
-
"ParagraphElement",
|
67
|
-
"ParagraphMarkdownNode",
|
68
|
-
"TableElement",
|
69
|
-
"TableMarkdownNode",
|
70
|
-
"ToggleElement",
|
71
|
-
"ToggleMarkdownNode",
|
72
|
-
"TodoElement",
|
73
|
-
"TodoMarkdownNode",
|
74
|
-
"VideoElement",
|
75
|
-
"VideoMarkdownNode",
|
76
|
-
"ToggleableHeadingElement",
|
77
|
-
"ToggleableHeadingMarkdownNode",
|
78
|
-
"BookmarkElement",
|
79
|
-
"BookmarkMarkdownNode",
|
80
|
-
"MentionElement",
|
81
|
-
"MentionMarkdownNode",
|
82
|
-
"QuoteElement",
|
83
|
-
"QuoteMarkdownNode",
|
84
|
-
"DocumentElement",
|
85
|
-
"DocumentMarkdownNode",
|
86
|
-
"BlockRegistry",
|
87
|
-
"BlockRegistryBuilder",
|
88
|
-
"TextInlineFormatter",
|
89
|
-
"NotionBlockResult",
|
90
|
-
"NotionBlock",
|
91
|
-
"NotionBlockClient",
|
92
|
-
]
|
3
|
+
__all__ = ["bootstrap_blocks"]
|
@@ -0,0 +1,263 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import Optional, Union
|
4
|
+
|
5
|
+
_bootstrapped = False
|
6
|
+
|
7
|
+
|
8
|
+
def bootstrap_blocks() -> None:
|
9
|
+
global _bootstrapped
|
10
|
+
if _bootstrapped:
|
11
|
+
return
|
12
|
+
|
13
|
+
from notionary.blocks import (
|
14
|
+
bookmark,
|
15
|
+
breadcrumbs,
|
16
|
+
bulleted_list,
|
17
|
+
callout,
|
18
|
+
child_page,
|
19
|
+
code,
|
20
|
+
column,
|
21
|
+
divider,
|
22
|
+
embed,
|
23
|
+
equation,
|
24
|
+
file,
|
25
|
+
heading,
|
26
|
+
image_block,
|
27
|
+
models,
|
28
|
+
numbered_list,
|
29
|
+
paragraph,
|
30
|
+
quote,
|
31
|
+
table,
|
32
|
+
table_of_contents,
|
33
|
+
todo,
|
34
|
+
toggle,
|
35
|
+
toggleable_heading,
|
36
|
+
video,
|
37
|
+
)
|
38
|
+
|
39
|
+
# Collect all exports from modules
|
40
|
+
ns = {}
|
41
|
+
for m in (
|
42
|
+
bookmark,
|
43
|
+
breadcrumbs,
|
44
|
+
bulleted_list,
|
45
|
+
callout,
|
46
|
+
child_page,
|
47
|
+
code,
|
48
|
+
column,
|
49
|
+
divider,
|
50
|
+
embed,
|
51
|
+
equation,
|
52
|
+
file,
|
53
|
+
heading,
|
54
|
+
image_block,
|
55
|
+
numbered_list,
|
56
|
+
paragraph,
|
57
|
+
quote,
|
58
|
+
table,
|
59
|
+
todo,
|
60
|
+
toggle,
|
61
|
+
video,
|
62
|
+
toggleable_heading,
|
63
|
+
table_of_contents,
|
64
|
+
):
|
65
|
+
ns.update(vars(m))
|
66
|
+
|
67
|
+
# Add missing types that are needed for model rebuilding
|
68
|
+
# These are the types that are only defined in TYPE_CHECKING in block_models
|
69
|
+
from notionary.blocks.bookmark.bookmark_models import (
|
70
|
+
BookmarkBlock,
|
71
|
+
CreateBookmarkBlock,
|
72
|
+
)
|
73
|
+
from notionary.blocks.breadcrumbs.breadcrumb_models import (
|
74
|
+
BreadcrumbBlock,
|
75
|
+
CreateBreadcrumbBlock,
|
76
|
+
)
|
77
|
+
from notionary.blocks.bulleted_list.bulleted_list_models import (
|
78
|
+
BulletedListItemBlock,
|
79
|
+
CreateBulletedListItemBlock,
|
80
|
+
)
|
81
|
+
from notionary.blocks.callout.callout_models import CalloutBlock, CreateCalloutBlock
|
82
|
+
from notionary.blocks.child_page.child_page_models import (
|
83
|
+
ChildPageBlock,
|
84
|
+
CreateChildPageBlock,
|
85
|
+
)
|
86
|
+
from notionary.blocks.code.code_models import CodeBlock, CreateCodeBlock
|
87
|
+
from notionary.blocks.column.column_models import (
|
88
|
+
ColumnBlock,
|
89
|
+
ColumnListBlock,
|
90
|
+
CreateColumnBlock,
|
91
|
+
CreateColumnListBlock,
|
92
|
+
)
|
93
|
+
from notionary.blocks.divider.divider_models import CreateDividerBlock, DividerBlock
|
94
|
+
from notionary.blocks.embed.embed_models import CreateEmbedBlock, EmbedBlock
|
95
|
+
from notionary.blocks.equation.equation_models import (
|
96
|
+
CreateEquationBlock,
|
97
|
+
EquationBlock,
|
98
|
+
)
|
99
|
+
from notionary.blocks.file.file_element_models import CreateFileBlock, FileBlock
|
100
|
+
from notionary.blocks.heading.heading_models import (
|
101
|
+
CreateHeading1Block,
|
102
|
+
CreateHeading2Block,
|
103
|
+
CreateHeading3Block,
|
104
|
+
HeadingBlock,
|
105
|
+
)
|
106
|
+
from notionary.blocks.image_block.image_models import CreateImageBlock
|
107
|
+
from notionary.blocks.numbered_list.numbered_list_models import (
|
108
|
+
CreateNumberedListItemBlock,
|
109
|
+
NumberedListItemBlock,
|
110
|
+
)
|
111
|
+
from notionary.blocks.paragraph.paragraph_models import (
|
112
|
+
CreateParagraphBlock,
|
113
|
+
ParagraphBlock,
|
114
|
+
)
|
115
|
+
from notionary.blocks.pdf.pdf_models import CreatePdfBlock
|
116
|
+
from notionary.blocks.quote.quote_models import CreateQuoteBlock, QuoteBlock
|
117
|
+
from notionary.blocks.table.table_models import TableBlock, TableRowBlock
|
118
|
+
from notionary.blocks.table_of_contents.table_of_contents_models import (
|
119
|
+
CreateTableOfContentsBlock,
|
120
|
+
TableOfContentsBlock,
|
121
|
+
)
|
122
|
+
from notionary.blocks.todo.todo_models import CreateToDoBlock, ToDoBlock
|
123
|
+
from notionary.blocks.toggle.toggle_models import CreateToggleBlock, ToggleBlock
|
124
|
+
from notionary.blocks.types import BlockType
|
125
|
+
from notionary.blocks.video.video_element_models import CreateVideoBlock
|
126
|
+
|
127
|
+
# Define the Union types that are needed for model rebuilding
|
128
|
+
BlockCreateRequest = Union[
|
129
|
+
CreateBookmarkBlock,
|
130
|
+
CreateBreadcrumbBlock,
|
131
|
+
CreateBulletedListItemBlock,
|
132
|
+
CreateCalloutBlock,
|
133
|
+
CreateChildPageBlock,
|
134
|
+
CreateCodeBlock,
|
135
|
+
CreateColumnListBlock,
|
136
|
+
CreateColumnBlock,
|
137
|
+
CreateDividerBlock,
|
138
|
+
CreateEmbedBlock,
|
139
|
+
CreateEquationBlock,
|
140
|
+
CreateFileBlock,
|
141
|
+
CreateHeading1Block,
|
142
|
+
CreateHeading2Block,
|
143
|
+
CreateHeading3Block,
|
144
|
+
CreateImageBlock,
|
145
|
+
CreateNumberedListItemBlock,
|
146
|
+
CreateParagraphBlock,
|
147
|
+
CreateQuoteBlock,
|
148
|
+
CreateToDoBlock,
|
149
|
+
CreateToggleBlock,
|
150
|
+
CreateVideoBlock,
|
151
|
+
CreateTableOfContentsBlock,
|
152
|
+
CreatePdfBlock,
|
153
|
+
]
|
154
|
+
|
155
|
+
BlockCreateResult = Optional[Union[list[BlockCreateRequest], BlockCreateRequest]]
|
156
|
+
|
157
|
+
# Add all block types to namespace
|
158
|
+
ns.update(
|
159
|
+
{
|
160
|
+
"BlockType": BlockType,
|
161
|
+
"BookmarkBlock": BookmarkBlock,
|
162
|
+
"CreateBookmarkBlock": CreateBookmarkBlock,
|
163
|
+
"BreadcrumbBlock": BreadcrumbBlock,
|
164
|
+
"CreateBreadcrumbBlock": CreateBreadcrumbBlock,
|
165
|
+
"BulletedListItemBlock": BulletedListItemBlock,
|
166
|
+
"CreateBulletedListItemBlock": CreateBulletedListItemBlock,
|
167
|
+
"CalloutBlock": CalloutBlock,
|
168
|
+
"CreateCalloutBlock": CreateCalloutBlock,
|
169
|
+
"ChildPageBlock": ChildPageBlock,
|
170
|
+
"CreateChildPageBlock": CreateChildPageBlock,
|
171
|
+
"CodeBlock": CodeBlock,
|
172
|
+
"CreateCodeBlock": CreateCodeBlock,
|
173
|
+
"ColumnBlock": ColumnBlock,
|
174
|
+
"ColumnListBlock": ColumnListBlock,
|
175
|
+
"CreateColumnBlock": CreateColumnBlock,
|
176
|
+
"CreateColumnListBlock": CreateColumnListBlock,
|
177
|
+
"DividerBlock": DividerBlock,
|
178
|
+
"CreateDividerBlock": CreateDividerBlock,
|
179
|
+
"EmbedBlock": EmbedBlock,
|
180
|
+
"CreateEmbedBlock": CreateEmbedBlock,
|
181
|
+
"EquationBlock": EquationBlock,
|
182
|
+
"CreateEquationBlock": CreateEquationBlock,
|
183
|
+
"FileBlock": FileBlock,
|
184
|
+
"CreateFileBlock": CreateFileBlock,
|
185
|
+
"HeadingBlock": HeadingBlock,
|
186
|
+
"CreateHeading1Block": CreateHeading1Block,
|
187
|
+
"CreateHeading2Block": CreateHeading2Block,
|
188
|
+
"CreateHeading3Block": CreateHeading3Block,
|
189
|
+
"CreateImageBlock": CreateImageBlock,
|
190
|
+
"NumberedListItemBlock": NumberedListItemBlock,
|
191
|
+
"CreateNumberedListItemBlock": CreateNumberedListItemBlock,
|
192
|
+
"ParagraphBlock": ParagraphBlock,
|
193
|
+
"CreateParagraphBlock": CreateParagraphBlock,
|
194
|
+
"QuoteBlock": QuoteBlock,
|
195
|
+
"CreateQuoteBlock": CreateQuoteBlock,
|
196
|
+
"TableBlock": TableBlock,
|
197
|
+
"TableRowBlock": TableRowBlock,
|
198
|
+
"ToDoBlock": ToDoBlock,
|
199
|
+
"CreateToDoBlock": CreateToDoBlock,
|
200
|
+
"ToggleBlock": ToggleBlock,
|
201
|
+
"CreateToggleBlock": CreateToggleBlock,
|
202
|
+
"CreateVideoBlock": CreateVideoBlock,
|
203
|
+
"TableOfContentsBlock": TableOfContentsBlock,
|
204
|
+
"CreateTableOfContentsBlock": CreateTableOfContentsBlock,
|
205
|
+
# Add the Union types
|
206
|
+
"BlockCreateRequest": BlockCreateRequest,
|
207
|
+
"BlockCreateResult": BlockCreateResult,
|
208
|
+
}
|
209
|
+
)
|
210
|
+
|
211
|
+
# Now rebuild with complete namespace
|
212
|
+
models.Block.model_rebuild(_types_namespace=ns)
|
213
|
+
models.BlockChildrenResponse.model_rebuild(_types_namespace=ns)
|
214
|
+
|
215
|
+
# Rebuild all individual block models
|
216
|
+
BookmarkBlock.model_rebuild()
|
217
|
+
BreadcrumbBlock.model_rebuild()
|
218
|
+
BulletedListItemBlock.model_rebuild()
|
219
|
+
CalloutBlock.model_rebuild()
|
220
|
+
ChildPageBlock.model_rebuild()
|
221
|
+
CodeBlock.model_rebuild()
|
222
|
+
ColumnBlock.model_rebuild()
|
223
|
+
ColumnListBlock.model_rebuild()
|
224
|
+
DividerBlock.model_rebuild()
|
225
|
+
EmbedBlock.model_rebuild()
|
226
|
+
EquationBlock.model_rebuild()
|
227
|
+
FileBlock.model_rebuild()
|
228
|
+
HeadingBlock.model_rebuild()
|
229
|
+
NumberedListItemBlock.model_rebuild()
|
230
|
+
ParagraphBlock.model_rebuild()
|
231
|
+
QuoteBlock.model_rebuild()
|
232
|
+
TableBlock.model_rebuild()
|
233
|
+
TableRowBlock.model_rebuild()
|
234
|
+
ToDoBlock.model_rebuild()
|
235
|
+
ToggleBlock.model_rebuild()
|
236
|
+
TableOfContentsBlock.model_rebuild()
|
237
|
+
|
238
|
+
# Rebuild create models
|
239
|
+
CreateBookmarkBlock.model_rebuild()
|
240
|
+
CreateBreadcrumbBlock.model_rebuild()
|
241
|
+
CreateBulletedListItemBlock.model_rebuild()
|
242
|
+
CreateCalloutBlock.model_rebuild()
|
243
|
+
CreateChildPageBlock.model_rebuild()
|
244
|
+
CreateCodeBlock.model_rebuild()
|
245
|
+
CreateColumnListBlock.model_rebuild()
|
246
|
+
CreateColumnBlock.model_rebuild()
|
247
|
+
CreateDividerBlock.model_rebuild()
|
248
|
+
CreateEmbedBlock.model_rebuild()
|
249
|
+
CreateEquationBlock.model_rebuild()
|
250
|
+
CreateFileBlock.model_rebuild()
|
251
|
+
CreateHeading1Block.model_rebuild()
|
252
|
+
CreateHeading2Block.model_rebuild()
|
253
|
+
CreateHeading3Block.model_rebuild()
|
254
|
+
CreateImageBlock.model_rebuild()
|
255
|
+
CreateNumberedListItemBlock.model_rebuild()
|
256
|
+
CreateParagraphBlock.model_rebuild()
|
257
|
+
CreateQuoteBlock.model_rebuild()
|
258
|
+
CreateToDoBlock.model_rebuild()
|
259
|
+
CreateToggleBlock.model_rebuild()
|
260
|
+
CreateVideoBlock.model_rebuild()
|
261
|
+
CreateTableOfContentsBlock.model_rebuild()
|
262
|
+
|
263
|
+
_bootstrapped = True
|
@@ -1,7 +1,13 @@
|
|
1
|
-
from .audio_element import AudioElement
|
2
|
-
from .audio_markdown_node import
|
1
|
+
from notionary.blocks.audio.audio_element import AudioElement
|
2
|
+
from notionary.blocks.audio.audio_markdown_node import (
|
3
|
+
AudioMarkdownBlockParams,
|
4
|
+
AudioMarkdownNode,
|
5
|
+
)
|
6
|
+
from notionary.blocks.audio.audio_models import CreateAudioBlock
|
3
7
|
|
4
8
|
__all__ = [
|
5
9
|
"AudioElement",
|
10
|
+
"CreateAudioBlock",
|
6
11
|
"AudioMarkdownNode",
|
12
|
+
"AudioMarkdownBlockParams",
|
7
13
|
]
|
@@ -1,152 +1,90 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import re
|
2
|
-
from typing import
|
4
|
+
from typing import Optional
|
3
5
|
|
4
|
-
from notionary.blocks import
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
from notionary.blocks.shared.models import RichTextObject
|
6
|
+
from notionary.blocks.audio.audio_models import CreateAudioBlock
|
7
|
+
from notionary.blocks.base_block_element import BaseBlockElement
|
8
|
+
from notionary.blocks.file.file_element_models import ExternalFile, FileBlock, FileType
|
9
|
+
from notionary.blocks.models import Block, BlockCreateResult, BlockType
|
10
|
+
from notionary.blocks.rich_text.rich_text_models import RichTextObject
|
11
|
+
from notionary.blocks.rich_text.text_inline_formatter import TextInlineFormatter
|
11
12
|
|
12
13
|
|
13
|
-
class AudioElement(
|
14
|
+
class AudioElement(BaseBlockElement):
|
14
15
|
"""
|
15
16
|
Handles conversion between Markdown audio embeds and Notion audio blocks.
|
16
17
|
|
17
18
|
Markdown audio syntax:
|
18
19
|
- [audio](https://example.com/audio.mp3) - Simple audio embed
|
19
|
-
- [audio](https://example.com/audio.mp3 "Caption text") - Audio with caption
|
20
|
+
- [audio](https://example.com/audio.mp3 "Caption text") - Audio with optional caption
|
20
21
|
|
21
22
|
Where:
|
22
23
|
- URL is the required audio file URL
|
23
24
|
- Caption is optional descriptive text (enclosed in quotes)
|
24
25
|
"""
|
25
26
|
|
26
|
-
# Regex patterns
|
27
27
|
URL_PATTERN = r"(https?://[^\s\"]+)"
|
28
28
|
CAPTION_PATTERN = r'(?:\s+"([^"]+)")?'
|
29
|
-
|
30
29
|
PATTERN = re.compile(r"^\[audio\]\(" + URL_PATTERN + CAPTION_PATTERN + r"\)$")
|
31
30
|
|
32
|
-
# Supported audio extensions
|
33
31
|
SUPPORTED_EXTENSIONS = {".mp3", ".wav", ".ogg", ".oga", ".m4a"}
|
34
32
|
|
35
33
|
@classmethod
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
return False
|
40
|
-
url = m.group(1)
|
41
|
-
return cls._is_likely_audio_url(url)
|
34
|
+
def match_notion(cls, block: Block) -> bool:
|
35
|
+
"""Check if this element can handle the given Notion block."""
|
36
|
+
return block.type == BlockType.AUDIO
|
42
37
|
|
43
38
|
@classmethod
|
44
|
-
def
|
45
|
-
"""
|
46
|
-
|
47
|
-
|
48
|
-
@classmethod
|
49
|
-
def markdown_to_notion(cls, text: str) -> NotionBlockResult:
|
50
|
-
"""Convert markdown audio embed to Notion audio block."""
|
51
|
-
audio_match = cls.PATTERN.match(text.strip())
|
52
|
-
if not audio_match:
|
53
|
-
return None
|
54
|
-
|
55
|
-
url = audio_match.group(1)
|
56
|
-
caption_text = audio_match.group(2)
|
57
|
-
|
58
|
-
if not url:
|
39
|
+
def markdown_to_notion(cls, text: str) -> BlockCreateResult:
|
40
|
+
"""Convert markdown audio embed to Notion audio block (or return None if not matching)."""
|
41
|
+
match = cls.PATTERN.match(text.strip())
|
42
|
+
if not match:
|
59
43
|
return None
|
44
|
+
url = match.group(1)
|
60
45
|
|
61
|
-
# Validate URL if possible
|
62
46
|
if not cls._is_likely_audio_url(url):
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
audio_data = {"type": "external", "external": {"url": url}}
|
47
|
+
return None
|
48
|
+
caption_text = match.group(2)
|
67
49
|
|
68
|
-
#
|
50
|
+
# Create caption rich text objects
|
51
|
+
caption_objects = []
|
69
52
|
if caption_text:
|
70
|
-
|
71
|
-
|
72
|
-
else:
|
73
|
-
audio_data["caption"] = []
|
53
|
+
caption_rt = RichTextObject.from_plain_text(caption_text)
|
54
|
+
caption_objects = [caption_rt]
|
74
55
|
|
75
|
-
|
56
|
+
audio_content = FileBlock(
|
57
|
+
type=FileType.EXTERNAL,
|
58
|
+
external=ExternalFile(url=url),
|
59
|
+
caption=caption_objects,
|
60
|
+
)
|
61
|
+
|
62
|
+
return CreateAudioBlock(audio=audio_content)
|
76
63
|
|
77
64
|
@classmethod
|
78
|
-
def notion_to_markdown(cls, block:
|
65
|
+
def notion_to_markdown(cls, block: Block) -> Optional[str]:
|
79
66
|
"""Convert Notion audio block to markdown audio embed."""
|
80
|
-
if block.
|
67
|
+
if block.type != BlockType.AUDIO or block.audio is None:
|
81
68
|
return None
|
82
69
|
|
83
|
-
|
70
|
+
audio = block.audio
|
84
71
|
|
85
|
-
#
|
86
|
-
if
|
87
|
-
url = audio_data.get("external", {}).get("url", "")
|
88
|
-
else:
|
89
|
-
# Handle file or file_upload types if needed
|
72
|
+
# Only handle external audio
|
73
|
+
if audio.type != FileType.EXTERNAL or audio.external is None:
|
90
74
|
return None
|
91
|
-
|
75
|
+
url = audio.external.url
|
92
76
|
if not url:
|
93
77
|
return None
|
94
78
|
|
95
79
|
# Extract caption
|
96
|
-
|
97
|
-
if
|
98
|
-
|
80
|
+
captions = audio.caption or []
|
81
|
+
if captions:
|
82
|
+
# use TextInlineFormatter instead of manual extraction
|
83
|
+
caption_text = TextInlineFormatter.extract_text_with_formatting(captions)
|
99
84
|
return f'[audio]({url} "{caption_text}")'
|
100
85
|
|
101
86
|
return f"[audio]({url})"
|
102
87
|
|
103
|
-
@classmethod
|
104
|
-
def is_multiline(cls) -> bool:
|
105
|
-
"""Audio embeds are single-line elements."""
|
106
|
-
return False
|
107
|
-
|
108
88
|
@classmethod
|
109
89
|
def _is_likely_audio_url(cls, url: str) -> bool:
|
110
|
-
"""Check if URL likely points to an audio file."""
|
111
90
|
return any(url.lower().endswith(ext) for ext in cls.SUPPORTED_EXTENSIONS)
|
112
|
-
|
113
|
-
@classmethod
|
114
|
-
def _extract_text_content(cls, rich_text: List[dict[str, Any]]) -> str:
|
115
|
-
"""Extract plain text content from Notion rich_text elements."""
|
116
|
-
result = ""
|
117
|
-
for text_obj in rich_text:
|
118
|
-
if text_obj.get("type") == "text":
|
119
|
-
result += text_obj.get("text", {}).get("content", "")
|
120
|
-
elif "plain_text" in text_obj:
|
121
|
-
result += text_obj.get("plain_text", "")
|
122
|
-
return result
|
123
|
-
|
124
|
-
@classmethod
|
125
|
-
def get_llm_prompt_content(cls) -> ElementPromptContent:
|
126
|
-
"""
|
127
|
-
Returns structured LLM prompt metadata for the audio element.
|
128
|
-
"""
|
129
|
-
return (
|
130
|
-
ElementPromptBuilder()
|
131
|
-
.with_description(
|
132
|
-
"Embeds an audio file that can be played directly in the page."
|
133
|
-
)
|
134
|
-
.with_usage_guidelines(
|
135
|
-
"Use audio embeds when you want to include sound files, music, podcasts, "
|
136
|
-
"or voice recordings. Supports common audio formats like MP3, WAV, OGG, and M4A."
|
137
|
-
)
|
138
|
-
.with_syntax('')
|
139
|
-
.with_examples(
|
140
|
-
[
|
141
|
-
"[audio](https://example.com/song.mp3)",
|
142
|
-
'[audio](https://example.com/podcast.mp3 "Episode 1: Introduction")',
|
143
|
-
'[audio](https://example.com/sound.wav "Sound effect for presentation")',
|
144
|
-
'[audio](https://example.com/recording.m4a "Voice memo from meeting")',
|
145
|
-
]
|
146
|
-
)
|
147
|
-
.with_avoidance_guidelines(
|
148
|
-
"Ensure the URL points to a valid audio file. "
|
149
|
-
"Some audio formats may not be supported by all browsers."
|
150
|
-
)
|
151
|
-
.build()
|
152
|
-
)
|
@@ -1,8 +1,10 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
+
|
2
3
|
from typing import Optional
|
4
|
+
|
3
5
|
from pydantic import BaseModel
|
4
6
|
|
5
|
-
from notionary.
|
7
|
+
from notionary.markdown.markdown_node import MarkdownNode
|
6
8
|
|
7
9
|
|
8
10
|
class AudioMarkdownBlockParams(BaseModel):
|
@@ -1,59 +1,10 @@
|
|
1
|
-
from typing import
|
2
|
-
from pydantic import BaseModel
|
3
|
-
|
4
|
-
from notionary.blocks.shared.models import RichTextObject
|
5
|
-
|
6
|
-
|
7
|
-
# TODO: Diesen Kram hier auch verwenden
|
8
|
-
class ExternalAudioSource(BaseModel):
|
9
|
-
"""External audio source."""
|
10
|
-
|
11
|
-
url: str
|
12
|
-
|
13
|
-
|
14
|
-
class NotionAudioData(BaseModel):
|
15
|
-
"""Audio block data."""
|
16
|
-
|
17
|
-
type: str = "external"
|
18
|
-
external: ExternalAudioSource
|
19
|
-
caption: list[dict] = []
|
1
|
+
from typing import Literal
|
20
2
|
|
3
|
+
from pydantic import BaseModel
|
21
4
|
|
22
|
-
|
23
|
-
"""Audio block result."""
|
24
|
-
|
25
|
-
type: str = "audio"
|
26
|
-
audio: NotionAudioData
|
27
|
-
|
28
|
-
|
29
|
-
# Updated method with typed return
|
30
|
-
@classmethod
|
31
|
-
def markdown_to_notion(cls, text: str) -> Optional[NotionAudioBlock]:
|
32
|
-
"""Convert markdown audio embed to Notion audio block."""
|
33
|
-
audio_match = cls.PATTERN.match(text.strip())
|
34
|
-
if not audio_match:
|
35
|
-
return None
|
36
|
-
|
37
|
-
url = audio_match.group(1)
|
38
|
-
caption_text = audio_match.group(2)
|
39
|
-
|
40
|
-
if not url:
|
41
|
-
return None
|
42
|
-
|
43
|
-
# Validate URL if possible
|
44
|
-
if not cls._is_likely_audio_url(url):
|
45
|
-
# Still proceed - user might know better
|
46
|
-
pass
|
5
|
+
from notionary.blocks.file.file_element_models import FileBlock
|
47
6
|
|
48
|
-
# Build caption list
|
49
|
-
caption_list = []
|
50
|
-
if caption_text:
|
51
|
-
caption_rich_text = RichTextObject.from_plain_text(caption_text)
|
52
|
-
caption_list = [caption_rich_text.model_dump()]
|
53
7
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
external=ExternalAudioSource(url=url), caption=caption_list
|
58
|
-
)
|
59
|
-
)
|
8
|
+
class CreateAudioBlock(BaseModel):
|
9
|
+
type: Literal["audio"] = "audio"
|
10
|
+
audio: FileBlock
|