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 289 : mlagent_get_model_path_from (const GValue * val)
34 : {
35 289 : g_autofree gchar *scheme = NULL;
36 289 : g_autofree gchar *uri = g_value_dup_string (val);
37 289 : GError *err = NULL;
38 : gchar *uri_hier_part;
39 : gchar **parts;
40 :
41 289 : if (!uri)
42 0 : return NULL;
43 :
44 : /** Common checker for the given URI */
45 289 : scheme = g_uri_parse_scheme (uri);
46 289 : if (!scheme || g_strcmp0 (URI_SCHEME, scheme)) {
47 280 : return g_steal_pointer (&uri);
48 : }
49 :
50 9 : uri_hier_part = g_strstr_len (uri, -1, ":");
51 36 : while (*uri_hier_part == ':' || *uri_hier_part == '/') {
52 27 : uri_hier_part++;
53 : }
54 :
55 : /**
56 : * @note Only for the following URI formats to get the file path of
57 : * the matching models are currently supported.
58 : * mlagent://model/name or mlagent://model/name/version
59 : *
60 : * It is required to be revised to support more scenarios
61 : * that exploit the ML Agent.
62 : */
63 9 : parts = g_strsplit_set (uri_hier_part, "/", 0);
64 : {
65 : enum MODEL_PART_CONSTANTS
66 : {
67 : MODEL_PART_IDX_NAME = 1,
68 : MODEL_PART_IDX_VERSION = 2,
69 : MODEL_VERSION_MIN = 1,
70 : MODEL_VERSION_MAX = 255,
71 : };
72 9 : const size_t NUM_PARTS_MODEL = 3;
73 : size_t num_parts;
74 :
75 9 : num_parts = g_strv_length (parts);
76 9 : if (num_parts == 0) {
77 0 : goto fallback;
78 : }
79 :
80 9 : if (!g_strcmp0 (parts[0], URI_KEYWORD_MODEL)) {
81 : /** Convert the given URI for a model to the file path */
82 9 : g_autofree gchar *name = g_strdup (parts[MODEL_PART_IDX_NAME]);
83 9 : g_autofree gchar *stringified_json = NULL;
84 9 : g_autoptr (JsonParser) json_parser = NULL;
85 : gint rcode;
86 :
87 9 : if (num_parts < NUM_PARTS_MODEL - 1) {
88 0 : goto fallback;
89 : }
90 :
91 : /**
92 : * @todo The specification of the data layout filled in the third
93 : * argument (i.e., stringified_json) by the callee is not fully decided.
94 : */
95 9 : if (num_parts == NUM_PARTS_MODEL - 1) {
96 4 : rcode = ml_agent_model_get_activated (name, &stringified_json);
97 : } else {
98 5 : guint version = strtoul (parts[MODEL_PART_IDX_VERSION], NULL, 10);
99 5 : rcode = ml_agent_model_get (name, version, &stringified_json);
100 : }
101 :
102 9 : if (rcode != 0) {
103 1 : nns_loge
104 : ("Failed to get the stringified JSON using the given URI(%s)", uri);
105 1 : goto fallback;
106 : }
107 :
108 8 : json_parser = json_parser_new ();
109 : /** @todo Parse stringified_json to get the model's path */
110 8 : if (!json_parser_load_from_data (json_parser, stringified_json, -1, &err)) {
111 0 : nns_loge ("Failed to parse the stringified JSON while "
112 : "get the model's path: %s",
113 : (err ? err->message : "unknown reason"));
114 0 : goto fallback;
115 : }
116 8 : g_clear_error (&err);
117 :
118 : {
119 8 : const gchar *path = NULL;
120 : JsonNode *jroot;
121 : JsonObject *jobj;
122 :
123 8 : jroot = json_parser_get_root (json_parser);
124 8 : if (jroot == NULL) {
125 0 : nns_loge ("Failed to get JSON root node while get the model's path");
126 0 : goto fallback;
127 : }
128 :
129 8 : jobj = json_node_get_object (jroot);
130 8 : if (jobj == NULL) {
131 0 : nns_loge
132 : ("Failed to get JSON object from the root node while get the model's path");
133 0 : goto fallback;
134 : }
135 :
136 8 : if (!json_object_has_member (jobj, JSON_KEY_MODEL_PATH)) {
137 0 : nns_loge
138 : ("Failed to get the model's path from the given URI: "
139 : "There is no key named, %s, in the JSON object",
140 : JSON_KEY_MODEL_PATH);
141 0 : goto fallback;
142 : }
143 :
144 8 : path = json_object_get_string_member (jobj, JSON_KEY_MODEL_PATH);
145 8 : if (path == NULL || !g_strcmp0 (path, "")) {
146 0 : nns_loge
147 : ("Failed to get the model's path from the given URI: "
148 : "Invalid value for the key, %s", JSON_KEY_MODEL_PATH);
149 0 : goto fallback;
150 : }
151 :
152 8 : g_strfreev (parts);
153 8 : return g_strdup (path);
154 : }
155 : }
156 : }
157 :
158 0 : fallback:
159 1 : g_clear_error (&err);
160 1 : g_strfreev (parts);
161 :
162 2 : return g_strdup (uri);
163 : }
|