blob: 15b6f79a0c73215b318dbe6d41edd09b09746085 [file] [log] [blame]
avm99963cbcae352018-09-26 16:16:37 +02001<?php
2require_once("config.php");
3
4class write {
5 public static function do($json) {
6 echo json_encode($json)."\n";
7 exit();
8 }
9}
10
11class conv {
12 public static function ask($msg_array) {
13 $items = array();
14
15 foreach ($msg_array as $msg) {
16 $items[] = array("simpleResponse" => array("textToSpeech" => $msg));
17 }
18
19 self::ask_custom($items);
20 }
21
22 public static function ask_followup($msg, &$i18n) {
23 self::ask([$msg, $i18n->msg("followup_".mt_rand(1, 3))]);
24 }
25
26 public static function ask_custom($items) {
27 $json = array();
28 $json["payload"] = array();
29 $json["payload"]["google"] = array();
30 $json["payload"]["google"]["expectUserResponse"] = true;
31 $json["payload"]["google"]["richResponse"] = array();
32 $json["payload"]["google"]["richResponse"]["items"] = $items;
33
34 write::do($json);
35 }
36
37 public static function has($item, &$json) {
38 foreach ($json["originalDetectIntentRequest"]["payload"]["surface"]["capabilities"] as $cap) {
39 if ($cap["name"] == $item) {
40 return true;
41 }
42 }
43 return false;
44 }
45}
46
47class i18n {
48 public static $hllist = array("en", "es");
49 public $i18n_strings = null;
50 public $language = null;
51
52 function __construct($lang) {
53 global $_GET;
54 global $conf;
55
56 if (empty($this->i18n_strings)) {
57 $this->i18n_strings = array();
58 }
59
60 $this->language = $lang;
61
62 $this->i18n_strings = json_decode(file_get_contents("assistant/".$this->language.".json"), true);
63
64 return true;
65 }
66
67 function msg($message, $strings = null) {
68 if (!isset($this->i18n_strings[$message])) {
69 return false;
70 }
71
72 $string = $this->i18n_strings[$message];
73
74 if ($strings != null && is_array($strings)) {
75 foreach ($strings as $i => $subst) {
76 $string = str_replace("{".$i."}", $subst, $string);
77 }
78 }
79
80 return $string;
81 }
82}
83
84function get_graph() {
85 global $conf;
86 return json_decode(file_get_contents($conf["apiurl"]), true);
87}
88
89function comma($array, $wait=false) {
90 global $i18n;
91 if (count($array) == 0) {
92 return "";
93 }
94 if (count($array) == 1) {
95 return $array[0];
96 }
97 $break = ($wait ? '<break time="0.5s"/>' : "");
98 return implode($break.", ", array_slice($array, 0, -1)).$break.", ".$i18n->msg("and")." ".$array[count($array)-1];
99}
100
101$json = json_decode(file_get_contents('php://input'), true);
102
103if ($json === NULL || !isset($json["originalDetectIntentRequest"]) || !isset($json["originalDetectIntentRequest"]["source"]) || $json["originalDetectIntentRequest"]["source"] != "google") {
104 exit();
105}
106
107$graph = get_graph();
108$lang = (isset($json["queryResult"]["languageCode"]) && in_array(substr($json["queryResult"]["languageCode"], 0, 2), i18n::$hllist) ? substr($json["queryResult"]["languageCode"], 0, 2) : "en");
109$i18n = new i18n($lang);
110
111switch ($json["queryResult"]["intent"]["displayName"]) {
112 case "showVertex":
113 if (!isset($json["queryResult"]["parameters"]["Vertex"])) {
114 exit();
115 }
116
117 $shortest = -1;
118 $closest = -1;
119 $closest_id = -1;
120
121 foreach ($graph["nodes"] as $id => $node) {
122 $lev = levenshtein(strtolower($json["queryResult"]["parameters"]["Vertex"]), strtolower($node["name"]));
123
124 if ($lev == 0) {
125 $closest = $node["name"];
126 $shortest = $lev;
127 $closest_id = $id;
128 }
129
130 if (($lev <= $shortest || $shortest < 0) && $lev <= 3) {
131 $closest = $node["name"];
132 $shortest = $lev;
133 $closest_id = $id;
134 }
135 }
136
137 if ($shortest != -1) {
138 $neighbors = array();
139 // We're suposing each vertex has a different name. If not, this would get rid of some of the edges, but if two vertexs had the same name there would be no way to differentiate them anyway, so I think it's ok.
140 foreach ($graph["edges"] as $edge) {
141 if ($edge["a"] == $closest_id) {
142 $neighbors[$graph["nodes"][$edge["b"]]["name"]] = $edge["votes"];
143 } elseif ($edge["b"] == $closest_id) {
144 $neighbors[$graph["nodes"][$edge["a"]]["name"]] = $edge["votes"];
145 }
146 }
147 if (count($neighbors) == 0) {
148 conv::ask_followup($i18n->msg("new_to_graph", array("person" => $closest)), $i18n);
149 } else {
150 arsort($neighbors);
151 $params = array("person" => $closest, "count" => (count($neighbors) == 1 ? $i18n->msg("count_singular") : $i18n->msg("count_plural", array("count" => count($neighbors)))));
avm999636695f1b2018-10-18 23:06:19 +0200152 /*if (conv::has("actions.capability.SCREEN_OUTPUT", $json)) {
avm99963cbcae352018-09-26 16:16:37 +0200153 $items = [
154 array(
155 "simpleResponse" => array(
156 "textToSpeech" => $i18n->msg("edges_display", $params)
157 )
158 ),
159 array(
160 "tableCard" => array(
161 "columnProperties" => [
162 array(
163 "header" => "Adjacent vertex"
164 ),
165 array("header" => "Votes")
166 ],
167 "rows" => []
168 )
169 ),
170 array(
171 "simpleResponse" => array(
172 "textToSpeech" => $i18n->msg("followup_".mt_rand(1, 3))
173 )
174 )
175 ];
176 foreach ($neighbors as $neighbor => $votes) {
177 $items[1]["tableCard"]["rows"][] = array("cells" => [array("text" => $neighbor), array("text" => (string)$votes)]);
178 }
179 conv::ask_custom($items);
avm999636695f1b2018-10-18 23:06:19 +0200180 } else {*/ // This code shows a table if the user has a screen, but
181 // unfortunately tables are not public yet.
182 // @TODO: Uncomment when tables are out of developer preview.
avm99963cbcae352018-09-26 16:16:37 +0200183 $people = array_keys($neighbors);
184 $people_string = comma($people);
185 $params["edges"] = $people_string;
186 $num = mt_rand(1, 3);
187 conv::ask_followup($i18n->msg("edges_".$num, $params), $i18n);
avm999636695f1b2018-10-18 23:06:19 +0200188 /*}*/
avm99963cbcae352018-09-26 16:16:37 +0200189 }
190 } else {
191 conv::ask_followup($i18n->msg("not_found", array("person" => $json["queryResult"]["parameters"]["Vertex"])), $i18n);
192 }
193 break;
194
195 case "randomFact":
196 $rand = mt_rand(0, 5);
197 switch ($rand) {
198 case 0: // Last edge in the graph
199 $last = array_values(array_slice($graph["edges"], -1))[0];
200 conv::ask_followup($i18n->msg("random_fact", array("fact" => $i18n->msg("didyouknow_last_edge", array("person1" => $graph["nodes"][$last["a"]]["name"], "person2" => $graph["nodes"][$last["b"]]["name"])))), $i18n);
201 break;
202
203 case 1: // Num vertices
204 conv::ask_followup($i18n->msg("didyouknow_num_vertices", array("count" => count($graph["nodes"]))), $i18n);
205 break;
206
207 case 2: // Num edges
208 conv::ask_followup($i18n->msg("didyouknow_num_edges", array("count" => count($graph["edges"]))), $i18n);
209 break;
210
211 case 3: // First 3 vertices K3
212 conv::ask_followup($i18n->msg("random_fact", array("fact" => $i18n->msg("didyouknow_k3"))), $i18n);
213 break;
214
215 case 4: // Creator
216 conv::ask_followup($i18n->msg("didyouknow_creator"), $i18n);
217 break;
218
219 case 5: // Groph
220 conv::ask_followup($i18n->msg("random_fact", array("fact" => $i18n->msg("didyouknow_groph"))), $i18n);
221 break;
222 }
223
224 break;
225
226 case "numVertexs":
227 conv::ask_followup($i18n->msg("num_vertices", array("count" => count($graph["nodes"]))), $i18n);
228 break;
229
230 case "numEdges":
231 conv::ask_followup($i18n->msg("num_edges", array("count" => count($graph["edges"]))), $i18n);
232 break;
233
234 case "latestNews":
235 $param = (isset($json["queryResult"]["parameters"]["numEdges"]) ? $json["queryResult"]["parameters"]["numEdges"] : null);
236 $num = (isset($param) && !empty($param) ? (int)$param : 4);
237 $last = array_values(array_slice($graph["edges"], -$num));
238 $edges = [];
239 foreach ($last as $edge) {
240 $edges[] = $graph["nodes"][$edge["a"]]["name"]." - ".$graph["nodes"][$edge["b"]]["name"];
241 }
242 $edges_string = comma($edges, true);
243 conv::ask_followup($i18n->msg((isset($param) && !empty($param) ? "latest_news_count" : "latest_news"), array("edges" => $edges_string, "count" => $num)), $i18n);
244 break;
245
246 default:
247 exit();
248}