Skip to content

Commit 8663579

Browse files
authored
Merge pull request #21 from ks6088ts-labs/feature/issue-19_generate-client-library-via-kiota
generate client library via kiota
2 parents b5b1f7d + 9504355 commit 8663579

21 files changed

+1326
-9
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ repos:
1313
rev: 24.2.0
1414
hooks:
1515
- id: black
16+
exclude: 'client/.*'

Makefile

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ format: ## format code
3030
poetry run isort .
3131
poetry run black . --verbose
3232

33+
.PHONY: fix
34+
fix: format ## apply auto-fixes
35+
poetry run ruff check --fix
36+
3337
.PHONY: lint
3438
lint: ## lint
3539
poetry run ruff check .
@@ -81,7 +85,7 @@ ci-test-docker: docker-lint docker-build docker-scan docker-run ## run CI test f
8185
# ---
8286
# Application
8387
# ---
84-
SOLUTION_NAME ?= "DEFAULT"
88+
SOLUTION_NAME ?= "SANDBOX"
8589

8690
.PHONY: backend
8791
backend: ## run backend
@@ -114,3 +118,21 @@ azure-functions-functionapp-deploy: ## deploy Azure Functions App
114118
--with backend,azure-functions \
115119
--without-hashes
116120
func azure functionapp publish $(shell jq -r '.FUNCTION_APP_NAME' < azure-functions.json)
121+
122+
# ---
123+
# OpenAPI Client
124+
# ---
125+
.PHONY: generate-openapi-spec
126+
generate-openapi-spec: ## generate OpenAPI spec
127+
poetry run python main.py generate-openapi-spec
128+
129+
.PHONY: generate-openapi-client
130+
generate-openapi-client: ## generate OpenAPI client
131+
@kiota generate \
132+
--language Python \
133+
--class-name ApiClient \
134+
--namespace-name client \
135+
--openapi ./specs/openapi.json \
136+
--output ./client
137+
@echo "Get the list of dependencies"
138+
@kiota info -d ./specs/openapi.json --language Python

backend/fastapi.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from fastapi import FastAPI
2+
from fastapi.openapi.utils import get_openapi
23

34
from backend.routers import azure_openai as azure_openai_router
45
from backend.routers import document_intelligence as document_intelligence_router
@@ -9,3 +10,29 @@
910

1011
app.include_router(azure_openai_router.router)
1112
app.include_router(document_intelligence_router.router)
13+
14+
15+
def custom_openapi():
16+
if app.openapi_schema:
17+
return app.openapi_schema
18+
openapi_schema = get_openapi(
19+
title="Azure AI Services Solutions",
20+
version="0.0.1",
21+
description="This contains a collection of solutions that leverage Azure AI services.",
22+
routes=app.routes,
23+
servers=[
24+
{
25+
"url": "http://localhost:8000",
26+
}
27+
],
28+
)
29+
openapi_schema["info"]["x-logo"] = {
30+
"url": "https://news.microsoft.com/wp-content/uploads/prod/2022/05/Microsoft-logo_rgb_c-gray-1024x459.png"
31+
}
32+
openapi_schema["openapi"] = "3.0.0"
33+
app.openapi_schema = openapi_schema
34+
return app.openapi_schema
35+
36+
37+
app.openapi_version = "3.0.0" # to use Kiota, downgrade to 3.0.0 (ref. https://github.com/microsoft/kiota/issues/3914)
38+
app.openapi = custom_openapi

client/api_client.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from __future__ import annotations
2+
from kiota_abstractions.api_client_builder import enable_backing_store_for_serialization_writer_factory, register_default_deserializer, register_default_serializer
3+
from kiota_abstractions.base_request_builder import BaseRequestBuilder
4+
from kiota_abstractions.get_path_parameters import get_path_parameters
5+
from kiota_abstractions.request_adapter import RequestAdapter
6+
from kiota_abstractions.serialization import ParseNodeFactoryRegistry, SerializationWriterFactoryRegistry
7+
from kiota_serialization_form.form_parse_node_factory import FormParseNodeFactory
8+
from kiota_serialization_form.form_serialization_writer_factory import FormSerializationWriterFactory
9+
from kiota_serialization_json.json_parse_node_factory import JsonParseNodeFactory
10+
from kiota_serialization_json.json_serialization_writer_factory import JsonSerializationWriterFactory
11+
from kiota_serialization_multipart.multipart_serialization_writer_factory import MultipartSerializationWriterFactory
12+
from kiota_serialization_text.text_parse_node_factory import TextParseNodeFactory
13+
from kiota_serialization_text.text_serialization_writer_factory import TextSerializationWriterFactory
14+
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union
15+
16+
if TYPE_CHECKING:
17+
from .azure_openai.azure_openai_request_builder import Azure_openaiRequestBuilder
18+
from .document_intelligence.document_intelligence_request_builder import Document_intelligenceRequestBuilder
19+
20+
class ApiClient(BaseRequestBuilder):
21+
"""
22+
The main entry point of the SDK, exposes the configuration and the fluent API.
23+
"""
24+
def __init__(self,request_adapter: RequestAdapter) -> None:
25+
"""
26+
Instantiates a new ApiClient and sets the default values.
27+
param request_adapter: The request adapter to use to execute the requests.
28+
Returns: None
29+
"""
30+
if not request_adapter:
31+
raise TypeError("request_adapter cannot be null.")
32+
super().__init__(request_adapter, "{+baseurl}", None)
33+
register_default_serializer(JsonSerializationWriterFactory)
34+
register_default_serializer(TextSerializationWriterFactory)
35+
register_default_serializer(FormSerializationWriterFactory)
36+
register_default_serializer(MultipartSerializationWriterFactory)
37+
register_default_deserializer(JsonParseNodeFactory)
38+
register_default_deserializer(TextParseNodeFactory)
39+
register_default_deserializer(FormParseNodeFactory)
40+
if not self.request_adapter.base_url:
41+
self.request_adapter.base_url = "http://localhost:8000"
42+
self.path_parameters["base_url"] = self.request_adapter.base_url
43+
44+
@property
45+
def azure_openai(self) -> Azure_openaiRequestBuilder:
46+
"""
47+
The azure_openai property
48+
"""
49+
from .azure_openai.azure_openai_request_builder import Azure_openaiRequestBuilder
50+
51+
return Azure_openaiRequestBuilder(self.request_adapter, self.path_parameters)
52+
53+
@property
54+
def document_intelligence(self) -> Document_intelligenceRequestBuilder:
55+
"""
56+
The document_intelligence property
57+
"""
58+
from .document_intelligence.document_intelligence_request_builder import Document_intelligenceRequestBuilder
59+
60+
return Document_intelligenceRequestBuilder(self.request_adapter, self.path_parameters)
61+
62+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from __future__ import annotations
2+
from kiota_abstractions.base_request_builder import BaseRequestBuilder
3+
from kiota_abstractions.get_path_parameters import get_path_parameters
4+
from kiota_abstractions.request_adapter import RequestAdapter
5+
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union
6+
7+
if TYPE_CHECKING:
8+
from .chat_completions.chat_completions_request_builder import Chat_completionsRequestBuilder
9+
10+
class Azure_openaiRequestBuilder(BaseRequestBuilder):
11+
"""
12+
Builds and executes requests for operations under /azure_openai
13+
"""
14+
def __init__(self,request_adapter: RequestAdapter, path_parameters: Union[str, Dict[str, Any]]) -> None:
15+
"""
16+
Instantiates a new Azure_openaiRequestBuilder and sets the default values.
17+
param path_parameters: The raw url or the url-template parameters for the request.
18+
param request_adapter: The request adapter to use to execute the requests.
19+
Returns: None
20+
"""
21+
super().__init__(request_adapter, "{+baseurl}/azure_openai", path_parameters)
22+
23+
@property
24+
def chat_completions(self) -> Chat_completionsRequestBuilder:
25+
"""
26+
The chat_completions property
27+
"""
28+
from .chat_completions.chat_completions_request_builder import Chat_completionsRequestBuilder
29+
30+
return Chat_completionsRequestBuilder(self.request_adapter, self.path_parameters)
31+
32+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from __future__ import annotations
2+
from kiota_abstractions.base_request_builder import BaseRequestBuilder
3+
from kiota_abstractions.base_request_configuration import RequestConfiguration
4+
from kiota_abstractions.get_path_parameters import get_path_parameters
5+
from kiota_abstractions.method import Method
6+
from kiota_abstractions.request_adapter import RequestAdapter
7+
from kiota_abstractions.request_information import RequestInformation
8+
from kiota_abstractions.request_option import RequestOption
9+
from kiota_abstractions.serialization import Parsable, ParsableFactory
10+
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union
11+
12+
if TYPE_CHECKING:
13+
from ...models.chat_completion_request import ChatCompletionRequest
14+
from ...models.chat_completion_response import ChatCompletionResponse
15+
from ...models.h_t_t_p_validation_error import HTTPValidationError
16+
17+
class Chat_completionsRequestBuilder(BaseRequestBuilder):
18+
"""
19+
Builds and executes requests for operations under /azure_openai/chat_completions
20+
"""
21+
def __init__(self,request_adapter: RequestAdapter, path_parameters: Union[str, Dict[str, Any]]) -> None:
22+
"""
23+
Instantiates a new Chat_completionsRequestBuilder and sets the default values.
24+
param path_parameters: The raw url or the url-template parameters for the request.
25+
param request_adapter: The request adapter to use to execute the requests.
26+
Returns: None
27+
"""
28+
super().__init__(request_adapter, "{+baseurl}/azure_openai/chat_completions", path_parameters)
29+
30+
async def post(self,body: Optional[ChatCompletionRequest] = None, request_configuration: Optional[RequestConfiguration] = None) -> Optional[ChatCompletionResponse]:
31+
"""
32+
Create Chat Completions
33+
param body: The request body
34+
param request_configuration: Configuration for the request such as headers, query parameters, and middleware options.
35+
Returns: Optional[ChatCompletionResponse]
36+
"""
37+
if not body:
38+
raise TypeError("body cannot be null.")
39+
request_info = self.to_post_request_information(
40+
body, request_configuration
41+
)
42+
from ...models.h_t_t_p_validation_error import HTTPValidationError
43+
44+
error_mapping: Dict[str, ParsableFactory] = {
45+
"422": HTTPValidationError,
46+
}
47+
if not self.request_adapter:
48+
raise Exception("Http core is null")
49+
from ...models.chat_completion_response import ChatCompletionResponse
50+
51+
return await self.request_adapter.send_async(request_info, ChatCompletionResponse, error_mapping)
52+
53+
def to_post_request_information(self,body: Optional[ChatCompletionRequest] = None, request_configuration: Optional[RequestConfiguration] = None) -> RequestInformation:
54+
"""
55+
Create Chat Completions
56+
param body: The request body
57+
param request_configuration: Configuration for the request such as headers, query parameters, and middleware options.
58+
Returns: RequestInformation
59+
"""
60+
if not body:
61+
raise TypeError("body cannot be null.")
62+
request_info = RequestInformation(Method.POST, self.url_template, self.path_parameters)
63+
request_info.configure(request_configuration)
64+
request_info.headers.try_add("Accept", "application/json")
65+
request_info.set_content_from_parsable(self.request_adapter, "application/json", body)
66+
return request_info
67+
68+
def with_url(self,raw_url: Optional[str] = None) -> Chat_completionsRequestBuilder:
69+
"""
70+
Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
71+
param raw_url: The raw URL to use for the request builder.
72+
Returns: Chat_completionsRequestBuilder
73+
"""
74+
if not raw_url:
75+
raise TypeError("raw_url cannot be null.")
76+
return Chat_completionsRequestBuilder(self.request_adapter, raw_url)
77+
78+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from __future__ import annotations
2+
from kiota_abstractions.base_request_builder import BaseRequestBuilder
3+
from kiota_abstractions.base_request_configuration import RequestConfiguration
4+
from kiota_abstractions.get_path_parameters import get_path_parameters
5+
from kiota_abstractions.method import Method
6+
from kiota_abstractions.multipart_body import MultipartBody
7+
from kiota_abstractions.request_adapter import RequestAdapter
8+
from kiota_abstractions.request_information import RequestInformation
9+
from kiota_abstractions.request_option import RequestOption
10+
from kiota_abstractions.serialization import Parsable, ParsableFactory
11+
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union
12+
13+
if TYPE_CHECKING:
14+
from ...models.analyze_document_response import AnalyzeDocumentResponse
15+
from ...models.h_t_t_p_validation_error import HTTPValidationError
16+
17+
class Analyze_documentRequestBuilder(BaseRequestBuilder):
18+
"""
19+
Builds and executes requests for operations under /document_intelligence/analyze_document
20+
"""
21+
def __init__(self,request_adapter: RequestAdapter, path_parameters: Union[str, Dict[str, Any]]) -> None:
22+
"""
23+
Instantiates a new Analyze_documentRequestBuilder and sets the default values.
24+
param path_parameters: The raw url or the url-template parameters for the request.
25+
param request_adapter: The request adapter to use to execute the requests.
26+
Returns: None
27+
"""
28+
super().__init__(request_adapter, "{+baseurl}/document_intelligence/analyze_document", path_parameters)
29+
30+
async def post(self,body: Optional[MultipartBody] = None, request_configuration: Optional[RequestConfiguration] = None) -> Optional[AnalyzeDocumentResponse]:
31+
"""
32+
Analyze Document
33+
param body: The request body
34+
param request_configuration: Configuration for the request such as headers, query parameters, and middleware options.
35+
Returns: Optional[AnalyzeDocumentResponse]
36+
"""
37+
if not body:
38+
raise TypeError("body cannot be null.")
39+
request_info = self.to_post_request_information(
40+
body, request_configuration
41+
)
42+
from ...models.h_t_t_p_validation_error import HTTPValidationError
43+
44+
error_mapping: Dict[str, ParsableFactory] = {
45+
"422": HTTPValidationError,
46+
}
47+
if not self.request_adapter:
48+
raise Exception("Http core is null")
49+
from ...models.analyze_document_response import AnalyzeDocumentResponse
50+
51+
return await self.request_adapter.send_async(request_info, AnalyzeDocumentResponse, error_mapping)
52+
53+
def to_post_request_information(self,body: Optional[MultipartBody] = None, request_configuration: Optional[RequestConfiguration] = None) -> RequestInformation:
54+
"""
55+
Analyze Document
56+
param body: The request body
57+
param request_configuration: Configuration for the request such as headers, query parameters, and middleware options.
58+
Returns: RequestInformation
59+
"""
60+
if not body:
61+
raise TypeError("body cannot be null.")
62+
request_info = RequestInformation(Method.POST, self.url_template, self.path_parameters)
63+
request_info.configure(request_configuration)
64+
request_info.headers.try_add("Accept", "application/json")
65+
request_info.set_content_from_parsable(self.request_adapter, "multipart/form-data", body)
66+
return request_info
67+
68+
def with_url(self,raw_url: Optional[str] = None) -> Analyze_documentRequestBuilder:
69+
"""
70+
Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
71+
param raw_url: The raw URL to use for the request builder.
72+
Returns: Analyze_documentRequestBuilder
73+
"""
74+
if not raw_url:
75+
raise TypeError("raw_url cannot be null.")
76+
return Analyze_documentRequestBuilder(self.request_adapter, raw_url)
77+
78+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from __future__ import annotations
2+
from kiota_abstractions.base_request_builder import BaseRequestBuilder
3+
from kiota_abstractions.get_path_parameters import get_path_parameters
4+
from kiota_abstractions.request_adapter import RequestAdapter
5+
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union
6+
7+
if TYPE_CHECKING:
8+
from .analyze_document.analyze_document_request_builder import Analyze_documentRequestBuilder
9+
10+
class Document_intelligenceRequestBuilder(BaseRequestBuilder):
11+
"""
12+
Builds and executes requests for operations under /document_intelligence
13+
"""
14+
def __init__(self,request_adapter: RequestAdapter, path_parameters: Union[str, Dict[str, Any]]) -> None:
15+
"""
16+
Instantiates a new Document_intelligenceRequestBuilder and sets the default values.
17+
param path_parameters: The raw url or the url-template parameters for the request.
18+
param request_adapter: The request adapter to use to execute the requests.
19+
Returns: None
20+
"""
21+
super().__init__(request_adapter, "{+baseurl}/document_intelligence", path_parameters)
22+
23+
@property
24+
def analyze_document(self) -> Analyze_documentRequestBuilder:
25+
"""
26+
The analyze_document property
27+
"""
28+
from .analyze_document.analyze_document_request_builder import Analyze_documentRequestBuilder
29+
30+
return Analyze_documentRequestBuilder(self.request_adapter, self.path_parameters)
31+
32+

0 commit comments

Comments
 (0)