mistralrs_server_core/
openapi_doc.rs

1//! ## OpenAPI doc functionality.
2
3use utoipa::OpenApi;
4
5use crate::{
6    chat_completion::__path_chatcompletions,
7    completions::__path_completions,
8    handlers::{ReIsqRequest, __path_health, __path_models, __path_re_isq},
9    image_generation::__path_image_generation,
10    openai::{
11        AudioResponseFormat, ChatCompletionRequest, CompletionRequest, FunctionCalled, Grammar,
12        ImageGenerationRequest, JsonSchemaResponseFormat, Message, MessageContent,
13        MessageInnerContent, ModelObject, ModelObjects, ResponseFormat, SpeechGenerationRequest,
14        StopTokens, ToolCall,
15    },
16    speech_generation::__path_speech_generation,
17};
18use mistralrs_core::{
19    ApproximateUserLocation, Function, ImageGenerationResponseFormat, SearchContextSize, Tool,
20    ToolChoice, ToolType, WebSearchOptions, WebSearchUserLocation,
21};
22
23/// This is used to generate the OpenAPI docs.
24/// The mistral.rs server router will include these by default, but if you're
25/// including the mistral.rs server core into another project, you can generate the
26/// OpenAPI docs separately to merge with the other project OpenAPI docs.
27///
28/// ### Arguments
29/// * `base_path` - the base path of the mistral.rs server instance (in case the mistral.rs server is being included in another axum project)
30///
31/// ### Example
32/// ```ignore
33/// // MyApp
34/// use axum::{Router, routing::{get, post}};
35/// use utoipa::OpenApi;
36/// use utoipa_swagger_ui::SwaggerUi;
37/// use mistralrs_server_core::openapi_doc::get_openapi_doc;
38///
39/// #[derive(OpenApi)]
40/// #[openapi(
41///     paths(root, controllers::custom_chat),
42///     tags(
43///         (name = "hello", description = "Hello world endpoints")
44///     ),
45///     info(
46///         title = "Hello World API",
47///         version = "1.0.0",
48///         description = "A simple API that responds with a greeting"
49///     )
50/// )]
51/// struct ApiDoc;
52///
53/// let mistral_base_path = "/api/mistral";
54/// let mistral_doc = get_openapi_doc(Some(mistral_base_path));
55/// let mut api_docs = ApiDoc::openapi();
56/// api_docs.merge(mistral_doc);
57///
58/// let app = Router::new()
59///   .route("/", get(root))
60///   .merge(SwaggerUi::new("/api-docs").url("/api-docs/openapi.json", api_docs));
61/// ```
62pub fn get_openapi_doc(base_path: Option<&str>) -> utoipa::openapi::OpenApi {
63    #[derive(OpenApi)]
64    #[openapi(
65        paths(models, health, chatcompletions, completions, re_isq, image_generation, speech_generation),
66        components(schemas(
67            ApproximateUserLocation,
68            AudioResponseFormat,
69            ChatCompletionRequest,
70            CompletionRequest,
71            Function,
72            FunctionCalled,
73            Grammar,
74            ImageGenerationRequest,
75            ImageGenerationResponseFormat,
76            JsonSchemaResponseFormat,
77            Message,
78            MessageContent,
79            MessageInnerContent,
80            ModelObject,
81            ModelObjects,
82            ReIsqRequest,
83            ResponseFormat,
84            SearchContextSize,
85            SpeechGenerationRequest,
86            StopTokens,
87            Tool,
88            ToolCall,
89            ToolChoice,
90            ToolType,
91            WebSearchOptions,
92            WebSearchUserLocation
93        )),
94        tags(
95            (name = "Mistral.rs", description = "Mistral.rs API")
96        ),
97        info(
98            title = "Mistral.rs",
99            license(
100            name = "MIT",
101        )
102        )
103    )]
104    struct ApiDoc;
105
106    let mut doc = ApiDoc::openapi();
107
108    if let Some(prefix) = base_path {
109        if !prefix.is_empty() {
110            let mut prefixed_paths = utoipa::openapi::Paths::default();
111
112            let original_paths = std::mem::take(&mut doc.paths.paths);
113
114            for (path, item) in original_paths {
115                let prefixed_path = format!("{}{}", prefix, path);
116                prefixed_paths.paths.insert(prefixed_path, item);
117            }
118
119            prefixed_paths.extensions = doc.paths.extensions.clone();
120
121            doc.paths = prefixed_paths;
122        }
123    }
124
125    doc
126}