1- from typing import List , Optional
1+ from typing import List
22
33import requests
44from fastapi import APIRouter
99
1010class SemanticMatchingService :
1111 """
12- Todo
12+ A Semantic Matching Service
13+
14+ It offers two operations:
15+
16+ :func:`~.SemanticMatchingService.post_matches` allows to post
17+ :class:`model.SemanticMatch`es to the :class:`~.SemanticMatchingService`.
18+
19+ :func:`~.SemanticMatchingService.get_matches` lets users get the
20+ :class:`model.SemanticMatch`es of the :class:`~.SemanticMatchingService`
21+ and the respective remote :class:`~.SemanticMatchingService`s.
22+
23+ Additionally, the internal function
24+ :func:`~.SemanticMatchingService._get_matcher_from_semantic_id` lets the
25+ :class:`~.SemanticMatchingService` find the suiting remote
26+ :class:`~.SemanticMatchingService`s to a given `semantic_id`.
1327 """
14- def __init__ (self , equivalences : model .EquivalenceTable ):
28+ def __init__ (
29+ self ,
30+ endpoint : str ,
31+ equivalences : model .EquivalenceTable
32+ ):
33+ """
34+ Initializer of :class:`~.SemanticMatchingService`
35+
36+ :ivar endpoint: The endpoint on which the service listens
37+ :ivar equivalences: The :class:`model.EquivalenceTable` of the semantic
38+ equivalences that this :class:`~.SemanticMatchingService` contains.
39+ """
1540 self .router = APIRouter ()
1641 self .router .add_api_route (
17- "/get_match " ,
42+ "/get_matches " ,
1843 self .get_matches ,
1944 methods = ["GET" ]
2045 )
46+ self .router .add_api_route (
47+ "/post_matches" ,
48+ self .post_matches ,
49+ methods = ["POST" ]
50+ )
51+ self .endpoint : str = endpoint
2152 self .equivalence_table : model .EquivalenceTable = equivalences
2253
2354 def get_matches (
2455 self ,
2556 request_body : service_model .MatchRequest
26- ) -> service_model .MatchResponse :
57+ ) -> service_model .MatchesList :
2758 """
2859 A query to match two SubmodelElements semantically.
2960
@@ -36,7 +67,7 @@ def get_matches(
3667 )
3768 # If the request asks us to only locally look, we're done already
3869 if request_body .local_only :
39- return service_model .MatchResponse (matches = matches )
70+ return service_model .MatchesList (matches = matches )
4071 # Now look for remote matches:
4172 additional_remote_matches : List [model .SemanticMatch ] = []
4273 for match in matches :
@@ -56,18 +87,59 @@ def get_matches(
5687 definition = request_body .definition
5788 )
5889 new_matches_response = requests .get (remote_matching_service , data = remote_matching_request )
59- match_response : service_model .MatchResponse = service_model .MatchResponse . model_dump_json (
90+ match_response : service_model .MatchesList = service_model .MatchesList . model_validate_json (
6091 new_matches_response .json ()
6192 )
6293 additional_remote_matches .extend (match_response .matches )
6394 # Finally, put all matches together and return
6495 matches .extend (additional_remote_matches )
65- return service_model .MatchResponse (matches = matches )
96+ return service_model .MatchesList (matches = matches )
97+
98+ def post_matches (
99+ self ,
100+ request_body : service_model .MatchesList
101+ ) -> None :
102+ for match in request_body .matches :
103+ self .equivalence_table .add_semantic_match (match )
104+ # Todo: Figure out how to properly return 200
66105
67106 def _get_matcher_from_semantic_id (self , semantic_id : str ) -> str :
68107 """
69108 Finds the suiting `SemanticMatchingService` for the given `semantic_id`.
70109
71110 :returns: The endpoint with which the `SemanticMatchingService` can be accessed
72111 """
73- return "Todo" # todo
112+ return self .endpoint # todo
113+
114+
115+ if __name__ == '__main__' :
116+ import os
117+ import configparser
118+ from fastapi import FastAPI
119+ import uvicorn
120+
121+ config = configparser .ConfigParser ()
122+ config .read ([
123+ os .path .abspath (os .path .join (os .path .dirname (__file__ ), "../config.ini.default" )),
124+ os .path .abspath (os .path .join (os .path .dirname (__file__ ), "../config.ini" )),
125+ ])
126+
127+ # Read in equivalence table
128+ # Note, this construct takes the path in the config.ini relative to the
129+ # location of the config.ini
130+ EQUIVALENCES = model .EquivalenceTable .from_file (
131+ filename = os .path .abspath (os .path .join (
132+ os .path .dirname (__file__ ),
133+ ".." ,
134+ config ["SERVICE" ]["equivalence_table_file" ]
135+ ))
136+ )
137+ SEMANTIC_MATCHING_SERVICE = SemanticMatchingService (
138+ endpoint = config ["SERVICE" ]["endpoint" ],
139+ equivalences = EQUIVALENCES
140+ )
141+ APP = FastAPI ()
142+ APP .include_router (
143+ SEMANTIC_MATCHING_SERVICE .router
144+ )
145+ uvicorn .run (APP , host = "127.0.0.1" , port = int (config ["SERVICE" ]["PORT" ]))
0 commit comments