Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * Copyright (C) 2023 Wook Song <wook16.song@samsung.com>
4 : * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved.
5 : *
6 : *
7 : * @file ml_agent.c
8 : * @date 23 Jun 2023
9 : * @brief Internal helpers to make a bridge between NNS filters and the ML Agent service
10 : * @see http://github.com/nnstreamer/nnstreamer
11 : * @author wook16.song <wook16.song@samsung.com>
12 : * @bug No known bugs except for NYI items
13 : */
14 :
15 : #include <json-glib/json-glib.h>
16 : #include <nnstreamer_log.h>
17 : #include <mlops-agent-interface.h>
18 :
19 : #include "ml_agent.h"
20 :
21 : const gchar URI_SCHEME[] = "mlagent";
22 : const gchar URI_KEYWORD_MODEL[] = "model";
23 : const gchar JSON_KEY_MODEL_PATH[] = "path";
24 :
25 : /**
26 : * @brief Get a path of the model file from a given GValue
27 : * @param[in] val A pointer to a GValue holding a G_TYPE_STRING value
28 : * @return A newly allocated c-string representing the model file path, if the given GValue contains a valid URI
29 : * Otherwise, it simply returns a duplicated (strdup'ed) c-string that the val contains.
30 : * @note The caller should free the return c-string after using it.
31 : */
32 : gchar *
33 297 : mlagent_get_model_path_from (const GValue * val)
34 : {
35 297 : g_autofree gchar *scheme = NULL;
36 297 : g_autofree gchar *uri = g_value_dup_string (val);
37 297 : GError *err = NULL;
38 : gchar *uri_hier_part;
39 : gchar **parts;
40 :
41 297 : if (!uri)
42 0 : return NULL;
43 :
44 : /** Common checker for the given URI */
45 297 : scheme = g_uri_parse_scheme (uri);
46 297 : if (!scheme || g_strcmp0 (URI_SCHEME, scheme)) {
47 288 : return g_steal_pointer (&uri);
48 : }
49 :
50 9 : uri_hier_part = g_strstr_len (uri, -1, ":");
51 9 : if (!uri_hier_part)
52 0 : return NULL;
53 :
54 36 : while (*uri_hier_part == ':' || *uri_hier_part == '/') {
55 27 : uri_hier_part++;
56 : }
57 :
58 : /**
59 : * @note Only for the following URI formats to get the file path of
60 : * the matching models are currently supported.
61 : * mlagent://model/name or mlagent://model/name/version
62 : *
63 : * It is required to be revised to support more scenarios
64 : * that exploit the ML Agent.
65 : */
66 9 : parts = g_strsplit_set (uri_hier_part, "/", 0);
67 : {
68 : enum MODEL_PART_CONSTANTS
69 : {
70 : MODEL_PART_IDX_NAME = 1,
71 : MODEL_PART_IDX_VERSION = 2,
72 : MODEL_VERSION_MIN = 1,
73 : MODEL_VERSION_MAX = 255,
74 : };
75 9 : const size_t NUM_PARTS_MODEL = 3;
76 : size_t num_parts;
77 :
78 9 : num_parts = g_strv_length (parts);
79 9 : if (num_parts == 0) {
80 0 : goto fallback;
81 : }
82 :
83 9 : if (!g_strcmp0 (parts[0], URI_KEYWORD_MODEL)) {
84 : /** Convert the given URI for a model to the file path */
85 9 : g_autofree gchar *name = g_strdup (parts[MODEL_PART_IDX_NAME]);
86 9 : g_autofree gchar *stringified_json = NULL;
87 9 : g_autoptr (JsonParser) json_parser = NULL;
88 : gint rcode;
89 :
90 9 : if (num_parts < NUM_PARTS_MODEL - 1) {
91 0 : goto fallback;
92 : }
93 :
94 : /**
95 : * @todo The specification of the data layout filled in the third
96 : * argument (i.e., stringified_json) by the callee is not fully decided.
97 : */
98 9 : if (num_parts == NUM_PARTS_MODEL - 1) {
99 4 : rcode = ml_agent_model_get_activated (name, &stringified_json);
100 : } else {
101 5 : guint version = strtoul (parts[MODEL_PART_IDX_VERSION], NULL, 10);
102 5 : rcode = ml_agent_model_get (name, version, &stringified_json);
103 : }
104 :
105 9 : if (rcode != 0) {
106 1 : nns_loge
107 : ("Failed to get the stringified JSON using the given URI(%s)", uri);
108 1 : goto fallback;
109 : }
110 :
111 8 : json_parser = json_parser_new ();
112 : /** @todo Parse stringified_json to get the model's path */
113 8 : if (!json_parser_load_from_data (json_parser, stringified_json, -1, &err)) {
114 0 : nns_loge ("Failed to parse the stringified JSON while "
115 : "get the model's path: %s",
116 : (err ? err->message : "unknown reason"));
117 0 : goto fallback;
118 : }
119 8 : g_clear_error (&err);
120 :
121 : {
122 8 : const gchar *path = NULL;
123 : JsonNode *jroot;
124 : JsonObject *jobj;
125 :
126 8 : jroot = json_parser_get_root (json_parser);
127 8 : if (jroot == NULL) {
128 0 : nns_loge ("Failed to get JSON root node while get the model's path");
129 0 : goto fallback;
130 : }
131 :
132 8 : jobj = json_node_get_object (jroot);
133 8 : if (jobj == NULL) {
134 0 : nns_loge
135 : ("Failed to get JSON object from the root node while get the model's path");
136 0 : goto fallback;
137 : }
138 :
139 8 : if (!json_object_has_member (jobj, JSON_KEY_MODEL_PATH)) {
140 0 : nns_loge
141 : ("Failed to get the model's path from the given URI: "
142 : "There is no key named, %s, in the JSON object",
143 : JSON_KEY_MODEL_PATH);
144 0 : goto fallback;
145 : }
146 :
147 8 : path = json_object_get_string_member (jobj, JSON_KEY_MODEL_PATH);
148 8 : if (path == NULL || !g_strcmp0 (path, "")) {
149 0 : nns_loge
150 : ("Failed to get the model's path from the given URI: "
151 : "Invalid value for the key, %s", JSON_KEY_MODEL_PATH);
152 0 : goto fallback;
153 : }
154 :
155 8 : g_strfreev (parts);
156 8 : return g_strdup (path);
157 : }
158 : }
159 : }
160 :
161 0 : fallback:
162 1 : g_clear_error (&err);
163 1 : g_strfreev (parts);
164 :
165 2 : return g_strdup (uri);
166 : }
|