blob: d74d27eaf1e2a0d16768967bce22f614877ba665 [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)))));
avm99963691c2bf2018-10-18 22:55:09 +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);
avm99963691c2bf2018-10-18 22:55:09 +0200180 } else { // This code shows a table if the user has a screen, and
181 // as of now tables are finally public!
avm99963cbcae352018-09-26 16:16:37 +0200182 $people = array_keys($neighbors);
183 $people_string = comma($people);
184 $params["edges"] = $people_string;
185 $num = mt_rand(1, 3);
186 conv::ask_followup($i18n->msg("edges_".$num, $params), $i18n);
avm99963691c2bf2018-10-18 22:55:09 +0200187 }
avm99963cbcae352018-09-26 16:16:37 +0200188 }
189 } else {
190 conv::ask_followup($i18n->msg("not_found", array("person" => $json["queryResult"]["parameters"]["Vertex"])), $i18n);
191 }
192 break;
193
194 case "randomFact":
195 $rand = mt_rand(0, 5);
196 switch ($rand) {
197 case 0: // Last edge in the graph
198 $last = array_values(array_slice($graph["edges"], -1))[0];
199 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);
200 break;
201
202 case 1: // Num vertices
203 conv::ask_followup($i18n->msg("didyouknow_num_vertices", array("count" => count($graph["nodes"]))), $i18n);
204 break;
205
206 case 2: // Num edges
207 conv::ask_followup($i18n->msg("didyouknow_num_edges", array("count" => count($graph["edges"]))), $i18n);
208 break;
209
210 case 3: // First 3 vertices K3
211 conv::ask_followup($i18n->msg("random_fact", array("fact" => $i18n->msg("didyouknow_k3"))), $i18n);
212 break;
213
214 case 4: // Creator
215 conv::ask_followup($i18n->msg("didyouknow_creator"), $i18n);
216 break;
217
218 case 5: // Groph
219 conv::ask_followup($i18n->msg("random_fact", array("fact" => $i18n->msg("didyouknow_groph"))), $i18n);
220 break;
221 }
222
223 break;
224
225 case "numVertexs":
226 conv::ask_followup($i18n->msg("num_vertices", array("count" => count($graph["nodes"]))), $i18n);
227 break;
228
229 case "numEdges":
230 conv::ask_followup($i18n->msg("num_edges", array("count" => count($graph["edges"]))), $i18n);
231 break;
232
233 case "latestNews":
234 $param = (isset($json["queryResult"]["parameters"]["numEdges"]) ? $json["queryResult"]["parameters"]["numEdges"] : null);
235 $num = (isset($param) && !empty($param) ? (int)$param : 4);
236 $last = array_values(array_slice($graph["edges"], -$num));
237 $edges = [];
238 foreach ($last as $edge) {
239 $edges[] = $graph["nodes"][$edge["a"]]["name"]." - ".$graph["nodes"][$edge["b"]]["name"];
240 }
241 $edges_string = comma($edges, true);
242 conv::ask_followup($i18n->msg((isset($param) && !empty($param) ? "latest_news_count" : "latest_news"), array("edges" => $edges_string, "count" => $num)), $i18n);
243 break;
244
245 default:
246 exit();
247}