44
55import sqlmodel
66
7+ from app .business .info_base .relation import RelationManager
78from app .business .info_base .storage .main import StorageManager
89
910from app .schemas .info_base .main import SubGraphForm
10- from app .schemas .info_base .block import ResolverType , BlockModel
11+ from app .schemas .info_base .block import BlockID , ResolverType , BlockModel
1112from app .schemas .info_base .relation import RelationModel
1213from app .schemas .info_base .storage import StorageID
1314
1415
1516class ResolverManager :
16- RESOLVERS : dict [ResolverType , type ["Resolver" ]] = {}
17+ RESOLVER_CLS : dict [ResolverType , type ["Resolver" ]] = {}
1718 """Global resolver registry.
1819
19- Map ResolverType to Resolver class
20- """
20+ Map ResolverType to Resolver class
21+ """
2122
2223 @classmethod
2324 def register_resolver (cls , resolver_cls : type ["Resolver" ]):
24- cls .RESOLVERS [resolver_cls .__rsotype__ ] = resolver_cls
25+ cls .RESOLVER_CLS [resolver_cls .__rsotype__ ] = resolver_cls
2526
2627 @classmethod
27- def new_resolver (cls , block : BlockModel ) -> "Resolver" :
28+ def get (cls , block : BlockModel ) -> "Resolver" :
2829 """Create resolver instance from block."""
2930 try :
30- resolver_cls = cls .RESOLVERS [block .resolver ]
31+ resolver_cls = cls .RESOLVER_CLS [block .resolver ]
3132 except KeyError :
32- raise NotImplementedError (f"Resolver { block .resolver } not implemented." )
33+ raise NotImplementedError (f"Resolver { block .resolver } not implemented/registered ." )
3334 return resolver_cls (block )
3435
3536
@@ -38,7 +39,12 @@ def new_resolver(cls, block: BlockModel) -> "Resolver":
3839
3940
4041class Resolver (abc .ABC , typing .Generic [SolvedContentTV , RawContentTV ]):
41- """Resolver resolves a star graph (a block and its direct relations)"""
42+ """Resolver resolves a star graph (a block and its direct relations)
43+
44+ Generic parameters:
45+ - SolvedContentTV: The type of the solved content
46+ - RawContentTV: The type of the raw content
47+ """
4248
4349 __rsotype__ : ResolverType
4450 """Resolver type"""
@@ -55,18 +61,67 @@ def __init__(self, block: BlockModel, relations: Opt[tuple[RelationModel, ...]]
5561 :param relations: Relations of the block.
5662 """
5763 self ._block = block
58- self ._relations = relations or tuple ()
59- self ._raw_content : RawContentTV
60- self ._solved_content : SolvedContentTV
61- self .__post_init__ ()
64+ self .__relations = relations or None
65+ self .__raw_content : RawContentTV | None = None
66+ """The (real) content of the block, commonly fetched from storage.
67+ If storage is None, uses block.content
68+ """
69+ if self ._block .storage is None :
70+ self .__raw_content = typing .cast (RawContentTV , self ._block .content )
71+ self .__solved_content : SolvedContentTV | None = None
72+ """Solved content is the content the resolver really works with,
73+ commonly from raw content.
74+ """
75+ self .__post_init__ (self .__raw_content )
6276
63- def __post_init__ (self ) :
77+ def __post_init__ (self , raw_content : Opt [ RawContentTV ] = None ) -> None :
6478 """Subclass post-initialization hook.
6579
66- It's suggest to resolve the block content to _solved_content here.
80+ It's suggest to set __solved_content here if possible:
81+ ```python
82+ async def __post_init__(self, raw_content):
83+ if raw_content is not None:
84+ ... # anyhow from raw_content
85+ self.set_solved_content(solved_content)
86+ ```
6787 """
6888 ...
6989
90+ @property
91+ def block_id (self ) -> BlockID :
92+ """Get the block ID."""
93+ return typing .cast (BlockID , self ._block .id )
94+
95+ async def get_raw_content (self ) -> RawContentTV :
96+ """Get the raw content of the block."""
97+ if self .__raw_content is None :
98+ if self ._block .storage is None :
99+ self .__raw_content = typing .cast (RawContentTV , self ._block .content )
100+ else :
101+ storage = StorageManager .get_storage (self ._block .storage )
102+ self .__raw_content = typing .cast (
103+ RawContentTV , await storage .get_raw_content (self ._block .content )
104+ )
105+
106+ return self .__raw_content
107+
108+ async def get_solved_content (self ) -> SolvedContentTV :
109+ """Get the solved content of the block."""
110+ if self .__solved_content is None :
111+ raise NotImplementedError (
112+ f"{ self .__class__ .__name__ } .get_solved_content() must be implemented by subclasses."
113+ )
114+ return self .__solved_content
115+
116+ def set_solved_content (self , content : SolvedContentTV ) -> None :
117+ self .__solved_content = content
118+
119+ async def get_relations (self ) -> tuple [RelationModel , ...]:
120+ """Get relations of the block."""
121+ if self .__relations is None :
122+ self .__relations = RelationManager .get (block_id = self .block_id )
123+ return self .__relations
124+
70125 @classmethod
71126 # @abc.abstractmethod TODO
72127 def create_block (cls , content , storage : Opt [StorageID ] = None ) -> BlockModel : ...
@@ -75,14 +130,15 @@ def create_block(cls, content, storage: Opt[StorageID] = None) -> BlockModel: ..
75130 # @abc.abstractmethod TODO
76131 def create_graph (cls , * args , ** kwargs ) -> SubGraphForm : ...
77132
133+ @abc .abstractmethod
78134 async def get_text (self ) -> str :
79135 """Get block content in text format."""
80- storage = StorageManager .new_storage (self ._block )
81- return await storage .get_content (self ._block )
136+ ...
82137
83- def get_str_for_embedding (self ) -> str :
138+ @abc .abstractmethod
139+ async def get_str_for_embedding (self ) -> str :
84140 """Get string representation for embedding generation."""
85- return self . _block . content
141+ ...
86142
87143 def get_existing (self , db_session : sqlmodel .Session ) -> Opt [BlockModel ]:
88144 """Check if a block with the same content already exists in the database.
0 commit comments