├── .gitattributes
├── .gitignore
├── AI-engine
├── config_mitie.json
├── config_spacy.json
├── data
│ ├── demo-rasa.json
│ └── sitebot-data.json
└── rasa_nlu_log.json
├── bot-application
├── app.py
├── extract.py
├── getSchedule.py
├── local_settings.py
├── models.py
├── response.py
├── static
│ ├── css
│ │ ├── chat_interface.css
│ │ ├── style.css
│ │ ├── style.css~
│ │ └── temporary.css
│ └── js
│ │ ├── bind.js
│ │ └── jquery.timeago.js
└── templates
│ ├── base.html
│ └── home.html
├── readme.md
└── requirements.txt
/.gitattributes:
--------------------------------------------------------------------------------
1 | static/* linguist-vendored
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | AI-engine/logs/*
3 | AI-engine/model_*
4 | bot-application/migrations
5 | *.db
6 | *.dat
7 | venv
8 | .idea
9 | models
10 |
--------------------------------------------------------------------------------
/AI-engine/config_mitie.json:
--------------------------------------------------------------------------------
1 | {
2 | "backend": "mitie",
3 | "mitie_file": "data/total_word_feature_extractor.dat",
4 | "path" : "./",
5 | "data" : "data/sitebot-data.json",
6 | "num_threads":100,
7 | "pipeline": "mitie"
8 | }
9 |
--------------------------------------------------------------------------------
/AI-engine/config_spacy.json:
--------------------------------------------------------------------------------
1 | {
2 | "backend": "spacy_sklearn",
3 | "path" : "./",
4 | "data" : "data/sitebot-data.json",
5 | "num_threads":100,
6 | "pipeline":"spacy_sklearn"
7 | }
8 |
--------------------------------------------------------------------------------
/AI-engine/data/demo-rasa.json:
--------------------------------------------------------------------------------
1 | {
2 | "rasa_nlu_data": {
3 | "entity_examples": [
4 | {
5 | "text": "hey",
6 | "intent": "greet",
7 | "entities": []
8 | },
9 | {
10 | "text": "howdy",
11 | "intent": "greet",
12 | "entities": []
13 | },
14 | {
15 | "text": "hey there",
16 | "intent": "greet",
17 | "entities": []
18 | },
19 | {
20 | "text": "hello",
21 | "intent": "greet",
22 | "entities": []
23 | },
24 | {
25 | "text": "hi",
26 | "intent": "greet",
27 | "entities": []
28 | },
29 | {
30 | "text": "i'm looking for a place to eat",
31 | "intent": "restaurant_search",
32 | "entities": []
33 | },
34 | {
35 | "text": "i'm looking for a place in the north of town",
36 | "intent": "restaurant_search",
37 | "entities": [
38 | {
39 | "start": 31,
40 | "end": 36,
41 | "value": "north",
42 | "entity": "location"
43 | }
44 | ]
45 | },
46 | {
47 | "text": "show me chinese restaurants",
48 | "intent": "restaurant_search",
49 | "entities": [
50 | {
51 | "start": 8,
52 | "end": 15,
53 | "value": "chinese",
54 | "entity": "cuisine"
55 | }
56 | ]
57 | },
58 | {
59 | "text": "yes",
60 | "intent": "affirm",
61 | "entities": []
62 | },
63 | {
64 | "text": "yep",
65 | "intent": "affirm",
66 | "entities": []
67 | },
68 | {
69 | "text": "yeah",
70 | "intent": "affirm",
71 | "entities": []
72 | },
73 | {
74 | "text": "show me a mexican place in the centre",
75 | "intent": "restaurant_search",
76 | "entities": [
77 | {
78 | "start": 31,
79 | "end": 37,
80 | "value": "centre",
81 | "entity": "location"
82 | },
83 | {
84 | "start": 10,
85 | "end": 17,
86 | "value": "mexican",
87 | "entity": "cuisine"
88 | }
89 | ]
90 | },
91 | {
92 | "text": "bye",
93 | "intent": "goodbye",
94 | "entities": []
95 | },
96 | {
97 | "text": "goodbye",
98 | "intent": "goodbye",
99 | "entities": []
100 | },
101 | {
102 | "text": "good bye",
103 | "intent": "goodbye",
104 | "entities": []
105 | },
106 | {
107 | "text": "stop",
108 | "intent": "goodbye",
109 | "entities": []
110 | },
111 | {
112 | "text": "end",
113 | "intent": "goodbye",
114 | "entities": []
115 | },
116 | {
117 | "text": "i am looking for an indian spot",
118 | "intent": "restaurant_search",
119 | "entities": [
120 | {
121 | "start": 20,
122 | "end": 26,
123 | "value": "indian",
124 | "entity": "cuisine"
125 | }
126 | ]
127 | },
128 | {
129 | "text": "search for restaurants",
130 | "intent": "restaurant_search",
131 | "entities": []
132 | },
133 | {
134 | "text": "anywhere in the west",
135 | "intent": "restaurant_search",
136 | "entities": [
137 | {
138 | "start": 16,
139 | "end": 20,
140 | "value": "west",
141 | "entity": "location"
142 | }
143 | ]
144 | },
145 | {
146 | "text": "central indian restaurant",
147 | "intent": "restaurant_search",
148 | "entities": [
149 | {
150 | "start": 0,
151 | "end": 7,
152 | "value": "central",
153 | "entity": "location"
154 | },
155 | {
156 | "start": 8,
157 | "end": 14,
158 | "value": "indian",
159 | "entity": "cuisine"
160 | }
161 | ]
162 | },
163 | {
164 | "text": "indeed",
165 | "intent": "affirm",
166 | "entities": []
167 | },
168 | {
169 | "text": "that's right",
170 | "intent": "affirm",
171 | "entities": []
172 | },
173 | {
174 | "text": "ok",
175 | "intent": "affirm",
176 | "entities": []
177 | },
178 | {
179 | "text": "great",
180 | "intent": "affirm",
181 | "entities": []
182 | }
183 | ],
184 | "intent_examples": [
185 | {
186 | "text": "hey",
187 | "intent": "greet"
188 | },
189 | {
190 | "text": "howdy",
191 | "intent": "greet"
192 | },
193 | {
194 | "text": "hey there",
195 | "intent": "greet"
196 | },
197 | {
198 | "text": "hello",
199 | "intent": "greet"
200 | },
201 | {
202 | "text": "hi",
203 | "intent": "greet"
204 | },
205 | {
206 | "text": "i'm looking for a place to eat",
207 | "intent": "restaurant_search"
208 | },
209 | {
210 | "text": "i'm looking for a place in the north of town",
211 | "intent": "restaurant_search"
212 | },
213 | {
214 | "text": "show me chinese restaurants",
215 | "intent": "restaurant_search"
216 | },
217 | {
218 | "text": "yes",
219 | "intent": "affirm"
220 | },
221 | {
222 | "text": "yep",
223 | "intent": "affirm"
224 | },
225 | {
226 | "text": "yeah",
227 | "intent": "affirm"
228 | },
229 | {
230 | "text": "show me a mexican place in the centre",
231 | "intent": "restaurant_search"
232 | },
233 | {
234 | "text": "bye",
235 | "intent": "goodbye"
236 | },
237 | {
238 | "text": "goodbye",
239 | "intent": "goodbye"
240 | },
241 | {
242 | "text": "good bye",
243 | "intent": "goodbye"
244 | },
245 | {
246 | "text": "stop",
247 | "intent": "goodbye"
248 | },
249 | {
250 | "text": "end",
251 | "intent": "goodbye"
252 | },
253 | {
254 | "text": "i am looking for an indian spot",
255 | "intent": "restaurant_search"
256 | },
257 | {
258 | "text": "search for restaurants",
259 | "intent": "restaurant_search"
260 | },
261 | {
262 | "text": "anywhere in the west",
263 | "intent": "restaurant_search"
264 | },
265 | {
266 | "text": "central indian restaurant",
267 | "intent": "restaurant_search"
268 | },
269 | {
270 | "text": "indeed",
271 | "intent": "affirm"
272 | },
273 | {
274 | "text": "that's right",
275 | "intent": "affirm"
276 | },
277 | {
278 | "text": "ok",
279 | "intent": "affirm"
280 | },
281 | {
282 | "text": "great",
283 | "intent": "affirm"
284 | }
285 | ]
286 | }
287 | }
--------------------------------------------------------------------------------
/AI-engine/data/sitebot-data.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "rasa_nlu_data": {
4 | "common_examples": [
5 | {
6 | "text": "who are you?",
7 | "intent": "intro",
8 | "entities": []
9 | },
10 | {
11 | "text": "what do you do?",
12 | "intent": "intro",
13 | "entities": []
14 | },
15 | {
16 | "text": "what can you do for me?",
17 | "intent": "intro",
18 | "entities": []
19 | },
20 | {
21 | "text": "hey",
22 | "intent": "greet",
23 | "entities": []
24 | },
25 | {
26 | "text": "hey",
27 | "intent": "greet",
28 | "entities": []
29 | },
30 | {
31 | "text": "howdy",
32 | "intent": "greet",
33 | "entities": []
34 | },
35 | {
36 | "text": "hey there",
37 | "intent": "greet",
38 | "entities": []
39 | },
40 | {
41 | "text": "hello",
42 | "intent": "greet",
43 | "entities": []
44 | },
45 | {
46 | "text": "hi",
47 | "intent": "greet",
48 | "entities": []
49 | },
50 | {
51 | "text": "yes",
52 | "intent": "affirm",
53 | "entities": []
54 | },
55 | {
56 | "text": "yep",
57 | "intent": "affirm",
58 | "entities": []
59 | },
60 | {
61 | "text": "yeah",
62 | "intent": "affirm",
63 | "entities": []
64 | },
65 | {
66 | "text": "bye",
67 | "intent": "goodbye",
68 | "entities": []
69 | },
70 | {
71 | "text": "goodbye",
72 | "intent": "goodbye",
73 | "entities": []
74 | },
75 | {
76 | "text": "good bye",
77 | "intent": "goodbye",
78 | "entities": []
79 | },
80 | {
81 | "text": "stop",
82 | "intent": "goodbye",
83 | "entities": []
84 | },
85 | {
86 | "text": "end",
87 | "intent": "goodbye",
88 | "entities": []
89 | },
90 | {
91 | "text": "indeed",
92 | "intent": "affirm",
93 | "entities": []
94 | },
95 | {
96 | "text": "that's right",
97 | "intent": "affirm",
98 | "entities": []
99 | },
100 | {
101 | "text": "ok",
102 | "intent": "affirm",
103 | "entities": []
104 | },
105 | {
106 | "text": "great",
107 | "intent": "affirm",
108 | "entities": []
109 | },
110 | {
111 | "text": "What is the event happening now",
112 | "intent": "event-request",
113 | "entities": [
114 | {
115 | "start": 28,
116 | "end": 31,
117 | "value": "now",
118 | "entity": "time"
119 | }
120 | ]
121 | },
122 | {
123 | "text": "What event is happening at Lecture hall 10 AM today",
124 | "intent": "event-request",
125 | "entities": [
126 | {
127 | "start": 40,
128 | "end": 45,
129 | "value": "10 AM",
130 | "entity": "time"
131 | },
132 | {
133 | "start": 46,
134 | "end": 51,
135 | "value": "today",
136 | "entity": "day"
137 | },
138 | {
139 | "start": 27,
140 | "end": 39,
141 | "value": "Lecture hall",
142 | "entity": "place"
143 | }
144 | ]
145 | },
146 | {
147 | "text": "What is the event same time tomorrow",
148 | "intent": "event-request",
149 | "entities": [
150 | {
151 | "start": 18,
152 | "end": 27,
153 | "value": "same time",
154 | "entity": "time"
155 | },
156 | {
157 | "start": 28,
158 | "end": 36,
159 | "value": "tomorrow",
160 | "entity": "day"
161 | }
162 | ]
163 | },
164 | {
165 | "text": "What event is happening at Lecture hall 2 tommorrow 10 PM",
166 | "intent": "event-request",
167 | "entities": [
168 | {
169 | "start": 27,
170 | "end": 41,
171 | "value": "Lecture hall 2",
172 | "entity": "place"
173 | },
174 | {
175 | "start": 52,
176 | "end": 57,
177 | "value": "10 PM",
178 | "entity": "time"
179 | },
180 | {
181 | "start": 42,
182 | "end": 51,
183 | "value": "tomorrow",
184 | "entity": "day"
185 | }
186 | ]
187 | },
188 | {
189 | "text": "What event is happening at Lecture hall 6 AM today",
190 | "intent": "event-request",
191 | "entities": [
192 | {
193 | "start": 40,
194 | "end": 44,
195 | "value": "10 AM",
196 | "entity": "time"
197 | },
198 | {
199 | "start": 45,
200 | "end": 52,
201 | "value": "today",
202 | "entity": "day"
203 | },
204 | {
205 | "start": 27,
206 | "end": 39,
207 | "value": "Lecture hall",
208 | "entity": "place"
209 | }
210 | ]
211 | },
212 | {
213 | "text": "What event is happening at Lecture hall 6:30 PM today",
214 | "intent": "event-request",
215 | "entities": [
216 | {
217 | "start": 40,
218 | "end": 47,
219 | "value": "10 AM",
220 | "entity": "time"
221 | },
222 | {
223 | "start": 48,
224 | "end": 55,
225 | "value": "today",
226 | "entity": "day"
227 | },
228 | {
229 | "start": 27,
230 | "end": 39,
231 | "value": "Lecture hall",
232 | "entity": "place"
233 | }
234 | ]
235 | },
236 | {
237 | "text": "What event is happening at Lecture hall 6 30 PM today",
238 | "intent": "event-request",
239 | "entities": [
240 | {
241 | "start": 40,
242 | "end": 47,
243 | "value": "10 AM",
244 | "entity": "time"
245 | },
246 | {
247 | "start": 48,
248 | "end": 55,
249 | "value": "today",
250 | "entity": "day"
251 | },
252 | {
253 | "start": 27,
254 | "end": 39,
255 | "value": "Lecture hall",
256 | "entity": "place"
257 | }
258 | ]
259 | },
260 | {
261 | "text": "What event is happening at 6 30 PM today",
262 | "intent": "event-request",
263 | "entities": [
264 | {
265 | "start": 27,
266 | "end": 34,
267 | "value": "6 30 PM",
268 | "entity": "time"
269 | },
270 | {
271 | "start": 35,
272 | "end": 40,
273 | "value": "today",
274 | "entity": "day"
275 | }
276 | ]
277 | },
278 | {
279 | "text": "What event is happening at 6",
280 | "intent": "event-request",
281 | "entities": [
282 | {
283 | "start": 27,
284 | "end": 28,
285 | "value": "6",
286 | "entity": "time"
287 | }
288 | ]
289 | },
290 | {
291 | "text": "What event is at 12",
292 | "intent": "event-request",
293 | "entities": [
294 | {
295 | "start": 17,
296 | "end": 19,
297 | "value": "12",
298 | "entity": "time"
299 | }
300 | ]
301 | },
302 | {
303 | "text": "list events before 12",
304 | "intent": "event-request",
305 | "entities": [
306 | {
307 | "start": 19,
308 | "end": 21,
309 | "value": "12",
310 | "entity": "time"
311 | },
312 | {
313 | "start": 12,
314 | "end": 18,
315 | "value": "before",
316 | "entity": "relative-time"
317 | }
318 | ]
319 | },
320 | {
321 | "text": "list events after 5",
322 | "intent": "event-request",
323 | "entities": [
324 | {
325 | "start": 18,
326 | "end": 19,
327 | "value": "5",
328 | "entity": "time"
329 | },
330 | {
331 | "start": 12,
332 | "end": 17,
333 | "value": "before",
334 | "entity": "relative-time"
335 | }
336 | ]
337 | },
338 | {
339 | "text": "when is the chatbot event happening",
340 | "intent": "event-time",
341 | "entities": [
342 | {
343 | "start": 12,
344 | "end": 19,
345 | "value": "chatbot",
346 | "entity": "event_name"
347 | }
348 | ]
349 | },
350 | {
351 | "text": "when is python 101 event happening",
352 | "intent": "event-time",
353 | "entities": [
354 | {
355 | "start": 8,
356 | "end": 18,
357 | "value": "python 101",
358 | "entity": "event_name"
359 | }
360 | ]
361 | },
362 | {
363 | "text": "what event is happening 2 tomorrow",
364 | "intent": "event-request",
365 | "entities": [
366 | {
367 | "start": 24,
368 | "end": 25,
369 | "value": "2",
370 | "entity": "time"
371 | },
372 | {
373 | "start": 26,
374 | "end": 34,
375 | "value": "2",
376 | "entity": "time"
377 | }
378 | ]
379 | },
380 | {
381 | "text": "What event is happening at Lecture hall 10 AM today",
382 | "intent": "event-request",
383 | "entities": [
384 | {
385 | "start": 40,
386 | "end": 45,
387 | "value": "10 AM",
388 | "entity": "time"
389 | },
390 | {
391 | "start": 46,
392 | "end": 51,
393 | "value": "today",
394 | "entity": "day"
395 | },
396 | {
397 | "start": 27,
398 | "end": 39,
399 | "value": "Lecture hall",
400 | "entity": "place"
401 | }
402 | ]
403 | },
404 | {
405 | "text": "What is the event same time tomorrow",
406 | "intent": "event-request",
407 | "entities": [
408 | {
409 | "start": 18,
410 | "end": 27,
411 | "value": "same time",
412 | "entity": "time"
413 | },
414 | {
415 | "start": 28,
416 | "end": 36,
417 | "value": "tomorrow",
418 | "entity": "day"
419 | }
420 | ]
421 | },
422 | {
423 | "text": "What event is happening at Lecture hall 2 tommorrow 10 PM",
424 | "intent": "event-request",
425 | "entities": [
426 | {
427 | "start": 27,
428 | "end": 41,
429 | "value": "Lecture hall 2",
430 | "entity": "place"
431 | },
432 | {
433 | "start": 52,
434 | "end": 57,
435 | "value": "tomorrow 10 PM",
436 | "entity": "time"
437 | },
438 | {
439 | "start": 42,
440 | "end": 51,
441 | "value": "tomorrow",
442 | "entity": "day"
443 | }
444 | ]
445 | },
446 | {
447 | "text": "What event is happening at Lecture hall 6 AM today",
448 | "intent": "event-request",
449 | "entities": [
450 | {
451 | "start": 40,
452 | "end": 44,
453 | "value": "6 AM",
454 | "entity": "time"
455 | },
456 | {
457 | "start": 45,
458 | "end": 50,
459 | "value": "today",
460 | "entity": "day"
461 | },
462 | {
463 | "start": 27,
464 | "end": 39,
465 | "value": "Lecture hall",
466 | "entity": "place"
467 | }
468 | ]
469 | },
470 | {
471 | "text": "What event is happening at Lecture hall 6:30 PM today",
472 | "intent": "event-request",
473 | "entities": [
474 | {
475 | "start": 40,
476 | "end": 47,
477 | "value": "6:30 PM",
478 | "entity": "time"
479 | },
480 | {
481 | "start": 48,
482 | "end": 53,
483 | "value": "today",
484 | "entity": "day"
485 | },
486 | {
487 | "start": 27,
488 | "end": 39,
489 | "value": "Lecture hall",
490 | "entity": "place"
491 | }
492 | ]
493 | },
494 | {
495 | "text": "What event is happening at Lecture hall 6 30 PM today",
496 | "intent": "event-request",
497 | "entities": [
498 | {
499 | "start": 40,
500 | "end": 47,
501 | "value": "10 AM",
502 | "entity": "time"
503 | },
504 | {
505 | "start": 48,
506 | "end": 53,
507 | "value": "today",
508 | "entity": "day"
509 | },
510 | {
511 | "start": 27,
512 | "end": 39,
513 | "value": "Lecture hall",
514 | "entity": "place"
515 | }
516 | ]
517 | },
518 | {
519 | "text": "What event is happening at 6 30 PM today",
520 | "intent": "event-request",
521 | "entities": [
522 | {
523 | "start": 27,
524 | "end": 34,
525 | "value": "6 30 PM",
526 | "entity": "time"
527 | },
528 | {
529 | "start": 35,
530 | "end": 40,
531 | "value": "today",
532 | "entity": "day"
533 | }
534 | ]
535 | },
536 | {
537 | "text": "What event is happening at 6 30 PM today",
538 | "intent": "event-request",
539 | "entities": [
540 | {
541 | "start": 27,
542 | "end": 34,
543 | "value": "10 30 AM",
544 | "entity": "time"
545 | },
546 | {
547 | "start": 35,
548 | "end": 40,
549 | "value": "today",
550 | "entity": "day"
551 | }
552 | ]
553 | },
554 | {
555 | "text": "What event is happening at 6",
556 | "intent": "event-request",
557 | "entities": [
558 | {
559 | "start": 27,
560 | "end": 28,
561 | "value": "6",
562 | "entity": "time"
563 | }
564 | ]
565 | },
566 | {
567 | "text": "What event is at 12",
568 | "intent": "event-request",
569 | "entities": [
570 | {
571 | "start": 17,
572 | "end": 19,
573 | "value": "12",
574 | "entity": "time"
575 | }
576 | ]
577 | },
578 | {
579 | "text": "list events before 12",
580 | "intent": "event-request",
581 | "entities": [
582 | {
583 | "start": 19,
584 | "end": 21,
585 | "value": "12",
586 | "entity": "time"
587 | },
588 | {
589 | "start": 12,
590 | "end": 18,
591 | "value": "before",
592 | "entity": "relative-time"
593 | }
594 | ]
595 | },
596 | {
597 | "text": "list events after 5",
598 | "intent": "event-request",
599 | "entities": [
600 | {
601 | "start": 18,
602 | "end": 19,
603 | "value": "5",
604 | "entity": "time"
605 | },
606 | {
607 | "start": 12,
608 | "end": 17,
609 | "value": "before",
610 | "entity": "relative-time"
611 | }
612 | ]
613 | },
614 | {
615 | "text": "when is the chatbot event happening",
616 | "intent": "event-time",
617 | "entities": [
618 | {
619 | "start": 12,
620 | "end": 19,
621 | "value": "chatbot",
622 | "entity": "event_name"
623 | }
624 | ]
625 | },
626 | {
627 | "text": "when is python 101 event happening",
628 | "intent": "event-time",
629 | "entities": [
630 | {
631 | "start": 8,
632 | "end": 18,
633 | "value": "python 101",
634 | "entity": "event_name"
635 | }
636 | ]
637 | },
638 | {
639 | "text": "what event is happening 2 tomorrow",
640 | "intent": "event-request",
641 | "entities": [
642 | {
643 | "start": 24,
644 | "end": 25,
645 | "value": "2",
646 | "entity": "time"
647 | },
648 | {
649 | "start": 26,
650 | "end": 34,
651 | "value": "2",
652 | "entity": "time"
653 | }
654 | ]
655 | }
656 | ]
657 | }
658 | }
--------------------------------------------------------------------------------
/AI-engine/rasa_nlu_log.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "entities": [],
4 | "confidence": 0.7503025949407385,
5 | "intent": "greet",
6 | "text": "hi"
7 | },
8 | {
9 | "entities": [],
10 | "confidence": 0.3309503410702648,
11 | "intent": "greet",
12 | "text": "yo"
13 | },
14 | {
15 | "entities": [
16 | {
17 | "start": 0,
18 | "end": 9,
19 | "value": "first day",
20 | "entity": "time"
21 | }
22 | ],
23 | "confidence": 0.19041142788243318,
24 | "intent": "affirm",
25 | "text": "first day"
26 | },
27 | {
28 | "entities": [],
29 | "confidence": 1.0887962093977857,
30 | "intent": "greet",
31 | "text": "hey"
32 | },
33 | {
34 | "entities": [
35 | {
36 | "start": 26,
37 | "end": 29,
38 | "value": "now",
39 | "entity": "time"
40 | }
41 | ],
42 | "confidence": 0.4448289239245017,
43 | "intent": "event-request",
44 | "text": "what events are happening now"
45 | },
46 | {
47 | "entities": [
48 | {
49 | "start": 0,
50 | "end": 5,
51 | "value": "heeey",
52 | "entity": "time"
53 | }
54 | ],
55 | "confidence": 0.21558314243108612,
56 | "intent": "greet",
57 | "text": "heeey"
58 | },
59 | {
60 | "entities": [],
61 | "confidence": 0.09125234572941558,
62 | "intent": "affirm",
63 | "text": "whts up"
64 | },
65 | {
66 | "entities": [],
67 | "confidence": 0.1148097920349114,
68 | "intent": "affirm",
69 | "text": "whats up"
70 | }
71 | ]
--------------------------------------------------------------------------------
/bot-application/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask import render_template, jsonify, request
3 | import requests
4 | from models import *
5 | from response import *
6 | import random
7 |
8 |
9 | @app.route('/')
10 | def hello_world():
11 | """
12 | Sample hello world
13 | """
14 | return render_template('home.html')
15 |
16 |
17 | def get_random_response(intent):
18 | print (response[intent])
19 | return random.choice(response[intent])
20 |
21 |
22 | def format_entities(entities):
23 | """
24 | formats entities to key value pairs
25 | """
26 | # Should be formatted to handle multiple entity values
27 | e = {"day": None, "time": None, "place": None}
28 | for entity in entities:
29 | e[entity["entity"]] = entity["value"]
30 | return e
31 |
32 |
33 | def get_event(day=None, time=None, place=None):
34 | """
35 | gets event date and time from user utterance
36 | and finds event within next half an hour of that range
37 | """
38 | if not day and not time:
39 | return get_random_response("events_link")
40 | date_time = get_date_time(day, time)
41 | print(date_time)
42 | events = Event.query.filter(Event.date_time >= date_time,
43 | Event.date_time <= date_time + datetime.timedelta(minutes=30))
44 | events = events.all()
45 | if not events:
46 | return get_random_response("no_events") + "
" + get_random_response("events_link")
47 | event_description = "
".join(event.event_description + " at " + event.place for event in events)
48 | return event_description
49 |
50 |
51 | @app.route('/chat', methods=["POST"])
52 | def chat():
53 | """
54 | chat end point that performs NLU using rasa.ai
55 | and constructs response from response.py
56 | """
57 | # try:
58 | response = requests.get("http://localhost:5000/parse", params={"q": request.form["text"]})
59 | response = response.json()
60 | print (response)
61 | intent = response.get("intent", {}).get("name", "default")
62 | entities = format_entities(response.get("entities", []))
63 | if intent == "event-request":
64 | response_text = get_event(entities["day"], entities["time"], entities["place"])
65 | else:
66 | response_text = get_random_response(intent)
67 | return jsonify({"status": "success", "response": response_text})
68 | # except Exception as e:
69 | # print(e)
70 | # return jsonify({"status": "success", "response": "Sorry I am not trained to do that yet..."})
71 |
72 |
73 | app.config["DEBUG"] = True
74 | if __name__ == "__main__":
75 | app.run(port=8000)
76 |
--------------------------------------------------------------------------------
/bot-application/extract.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 | import requests
3 | import json
4 |
5 | conn = sqlite3.connect('app.db')
6 | c = conn.cursor()
7 | # print("Opened database successfully")
8 |
9 | conn.execute('''CREATE TABLE IF NOT EXISTS Event
10 | (ID INT NOT NULL ,
11 | event_description VARCHAR(40),
12 | date_time DATATIME,
13 | place VARCHAR(40));''')
14 | # print("Table created successfully")
15 |
16 | url = "https://conference.pydelhi.org/api/schedule.json"
17 | r = requests.get(url)
18 | data = r.text
19 | schedule = json.loads(data)["0.0.1"][0]
20 | url2 = "https://conference.pydelhi.org/api/tracks.json"
21 | r2 = requests.get(url2)
22 | data2 = r2.text
23 | tracks = json.loads(data2)["0.0.1"][0]
24 | DATE_ONE = "2017-03-18"
25 | DATE_TWO = "2017-03-19"
26 |
27 | schedule["2017-03-23"] = schedule[DATE_ONE]
28 | del schedule[DATE_ONE]
29 |
30 | schedule["2017-03-24"] = schedule[DATE_TWO]
31 | del schedule[DATE_TWO]
32 |
33 |
34 | DATE_ONE = "2017-03-23"
35 | DATE_TWO = "2017-03-24"
36 |
37 | from datetime import datetime
38 | # DayOne Loop
39 | for events in schedule[DATE_ONE]:
40 | title = events["title"]
41 | talk_id = str(events["talk_id"])
42 | start_time = events["start_time"]
43 | end_time = events["end_time"]
44 | track = events["track"]
45 | description = tracks[talk_id]["description"]
46 | theTime = datetime.strptime(DATE_ONE +
47 | " " + start_time+" "+("AM" if int(start_time.split(":")[0])>8 else "PM"),
48 | "%Y-%m-%d %I:%M %p")
49 |
50 | place = "AUDI 1"
51 | speaker = ''
52 | if track != "all":
53 | speaker = tracks[talk_id]["speaker"]["name"]
54 | if track == "all":
55 | place = "AUDI 1"
56 | elif track == "1":
57 | place = "AUDI 1"
58 | elif track == "2":
59 | place = "LECTURE HALL 1"
60 | else:
61 | place = "LECTURE HALL 2"
62 | if speaker != '':
63 | title = title + " by " + speaker
64 | c.execute("insert into Event (ID,event_description,date_time,place) values(?,?,?,?)",
65 | (talk_id, title, theTime, place))
66 | conn.commit()
67 |
68 | # Day2 Loop
69 | for events in schedule[DATE_TWO]:
70 | title = events["title"]
71 | place = "AUDI 1"
72 | speaker = ''
73 | talk_id = str(events["talk_id"])
74 | start_time = events["start_time"]
75 | end_time = events["end_time"]
76 | track = events["track"]
77 | description = tracks[talk_id]["description"]
78 | if track != "all":
79 | speaker = tracks[talk_id]["speaker"]["name"]
80 | if track == "all":
81 | place = "AUDI 1"
82 | elif track == "1":
83 | place = "AUDI 1"
84 | elif track == "2":
85 | place = "LECTURE HALL 1"
86 | else:
87 | place = "LECTURE HALL 2"
88 | theTime = datetime.strptime(DATE_TWO +
89 | " " + start_time+" "+("AM" if int(start_time.split(":")[0])>8 else "PM"),
90 | "%Y-%m-%d %I:%M %p")
91 | if speaker != '':
92 | title = title + " by " + speaker
93 | conn.execute("insert into Event (ID,event_description,date_time,place) values(?,?,?,?)",
94 | (talk_id, title, theTime, place))
95 | conn.commit()
96 |
97 | print("all data")
98 | c.execute("select * from Event")
99 | for i in c.fetchall():
100 | print(i)
101 |
102 | conn.close()
103 |
--------------------------------------------------------------------------------
/bot-application/getSchedule.py:
--------------------------------------------------------------------------------
1 | class getSchedule:
2 | def getSchedule(schedule, tracks, table_body):
3 | schedule_rows = []
4 | for i in range(len(schedule)):
5 | talk_id = schedule[i]["talk_id"]
6 | entity_details = schedule[i]
7 | title = entity_details["title"]
8 | if "speaker" in tracks["talk_id"]:
9 | speaker_name= tracks["talk_id"]["speaker"]
10 | display_title=title+" by "+speaker_name
11 | else:
12 | display_title=title
13 | time_duration = entity_details["start_time"] + ' - ' + entity_details["end_time"]
14 |
15 | try:
16 | current_day_track = schedule[i]["track"]
17 | if current_day_track =='all':
18 | schedule_rows.append([time_duration,display_title])
19 | except:
20 | schedule_rows.append([time_duration, display_title])
21 | if current_day_track==1:
22 | # else if (current_day_track == '1')
23 | schedule_rows.append([time_duration, display_title])
24 | else:
25 | # index_of_last_row = len(schedule_rows) - 1
26 | schedule_rows.append(display_title)
27 |
28 |
--------------------------------------------------------------------------------
/bot-application/local_settings.py:
--------------------------------------------------------------------------------
1 | LXD_URL = "http://codecompiler.etpg.in"
2 | MYSQL_PASSWORD = ""
3 | MYSQL_USER = "root"
4 | DEBUG_MODE = True
5 | LXD_USERNAME = "ibo"
6 | LXD_PASSWORD = "ibo@ffi2016"
7 |
--------------------------------------------------------------------------------
/bot-application/models.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_sqlalchemy import SQLAlchemy
3 | # from urllib import quote_plus as urlquote
4 | import urllib.parse
5 | from flask_admin import Admin
6 | from flask_admin.contrib.sqla import ModelView
7 | from flask_migrate import Migrate
8 |
9 | try:
10 | from local_settings import *
11 | except ImportError:
12 | from production_settings import *
13 |
14 | app = Flask(__name__)
15 | app.secret_key = '12345'
16 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
17 | app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///app.db"
18 | db = SQLAlchemy(app)
19 | # Migrate won't work well on sqlite better to use mysql db
20 | migrate = Migrate(app, db)
21 |
22 |
23 | class Event(db.Model):
24 | id = db.Column(db.Integer, primary_key=True, autoincrement=True)
25 | event_description = db.Column(db.String(50))
26 | date_time = db.Column(db.DateTime())
27 | place = db.Column(db.String(50))
28 |
29 | def __init__(self, event_description=None, date=None, time=None, place=None):
30 | self.event_description = event_description
31 | self.date = date
32 | self.time = time
33 | self.place = place
34 |
35 |
36 | class MyModelView(ModelView):
37 | def __init__(self, model, session, name=None, category=None, endpoint=None, url=None, **kwargs):
38 | for k, v in kwargs.items():
39 | setattr(self, k, v)
40 |
41 | super(MyModelView, self).__init__(model, session, name=name, category=category, endpoint=endpoint, url=url)
42 |
43 |
44 | admin = Admin(app, name='rasa-site-bot', template_mode='bootstrap3')
45 | admin.add_view(MyModelView(Event, db.session))
46 |
--------------------------------------------------------------------------------
/bot-application/response.py:
--------------------------------------------------------------------------------
1 | # dict of response for each type of intent
2 |
3 | import datetime
4 |
5 | response = {
6 | "greet": ["hey", "hello", "hi"],
7 | "goodbye": ["bye", "It was nice talking to you", "see you", "ttyl"],
8 | "affirm": ["cool", "I know you would like it"],
9 | "day_preference": ["which day of conference ?"],
10 | "time_preference": ["Do you have any time preference"],
11 | "events_link": [
12 | 'You can check all the events here PyDelhi events'],
13 | "no_events": ["No events found"],
14 | "intro": ["I am event bot for pydelhi, I can find you event details in minutes"],
15 | "default": ["Sorry I am not trained to answer that yet.", "Oops I didn't understand that sorry"]
16 | }
17 |
18 | mapping = {
19 | "now": datetime.datetime.now(),
20 | "tomorrow": datetime.date.today() + datetime.timedelta(days=1),
21 | "today": datetime.date.today(),
22 | "same time": datetime.datetime.now(),
23 | "second day": datetime.datetime.now()
24 | }
25 |
26 |
27 | def try_parsing_date(text):
28 | """
29 | Parses time of string format to a time object
30 | """
31 | for fmt in ('%I %p', '%I %M %p', '%I:%M %p'):
32 | try:
33 | return datetime.datetime.strptime(text, fmt)
34 | except ValueError:
35 | pass
36 | if ":" in text:
37 | return datetime.datetime.strptime(text + " " +
38 | ("AM" if int(text.split(":")[0]) >= 8 else "PM"), '%I:%M %p')
39 | return datetime.datetime.strptime(text + " " +
40 | ("AM" if int(text) >= 8 else "PM"), '%I %p')
41 |
42 |
43 | def get_date_time(day, time):
44 | """
45 | Maps words like now today tom etc., to corresponding datetime objects
46 | """
47 | try:
48 | time = mapping[time]
49 | except KeyError:
50 | if not time:
51 | time = datetime.datetime.now()
52 | else:
53 | time = try_parsing_date(time)
54 | try:
55 | date = mapping[day]
56 | except KeyError:
57 | date = datetime.date.today()
58 |
59 | return datetime.datetime.combine(date, time.time())
60 |
--------------------------------------------------------------------------------
/bot-application/static/css/chat_interface.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | background-color: #edeff2;
7 | font-family: "Calibri", "Roboto", sans-serif;
8 | }
9 |
10 | .chat_window {
11 | /*position: absolute;*/
12 | width: calc(100% - 20px);
13 | max-width: 800px;
14 | height: 500px;
15 | border-radius: 10px;
16 | background-color: #fff;
17 | left: 50%;
18 | top: 50%;
19 | /*transform: translateX(-50%) translateY(-50%);*/
20 | box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
21 | background-color: #f8f8f8;
22 | overflow: hidden;
23 | }
24 |
25 | .top_menu {
26 | background-color: #fff;
27 | width: 100%;
28 | padding: 13px 0px;
29 | box-shadow: 0 1px 30px rgba(0, 0, 0, 0.1);
30 | }
31 | .top_menu .buttons {
32 | margin: 3px 0 0 20px;
33 | position: absolute;
34 | }
35 | .top_menu .buttons .button {
36 | width: 16px;
37 | height: 16px;
38 | border-radius: 50%;
39 | display: inline-block;
40 | margin-right: 10px;
41 | position: relative;
42 | }
43 | .top_menu .buttons .button.close {
44 | background-color: #f5886e;
45 | }
46 | .top_menu .buttons .button.minimize {
47 | background-color: #fdbf68;
48 | }
49 | .top_menu .buttons .button.maximize {
50 | background-color: #a3d063;
51 | }
52 | .top_menu .title {
53 | text-align: center;
54 | color: #337ab7;
55 | font-size: 20px;
56 | }
57 |
58 | .messages {
59 | position: relative;
60 | list-style: none;
61 | padding: 20px 10px 0 10px;
62 | margin: 0;
63 | height: 70%;
64 | overflow: scroll;
65 | }
66 | .messages .message {
67 | clear: both;
68 | overflow: hidden;
69 | margin-bottom: 20px;
70 | transition: all 0.5s linear;
71 | opacity: 0;
72 | }
73 | .messages .message.left .avatar {
74 | background-color: #f5886e;
75 | float: left;
76 | }
77 | .messages .message.left .text_wrapper {
78 | background-color: #ffe6cb;
79 | margin-left: 20px;
80 | }
81 | .messages .message.left .text_wrapper::after, .messages .message.left .text_wrapper::before {
82 | right: 100%;
83 | border-right-color: #ffe6cb;
84 | }
85 | .messages .message.left .text {
86 | color: #c48843;
87 | }
88 | .messages .message.right .avatar {
89 | background-color: #fdbf68;
90 | float: right;
91 | }
92 | .messages .message.right .text_wrapper {
93 | background-color: #c7eafc;
94 | margin-right: 20px;
95 | float: right;
96 | }
97 | .messages .message.right .text_wrapper::after, .messages .message.right .text_wrapper::before {
98 | left: 100%;
99 | border-left-color: #c7eafc;
100 | }
101 | .messages .message.right .text {
102 | color: #45829b;
103 | }
104 | .messages .message.appeared {
105 | opacity: 1;
106 | }
107 | .messages .message .avatar {
108 | width: 60px;
109 | height: 60px;
110 | border-radius: 50%;
111 | display: inline-block;
112 | }
113 | .messages .message .text_wrapper {
114 | display: inline-block;
115 | padding: 20px;
116 | border-radius: 6px;
117 | width: calc(100% - 85px);
118 | min-width: 100px;
119 | position: relative;
120 | }
121 | .messages .message .text_wrapper::after, .messages .message .text_wrapper:before {
122 | top: 18px;
123 | border: solid transparent;
124 | content: " ";
125 | height: 0;
126 | width: 0;
127 | position: absolute;
128 | pointer-events: none;
129 | }
130 | .messages .message .text_wrapper::after {
131 | border-width: 13px;
132 | margin-top: 0px;
133 | }
134 | .messages .message .text_wrapper::before {
135 | border-width: 15px;
136 | margin-top: -2px;
137 | }
138 | .messages .message .text_wrapper .text {
139 | font-size: 18px;
140 | font-weight: 300;
141 | }
142 |
143 | .bottom_wrapper {
144 | position: relative;
145 | width: 100%;
146 | background-color: #fff;
147 | padding: 20px 20px;
148 | /*position: absolute;*/
149 | bottom: 0;
150 | }
151 | .bottom_wrapper .message_input_wrapper {
152 | display: inline-block;
153 | height: 50px;
154 | border-radius: 25px;
155 | border: 1px solid #bcbdc0;
156 | width: calc(100% - 160px);
157 | position: relative;
158 | padding: 0 20px;
159 | }
160 | .bottom_wrapper .message_input_wrapper .message_input {
161 | border: none;
162 | height: 100%;
163 | box-sizing: border-box;
164 | width: calc(100% - 40px);
165 | position: absolute;
166 | outline-width: 0;
167 | color: gray;
168 | }
169 | .bottom_wrapper .send_message {
170 | width: 140px;
171 | height: 50px;
172 | display: inline-block;
173 | border-radius: 50px;
174 | background-color: #a3d063;
175 | border: 2px solid #a3d063;
176 | color: #fff;
177 | cursor: pointer;
178 | transition: all 0.2s linear;
179 | text-align: center;
180 | float: right;
181 | }
182 | .bottom_wrapper .send_message:hover {
183 | color: #a3d063;
184 | background-color: #fff;
185 | }
186 | .bottom_wrapper .send_message .text {
187 | font-size: 18px;
188 | font-weight: 300;
189 | display: inline-block;
190 | line-height: 48px;
191 | }
192 |
193 | .message_template {
194 | display: none;
195 | }
196 |
--------------------------------------------------------------------------------
/bot-application/static/css/style.css:
--------------------------------------------------------------------------------
1 | @import url(http://weloveiconfonts.com/api/?family=fontawesome|iconicstroke|typicons);
2 | /* fontawesome */
3 | [class*="fontawesome-"]:before {
4 | font-family: 'FontAwesome', sans-serif;
5 | }
6 | /* iconicstroke */
7 | [class*="iconicstroke-"]:before {
8 | font-family: 'IconicStroke', sans-serif;
9 | }
10 | /* typicons */
11 | [class*="typicons-"]:before {
12 | font-family: 'Typicons', sans-serif;
13 | }
14 | body{
15 | font-family:arial,sans-serif;
16 | }
17 | .chat-container {
18 | width: 300px;
19 | margin-right: 20px;
20 | float:right;
21 | overflow:hidden;
22 | }
23 | .top-header {
24 | background: #666;
25 | color: white;
26 | padding: 0.2rem;
27 | position: relative;
28 | overflow: hidden;
29 | border-bottom: 4px solid #35ac19;
30 | cursor:pointer;
31 | }
32 | .top-header:hover {
33 | background-color:#35ac19;
34 | }
35 | .top-header-tit {
36 | display: inline;
37 | font-size: 14px;
38 | }
39 | .top-header .typicons-message {
40 | display: inline-block;
41 | padding: 2px 5px 2px 5px;
42 | font-size: 20px;
43 | position: relative;
44 | top: 5px;
45 | }
46 | .top-header .typicons-minus {
47 | position: relative;
48 | top: 3px;
49 | font-size: 15px;
50 | cursor:pointer;
51 | }
52 | .top-header .typicons-plus {
53 | position: relative;
54 | top: 3px;
55 | font-size: 15px;
56 | }
57 | .top-header .typicons-times{
58 | position: relative;
59 | top: 3px;
60 | font-size: 15px;
61 | }
62 | .top-header .left {
63 | float: left;
64 | }
65 | .top-header .right {
66 | float: right;
67 | padding-top: 5px;
68 | }
69 | .top-header > * {
70 | position: relative;
71 | }
72 | .top-header::before {
73 | content: '';
74 | position: absolute;
75 | top: -100%;
76 | left: 0;
77 | right: 0;
78 | bottom: -100%;
79 | opacity: 0.25;
80 | background-color: #404040
81 | }
82 | .chat-box {
83 | list-style: none;
84 | background: #e5e5e5;
85 | margin: 0;
86 | padding: 0 0 50px 0;
87 | height: 280px;
88 | overflow-y: auto;
89 | }
90 | .chat-box li {
91 | padding: 0.5rem;
92 | overflow: hidden;
93 | display: flex;
94 | }
95 | .chat-box .avatar-icon {
96 | width: 40px;
97 | position: relative;
98 | }
99 | .chat-box .avatar-icon img {
100 | display: block;
101 | width: 100%;
102 | background-color:#1469A6;
103 | }
104 | .ibo .avatar-icon:after {
105 | content: '';
106 | position: absolute;
107 | top: 0;
108 | right: 0;
109 | width: 0;
110 | height: 0;
111 | border: 5px solid white;
112 | border-left-color: transparent;
113 | border-bottom-color: transparent;
114 | }
115 | .me {
116 | justify-content: flex-end;
117 | align-items: flex-end;
118 | }
119 | .me .messages {
120 | order: 1;
121 | border-bottom-right-radius: 0;
122 | }
123 | .me .avatar-icon {
124 | order: 2;
125 | }
126 | .me .avatar-icon:after {
127 | content: '';
128 | position: absolute;
129 | bottom: 0;
130 | left: 0;
131 | width: 0;
132 | height: 0;
133 | border: 5px solid white;
134 | border-right-color: transparent;
135 | border-top-color: transparent;
136 | box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
137 | }
138 | .messages {
139 | background: white;
140 | padding: 10px;
141 | border-radius: 2px;
142 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
143 | }
144 | .messages p {
145 | font-size: 0.8rem;
146 | margin: 0 0 0.2rem 0;
147 | }
148 | .messages time {
149 | font-size: 0.7rem;
150 | color: #ccc;
151 | }
152 | .setting{
153 | background-color: #e5e5e5;
154 | height: 32px;
155 | padding-top: 2px;
156 | border-bottom: 1px solid rgba(0,0,0,.1);
157 | }
158 | .setting .left {
159 | float: left;
160 | }
161 | .setting .right {
162 | float: right;
163 | }
164 | .iconicstroke-user{
165 | font-size: 22px;
166 | position: relative;
167 | top: 4px;
168 | left: 10px;
169 | color: #414141;
170 | cursor:pointer;
171 | }
172 | .typicons-cog{
173 | font-size: 23px;
174 | position: relative;
175 | top: 7px;
176 | right: 4px;
177 | color: #414141;
178 | cursor:pointer;
179 | }
180 | .fontawesome-facetime-video{
181 | font-size: 18px;
182 | position: relative;
183 | top: 3px;
184 | color: #414141;
185 | left: 5px;
186 | cursor:pointer;
187 | }
188 | .iconicstroke-user:hover, .typicons-cog:hover,.fontawesome-facetime-video:hover{
189 | color:#000000;
190 | }
191 | ::-webkit-scrollbar{height:14px;width:10px;background:#eee;border-left:1px solid #ddd}
192 | ::-webkit-scrollbar-thumb{background:#ddd;border:1px solid #cfcfcf}
193 | ::-webkit-scrollbar-thumb:hover{background:#b2b2b2;border:1px solid #b2b2b2}
194 | ::-webkit-scrollbar-thumb:active{background:#b2b2b2;border:1px solid #b2b2b2}
195 | @-webkit-keyframes pulse {
196 | from {
197 | opacity: 0;
198 | }
199 | to {
200 | opacity: 0.5;
201 | }
202 | }
203 |
204 | /************
205 | * response *
206 | ************/
207 | #response {
208 | width:320px;
209 | background-color: rgba(255, 255, 255, 0.8);
210 | }
211 | .say {
212 | width:220px;
213 | padding:8px 15px;
214 | background:rgba(50, 50, 50, 0.2);
215 | border:0px solid #dbdbdb;
216 | }
217 | .saybtn {
218 | position:relative;
219 | padding:6px 15px;
220 | left:-8px;
221 | border:2px solid #207cca;
222 | background-color:#207cca;
223 | color:#fafafa;
224 | }
225 | .saybtn:hover {
226 | background-color:#409cea;
227 | }
228 |
229 | .ace_editor {
230 | border: 1px solid lightgray;
231 | margin: auto;
232 | height: 200px;
233 | width: 80%;
234 | }
235 | .scrollmargin {
236 | height: 80px;
237 | text-align: center;
238 | }
239 | .view{
240 | border: 1px solid lightgray;
241 | margin: auto;
242 | width: 80%;
243 | }
244 | .view div span{
245 | margin: 20px;
246 | display: inline-block;
247 | }
248 | .view div span span{
249 | margin: 0px;
250 | display: inline;
251 | }
252 | .output{
253 | min-height: 70px;
254 | }
255 | .TitleBar {
256 | margin: auto;
257 | width: 80%;
258 | border: 1px solid lightgray;
259 | height: 30px;
260 | border-bottom: 0px;
261 | background-color: #FCFAFA;
262 | font-size:20px;
263 | }
264 | .TitleBar b{
265 | margin:15px;
266 | color: #454444;
267 | }
268 | .actionbar{
269 | margin: auto;
270 | width: 80%;
271 | }
272 | #statusBar {
273 | margin: auto;
274 | width: 80%;
275 | border: 1px solid lightgray;
276 | height: 20px;
277 | border-top: 0px;
278 | }
279 |
280 | .ace_status-indicator {
281 | color: gray;
282 | float:right;
283 | right: 0;
284 | border-left: 1px solid;
285 | }
286 | .submit {
287 | float: right;
288 | border: 1px solid #AAA;
289 | margin-left: 10px;
290 | padding: 4px;
291 | cursor: pointer;
292 | }
293 |
294 | .blinking-cursor {
295 | font-weight: 500;
296 | font-size: 15px;
297 | color: #2E3D48;
298 | -webkit-animation: 1s blink step-end infinite;
299 | -moz-animation: 1s blink step-end infinite;
300 | -ms-animation: 1s blink step-end infinite;
301 | -o-animation: 1s blink step-end infinite;
302 | animation: 1s blink step-end infinite;
303 | }
304 |
305 | @keyframes "blink" {
306 | from, to {
307 | color: transparent;
308 | }
309 | 50% {
310 | color: black;
311 | }
312 | }
313 |
314 | @-moz-keyframes blink {
315 | from, to {
316 | color: transparent;
317 | }
318 | 50% {
319 | color: black;
320 | }
321 | }
322 |
323 | @-webkit-keyframes "blink" {
324 | from, to {
325 | color: transparent;
326 | }
327 | 50% {
328 | color: black;
329 | }
330 | }
331 |
332 | @-ms-keyframes "blink" {
333 | from, to {
334 | color: transparent;
335 | }
336 | 50% {
337 | color: black;
338 | }
339 | }
340 |
341 | @-o-keyframes "blink" {
342 | from, to {
343 | color: transparent;
344 | }
345 | 50% {
346 | color: black;
347 | }
348 | }
349 | #submit:disabled,#SubmitMCQ :disabled {
350 | background-color: white;
351 | }
352 | #submit, #SubmitMCQ {
353 | background: #2cbb0f;
354 | color: white;
355 | }
356 | #submit:hover,#SubmitMCQ:hover{
357 | background: white;
358 | color: #2cbb0f;}
359 | .submit:hover {
360 | box-shadow: 1px 1px 3px gray;
361 | }
362 | .submit:disabled {
363 | box-shadow: unset;
364 | cursor: unset;
365 | color: lightgrey !important;
366 | background-color: #f6f6f6 !important;
367 | }
368 | #run {
369 | background-color: #4c9ed9;
370 | color: white;
371 | }
372 | #compiler::first-letter {
373 | text-transform: uppercase;
374 | }
375 | @media only screen and (max-height: 480px) {
376 | .chat-box {
377 | height: calc(100vh - 180px);
378 | }
379 |
380 | }
381 | #response{
382 | width: calc(100% + 20px);
383 | }
384 | @media only screen and (max-Width: 340px) {
385 | .chat-container {
386 | width: calc(100vw - 20px);
387 | max-width: 300px;
388 | margin: auto 10px;
389 | }
390 | .say {
391 | width: calc(100% - 100px);
392 | }
393 |
394 | }
395 | .view {
396 | white-space: pre-wrap; /* Since CSS 2.1 */
397 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
398 | white-space: -pre-wrap; /* Opera 4-6 */
399 | white-space: -o-pre-wrap; /* Opera 7 */
400 | word-wrap: break-word; /* Internet Explorer 5.5+ */
401 | }
402 |
403 | #QI {
404 | overflow-x: hidden;
405 | }
406 |
407 | .slide {
408 | opacity: 0;
409 | position: relative;
410 | font-family: Arial;
411 | font-size: 14px;
412 | /*line-height: 50px;*/
413 | right: -100%;
414 | width:100%;
415 | }
416 |
417 | /*.choice {
418 | -webkit-column-count: 2;
419 | -moz-column-count: 2;
420 | column-count: 2;
421 | }*/
422 | .MCanswer {
423 | display: inline-block;
424 | vertical-align: top;
425 | }
426 | .tab-container{
427 | background: #f1f1f1;
428 | /* margin: 0; */
429 | padding: 0;
430 | /* max-height: 35px; */
431 | /* position: relative; */
432 | overflow: hidden;
433 | }
434 |
435 | ul.tabs{
436 | margin: 0;
437 | list-style-type : none;
438 | line-height : 35px;
439 | max-height: 35px;
440 | overflow: hidden;
441 | display: inline-block;
442 | padding: 0;
443 | padding-right: 10px;
444 | padding-left: 10px;
445 | border-bottom: 1px solid #d4d4d4;
446 | width: 100%;
447 | }
448 |
449 | ul.tabs > li.active{
450 | z-index: 2;
451 | background: white;
452 | }
453 |
454 | ul.tabs > li.active:before{
455 | border-color : transparent #efefef transparent transparent;
456 | }
457 |
458 |
459 | ul.tabs > li.active:after{
460 | border-color : transparent transparent transparent #efefef;
461 | }
462 |
463 | ul.tabs > li{
464 | float: left;
465 | margin : 5px -10px 0;
466 | border-top-right-radius: 25px 170px;
467 | border-top-left-radius: 20px 90px;
468 | padding : 0 30px 0 25px;
469 | height: 170px;
470 | background: #ddd;
471 | position : relative;
472 | box-shadow: 0 10px 20px rgba(0,0,0,.5);
473 | max-width : 200px;
474 | }
475 |
476 | ul.tabs > li > a{
477 | display: inline-block;
478 | max-width:100%;
479 | overflow: hidden;
480 | text-overflow: ellipsis;
481 | text-decoration: none;
482 | color: #222;
483 | }
484 |
485 | ul.tabs > li:before, ul.tabs > li:after{
486 | content : '';
487 | background : transparent;
488 | height: 20px;
489 | width: 20px;
490 | border-radius: 100%;
491 | border-width: 10px;
492 | top: 0px;
493 | border-style : solid;
494 | position : absolute;
495 | }
496 |
497 | ul.tabs > li:before{
498 |
499 | border-color : transparent #ddd transparent transparent;
500 | left: -23px;
501 | -ms-transform: rotate(48deg);
502 | -webkit-transform : rotate(48deg);
503 | transform: rotate(48deg);
504 | }
505 |
506 | ul.tabs > li:after{
507 | border-color : transparent transparent transparent #ddd;
508 | -webkit-transform : rotate(-48deg);
509 | -ms-transform: rotate(-48deg);
510 | transform: rotate(-48deg);
511 | right: -17px;
512 | }
513 |
514 | /* Clear Fix took for HTML 5 Boilerlate*/
515 | .clearfix:after { clear: both; }
516 | .clearfix { zoom: 1; }
517 | .clearfix:after,.clearfix:before{
518 | -webkit-box-sizing: unset;
519 | -moz-box-sizing: unset;
520 | box-sizing: unset;
521 | }
522 |
523 | *{
524 | -webkit-box-sizing: unset;
525 | -moz-box-sizing: unset;
526 | box-sizing: unset;
527 | }
528 | body{
529 | line-height: unset;
530 | }
531 | pre{
532 | padding: unset;
533 | border-radius:unset;
534 | }
535 | #modal-backdrop{
536 | height: 100vh;
537 | width: 100vw;
538 | background: rgba(0,0,0,0.53);
539 | z-index: 10000;
540 | position: fixed;
541 | top: 0px;
542 | left: 0px;
543 | }
544 | #modal{
545 | border-radius: 4px;
546 | background: white;
547 | width: 500px;
548 | margin: auto;
549 | top: 100px;
550 | position: relative;
551 | color: #757575;
552 | overflow: hidden;
553 |
554 | }
555 | #modal-header{
556 | min-height: 20px;
557 | width: 100%;
558 | font-size: 16px;
559 | font-weight: 100;
560 | border-bottom: 1px solid lightgray;
561 | padding: 12px;
562 | /*text-shadow: 1px 1px 1px rgba(114, 119, 112, 0.8);*/
563 | }
564 | #modal-body{
565 | min-height: 20px;
566 | width: 100%;
567 | padding: 5px;
568 | overflow: hidden
569 | }
570 | #modal-footer{
571 | min-height: 20px;
572 | width: 100%;
573 | border-top: 1px solid lightgray;
574 | padding: 5px;
575 | }
576 | #modal-footer #next{
577 | cursor: unset;
578 | color: white;
579 | background-color: #4CAF50;
580 | float: right;
581 | margin: 5px;
582 | margin-right: 8px;
583 | border: unset;
584 | padding: 6px;
585 | border-radius: 1px;
586 | }
587 | #modal-footer #next:hover{
588 | background-color: #ffffff;
589 | color: #4CAF50;
590 | box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
591 | }
592 | #modal-footer #skip{
593 | cursor: unset;
594 | color: white;
595 | background-color: #FF622C;
596 | float: right;
597 | margin: 5px;
598 | margin-right: 8px;
599 | border: unset;
600 | padding: 6px;
601 | border-radius: 1px;
602 | }
603 | #modal-footer #skip:hover{
604 | background-color: white;
605 | color: #FF622C;
606 | box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
607 | }
608 | .skip:disabled {
609 | box-shadow: unset;
610 | cursor: unset;
611 | color: lightgrey !important;
612 | background-color: #f6f6f6 !important;
613 | }
614 | .test-text {
615 | background-color: white;
616 | margin-left: 40px;
617 | margin-right: 479px;
618 | min-height: 58px;
619 |
620 | }
621 | #modal-body div {
622 | float: left;
623 | width: 166px;
624 | display: inline-block;
625 | /* possibly also height: 300px; */
626 | }
627 | #modal-body div p span {
628 | font-family: serif;}
--------------------------------------------------------------------------------
/bot-application/static/css/style.css~:
--------------------------------------------------------------------------------
1 | @import url(http://weloveiconfonts.com/api/?family=fontawesome|iconicstroke|typicons);
2 | /* fontawesome */
3 | [class*="fontawesome-"]:before {
4 | font-family: 'FontAwesome', sans-serif;
5 | }
6 | /* iconicstroke */
7 | [class*="iconicstroke-"]:before {
8 | font-family: 'IconicStroke', sans-serif;
9 | }
10 | /* typicons */
11 | [class*="typicons-"]:before {
12 | font-family: 'Typicons', sans-serif;
13 | }
14 | body{
15 | font-family:arial,sans-serif;
16 | }
17 | .chat-container {
18 | width: 300px;
19 | margin-right: 20px;
20 | float:right;
21 | overflow:hidden;
22 | }
23 | .top-header {
24 | background: #666;
25 | color: white;
26 | padding: 0.2rem;
27 | position: relative;
28 | overflow: hidden;
29 | border-bottom: 4px solid #35ac19;
30 | cursor:pointer;
31 | }
32 | .top-header:hover {
33 | background-color:#35ac19;
34 | }
35 | .top-header-tit {
36 | display: inline;
37 | font-size: 14px;
38 | }
39 | .top-header .typicons-message {
40 | display: inline-block;
41 | padding: 2px 5px 2px 5px;
42 | font-size: 20px;
43 | position: relative;
44 | top: 5px;
45 | }
46 | .top-header .typicons-minus {
47 | position: relative;
48 | top: 3px;
49 | font-size: 15px;
50 | cursor:pointer;
51 | }
52 | .top-header .typicons-plus {
53 | position: relative;
54 | top: 3px;
55 | font-size: 15px;
56 | }
57 | .top-header .typicons-times{
58 | position: relative;
59 | top: 3px;
60 | font-size: 15px;
61 | }
62 | .top-header .left {
63 | float: left;
64 | }
65 | .top-header .right {
66 | float: right;
67 | padding-top: 5px;
68 | }
69 | .top-header > * {
70 | position: relative;
71 | }
72 | .top-header::before {
73 | content: '';
74 | position: absolute;
75 | top: -100%;
76 | left: 0;
77 | right: 0;
78 | bottom: -100%;
79 | opacity: 0.25;
80 | background-color: #404040
81 | }
82 | .chat-box {
83 | list-style: none;
84 | background: #e5e5e5;
85 | margin: 0;
86 | padding: 0 0 50px 0;
87 | height: 280px;
88 | overflow-y: auto;
89 | }
90 | .chat-box li {
91 | padding: 0.5rem;
92 | overflow: hidden;
93 | display: flex;
94 | }
95 | .chat-box .avatar-icon {
96 | width: 40px;
97 | position: relative;
98 | }
99 | .chat-box .avatar-icon img {
100 | display: block;
101 | width: 100%;
102 | background-color:#1469A6;
103 | }
104 | .ibo .avatar-icon:after {
105 | content: '';
106 | position: absolute;
107 | top: 0;
108 | right: 0;
109 | width: 0;
110 | height: 0;
111 | border: 5px solid white;
112 | border-left-color: transparent;
113 | border-bottom-color: transparent;
114 | }
115 | .me {
116 | justify-content: flex-end;
117 | align-items: flex-end;
118 | }
119 | .me .messages {
120 | order: 1;
121 | border-bottom-right-radius: 0;
122 | }
123 | .me .avatar-icon {
124 | order: 2;
125 | }
126 | .me .avatar-icon:after {
127 | content: '';
128 | position: absolute;
129 | bottom: 0;
130 | left: 0;
131 | width: 0;
132 | height: 0;
133 | border: 5px solid white;
134 | border-right-color: transparent;
135 | border-top-color: transparent;
136 | box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
137 | }
138 | .messages {
139 | background: white;
140 | padding: 10px;
141 | border-radius: 2px;
142 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
143 | }
144 | .messages p {
145 | font-size: 0.8rem;
146 | margin: 0 0 0.2rem 0;
147 | }
148 | .messages time {
149 | font-size: 0.7rem;
150 | color: #ccc;
151 | }
152 | .setting{
153 | background-color: #e5e5e5;
154 | height: 32px;
155 | padding-top: 2px;
156 | border-bottom: 1px solid rgba(0,0,0,.1);
157 | }
158 | .setting .left {
159 | float: left;
160 | }
161 | .setting .right {
162 | float: right;
163 | }
164 | .iconicstroke-user{
165 | font-size: 22px;
166 | position: relative;
167 | top: 4px;
168 | left: 10px;
169 | color: #414141;
170 | cursor:pointer;
171 | }
172 | .typicons-cog{
173 | font-size: 23px;
174 | position: relative;
175 | top: 7px;
176 | right: 4px;
177 | color: #414141;
178 | cursor:pointer;
179 | }
180 | .fontawesome-facetime-video{
181 | font-size: 18px;
182 | position: relative;
183 | top: 3px;
184 | color: #414141;
185 | left: 5px;
186 | cursor:pointer;
187 | }
188 | .iconicstroke-user:hover, .typicons-cog:hover,.fontawesome-facetime-video:hover{
189 | color:#000000;
190 | }
191 | ::-webkit-scrollbar{height:14px;width:10px;background:#eee;border-left:1px solid #ddd}
192 | ::-webkit-scrollbar-thumb{background:#ddd;border:1px solid #cfcfcf}
193 | ::-webkit-scrollbar-thumb:hover{background:#b2b2b2;border:1px solid #b2b2b2}
194 | ::-webkit-scrollbar-thumb:active{background:#b2b2b2;border:1px solid #b2b2b2}
195 | @-webkit-keyframes pulse {
196 | from {
197 | opacity: 0;
198 | }
199 | to {
200 | opacity: 0.5;
201 | }
202 | }
203 |
204 | /************
205 | * response *
206 | ************/
207 | #response {
208 | width:320px;
209 | background-color: rgba(255, 255, 255, 0.8);
210 | }
211 | .say {
212 | width:212px;
213 | padding:8px 15px;
214 | background:rgba(50, 50, 50, 0.2);
215 | border:0px solid #dbdbdb;
216 | }
217 | .saybtn {
218 | position:relative;
219 | padding:6px 15px;
220 | left:-8px;
221 | border:2px solid #207cca;
222 | background-color:#207cca;
223 | color:#fafafa;
224 | }
225 | .saybtn:hover {
226 | background-color:#409cea;
227 | }
228 |
229 | .ace_editor {
230 | border: 1px solid lightgray;
231 | margin: auto;
232 | height: 200px;
233 | width: 80%;
234 | }
235 | .scrollmargin {
236 | height: 80px;
237 | text-align: center;
238 | }
239 | .view{
240 | border: 1px solid lightgray;
241 | margin: auto;
242 | width: 80%;
243 | }
244 | .view div span{
245 | margin: 20px;
246 | display: inline-block;
247 | }
248 | .view div span span{
249 | margin: 0px;
250 | display: inline;
251 | }
252 | .output{
253 | min-height: 70px;
254 | }
255 | .TitleBar {
256 | margin: auto;
257 | width: 80%;
258 | border: 1px solid lightgray;
259 | height: 30px;
260 | border-bottom: 0px;
261 | background-color: #FCFAFA;
262 | font-size:20px;
263 | }
264 | .TitleBar b{
265 | margin:15px;
266 | color: #454444;
267 | }
268 | .actionbar{
269 | margin: auto;
270 | width: 80%;
271 | }
272 | #statusBar {
273 | margin: auto;
274 | width: 80%;
275 | border: 1px solid lightgray;
276 | height: 20px;
277 | border-top: 0px;
278 | }
279 |
280 | .ace_status-indicator {
281 | color: gray;
282 | float:right;
283 | right: 0;
284 | border-left: 1px solid;
285 | }
286 | .submit {
287 | float: right;
288 | border: 1px solid #AAA;
289 | margin-left: 10px;
290 | padding: 4px;
291 | cursor: pointer;
292 | }
293 |
294 |
295 | #custominputfileds {
296 | display:none;
297 | }
298 |
299 | .blinking-cursor {
300 | font-weight: 500;
301 | font-size: 15px;
302 | color: #2E3D48;
303 | -webkit-animation: 1s blink step-end infinite;
304 | -moz-animation: 1s blink step-end infinite;
305 | -ms-animation: 1s blink step-end infinite;
306 | -o-animation: 1s blink step-end infinite;
307 | animation: 1s blink step-end infinite;
308 | }
309 |
310 | @keyframes "blink" {
311 | from, to {
312 | color: transparent;
313 | }
314 | 50% {
315 | color: black;
316 | }
317 | }
318 |
319 | @-moz-keyframes blink {
320 | from, to {
321 | color: transparent;
322 | }
323 | 50% {
324 | color: black;
325 | }
326 | }
327 |
328 | @-webkit-keyframes "blink" {
329 | from, to {
330 | color: transparent;
331 | }
332 | 50% {
333 | color: black;
334 | }
335 | }
336 |
337 | @-ms-keyframes "blink" {
338 | from, to {
339 | color: transparent;
340 | }
341 | 50% {
342 | color: black;
343 | }
344 | }
345 |
346 | @-o-keyframes "blink" {
347 | from, to {
348 | color: transparent;
349 | }
350 | 50% {
351 | color: black;
352 | }
353 | }
354 | #submit:disabled,#SubmitMCQ :disabled {
355 | background-color: white;
356 | }
357 | #submit,#SubmitMCQ {
358 | background: #35ac19;
359 | color: wheat;
360 | }
361 | .submit:hover {
362 | box-shadow: 1px 1px 3px gray;
363 | }
364 | .submit:disabled {
365 | box-shadow: unset;
366 | cursor: unset;
367 | color: lightgrey !important;
368 | background-color: #f6f6f6 !important;
369 | }
370 | #compiler::first-letter {
371 | text-transform: uppercase;
372 | }
373 | @media only screen and (max-height: 480px) {
374 | .chat-box {
375 | height: calc(100vh - 180px);
376 | }
377 |
378 | }
379 | #response{
380 | width: calc(100% + 20px);
381 | }
382 | @media only screen and (max-Width: 340px) {
383 | .chat-container {
384 | width: calc(100vw - 20px);
385 | max-width: 300px;
386 | margin: auto 10px;
387 | }
388 | .say {
389 | width: calc(100% - 108px);
390 | }
391 |
392 | }
393 | .view {
394 | white-space: pre-wrap; /* Since CSS 2.1 */
395 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
396 | white-space: -pre-wrap; /* Opera 4-6 */
397 | white-space: -o-pre-wrap; /* Opera 7 */
398 | word-wrap: break-word; /* Internet Explorer 5.5+ */
399 | }
400 |
401 | #QI {
402 | overflow-x: hidden;
403 | }
404 |
405 | .slide {
406 | opacity: 0;
407 | position: relative;
408 | font-family: Arial;
409 | font-size: 14px;
410 | /*line-height: 50px;*/
411 | right: -100%;
412 | width:100%;
413 | }
414 |
415 | /*.choice {
416 | -webkit-column-count: 2;
417 | -moz-column-count: 2;
418 | column-count: 2;
419 | }*/
420 | .MCanswer {
421 | display: inline-block;
422 | vertical-align: top;
423 | }
424 |
--------------------------------------------------------------------------------
/bot-application/static/css/temporary.css:
--------------------------------------------------------------------------------
1 | .chat_window{
2 | margin-left: 50%;
3 | height: calc(100vh - 120px);
4 | }
5 | .messages{
6 | height: calc(100vh - 250px);
7 | }
8 |
9 | .messages .message.left .text {
10 | color: black !important;
11 | font-weight: inherit;
12 | }
13 |
14 | #msg_input{
15 | color: black;
16 | }
17 |
--------------------------------------------------------------------------------
/bot-application/static/js/bind.js:
--------------------------------------------------------------------------------
1 | var data=[];
2 |
3 | function addBr(text){
4 | return text.replace(/\n/g, "
");
5 |
6 | }
7 | var Message;
8 | Message = function (arg) {
9 | this.text = arg.text, this.message_side = arg.message_side;
10 | this.draw = function (_this) {
11 | return function () {
12 | var $message;
13 | $message = $($('.message_template').clone().html());
14 | $message.addClass(_this.message_side).find('.text').html(addBr(_this.text));
15 | $('.messages').append($message);
16 | return setTimeout(function () {
17 | return $message.addClass('appeared');
18 | }, 0);
19 | };
20 | }(this);
21 | return this;
22 | };
23 |
24 |
25 | function showBotMessage(msg){
26 | message = new Message({
27 | text: msg,
28 | message_side: 'left'
29 | });
30 | message.draw();
31 | $messages.animate({ scrollTop: $messages.prop('scrollHeight') }, 300);
32 | }
33 | function showUserMessage(msg){
34 | $messages = $('.messages');
35 | message = new Message({
36 | text: msg,
37 | message_side: 'right'
38 | });
39 | message.draw();
40 | $messages.animate({ scrollTop: $messages.prop('scrollHeight') }, 300);
41 | $('#msg_input').val('');
42 | }
43 | function sayToBot(text){
44 | document.getElementById("msg_input").placeholder = "Type your messages here..."
45 | $.post("/chat",
46 | {
47 | //csrfmiddlewaretoken:csrf,
48 | text:text,
49 | },
50 | function(jsondata, status){
51 | if(jsondata["status"]=="success"){
52 | response=jsondata["response"];
53 |
54 | if(response){showBotMessage(response);}
55 | }
56 | });
57 |
58 | }
59 |
60 | getMessageText = function () {
61 | var $message_input;
62 | $message_input = $('.message_input');
63 | return $message_input.val();
64 | };
65 |
66 | $("#say").keypress(function(e) {
67 | if(e.which == 13) {
68 | $("#saybtn").click();
69 | }
70 | });
71 |
72 | $('.send_message').click(function (e) {
73 | msg = getMessageText();
74 | if(msg){
75 | showUserMessage(msg);
76 | sayToBot(msg);
77 | $('.message_input').val('');}
78 | });
79 |
80 | $('.message_input').keyup(function (e) {
81 | if (e.which === 13) {
82 | msg = getMessageText();
83 | if(msg){
84 | showUserMessage(msg);
85 | sayToBot(msg);
86 | $('.message_input').val('') ;}
87 | }
88 | });
89 |
--------------------------------------------------------------------------------
/bot-application/static/js/jquery.timeago.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Timeago is a jQuery plugin that makes it easy to support automatically
3 | * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
4 | *
5 | * @name timeago
6 | * @version 1.5.3
7 | * @requires jQuery v1.2.3+
8 | * @author Ryan McGeary
9 | * @license MIT License - http://www.opensource.org/licenses/mit-license.php
10 | *
11 | * For usage and examples, visit:
12 | * http://timeago.yarp.com/
13 | *
14 | * Copyright (c) 2008-2015, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
15 | */
16 |
17 | (function (factory) {
18 | if (typeof define === 'function' && define.amd) {
19 | // AMD. Register as an anonymous module.
20 | define(['jquery'], factory);
21 | } else if (typeof module === 'object' && typeof module.exports === 'object') {
22 | factory(require('jquery'));
23 | } else {
24 | // Browser globals
25 | factory(jQuery);
26 | }
27 | }(function ($) {
28 | $.timeago = function(timestamp) {
29 | if (timestamp instanceof Date) {
30 | return inWords(timestamp);
31 | } else if (typeof timestamp === "string") {
32 | return inWords($.timeago.parse(timestamp));
33 | } else if (typeof timestamp === "number") {
34 | return inWords(new Date(timestamp));
35 | } else {
36 | return inWords($.timeago.datetime(timestamp));
37 | }
38 | };
39 | var $t = $.timeago;
40 |
41 | $.extend($.timeago, {
42 | settings: {
43 | refreshMillis: 60000,
44 | allowPast: true,
45 | allowFuture: false,
46 | localeTitle: false,
47 | cutoff: 0,
48 | autoDispose: true,
49 | strings: {
50 | prefixAgo: null,
51 | prefixFromNow: null,
52 | suffixAgo: "ago",
53 | suffixFromNow: "from now",
54 | inPast: 'any moment now',
55 | seconds: "less than a minute",
56 | minute: "about a minute",
57 | minutes: "%d minutes",
58 | hour: "about an hour",
59 | hours: "about %d hours",
60 | day: "a day",
61 | days: "%d days",
62 | month: "about a month",
63 | months: "%d months",
64 | year: "about a year",
65 | years: "%d years",
66 | wordSeparator: " ",
67 | numbers: []
68 | }
69 | },
70 |
71 | inWords: function(distanceMillis) {
72 | if (!this.settings.allowPast && ! this.settings.allowFuture) {
73 | throw 'timeago allowPast and allowFuture settings can not both be set to false.';
74 | }
75 |
76 | var $l = this.settings.strings;
77 | var prefix = $l.prefixAgo;
78 | var suffix = $l.suffixAgo;
79 | if (this.settings.allowFuture) {
80 | if (distanceMillis < 0) {
81 | prefix = $l.prefixFromNow;
82 | suffix = $l.suffixFromNow;
83 | }
84 | }
85 |
86 | if (!this.settings.allowPast && distanceMillis >= 0) {
87 | return this.settings.strings.inPast;
88 | }
89 |
90 | var seconds = Math.abs(distanceMillis) / 1000;
91 | var minutes = seconds / 60;
92 | var hours = minutes / 60;
93 | var days = hours / 24;
94 | var years = days / 365;
95 |
96 | function substitute(stringOrFunction, number) {
97 | var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
98 | var value = ($l.numbers && $l.numbers[number]) || number;
99 | return string.replace(/%d/i, value);
100 | }
101 |
102 | var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
103 | seconds < 90 && substitute($l.minute, 1) ||
104 | minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
105 | minutes < 90 && substitute($l.hour, 1) ||
106 | hours < 24 && substitute($l.hours, Math.round(hours)) ||
107 | hours < 42 && substitute($l.day, 1) ||
108 | days < 30 && substitute($l.days, Math.round(days)) ||
109 | days < 45 && substitute($l.month, 1) ||
110 | days < 365 && substitute($l.months, Math.round(days / 30)) ||
111 | years < 1.5 && substitute($l.year, 1) ||
112 | substitute($l.years, Math.round(years));
113 |
114 | var separator = $l.wordSeparator || "";
115 | if ($l.wordSeparator === undefined) { separator = " "; }
116 | return $.trim([prefix, words, suffix].join(separator));
117 | },
118 |
119 | parse: function(iso8601) {
120 | var s = $.trim(iso8601);
121 | s = s.replace(/\.\d+/,""); // remove milliseconds
122 | s = s.replace(/-/,"/").replace(/-/,"/");
123 | s = s.replace(/T/," ").replace(/Z/," UTC");
124 | s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
125 | s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
126 | return new Date(s);
127 | },
128 | datetime: function(elem) {
129 | var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
130 | return $t.parse(iso8601);
131 | },
132 | isTime: function(elem) {
133 | // jQuery's `is()` doesn't play well with HTML5 in IE
134 | return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
135 | }
136 | });
137 |
138 | // functions that can be called via $(el).timeago('action')
139 | // init is default when no action is given
140 | // functions are called with context of a single element
141 | var functions = {
142 | init: function() {
143 | var refresh_el = $.proxy(refresh, this);
144 | refresh_el();
145 | var $s = $t.settings;
146 | if ($s.refreshMillis > 0) {
147 | this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
148 | }
149 | },
150 | update: function(timestamp) {
151 | var date = (timestamp instanceof Date) ? timestamp : $t.parse(timestamp);
152 | $(this).data('timeago', { datetime: date });
153 | if ($t.settings.localeTitle) {
154 | $(this).attr("title", date.toLocaleString());
155 | }
156 | refresh.apply(this);
157 | },
158 | updateFromDOM: function() {
159 | $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
160 | refresh.apply(this);
161 | },
162 | dispose: function () {
163 | if (this._timeagoInterval) {
164 | window.clearInterval(this._timeagoInterval);
165 | this._timeagoInterval = null;
166 | }
167 | }
168 | };
169 |
170 | $.fn.timeago = function(action, options) {
171 | var fn = action ? functions[action] : functions.init;
172 | if (!fn) {
173 | throw new Error("Unknown function name '"+ action +"' for timeago");
174 | }
175 | // each over objects here and call the requested function
176 | this.each(function() {
177 | fn.call(this, options);
178 | });
179 | return this;
180 | };
181 |
182 | function refresh() {
183 | var $s = $t.settings;
184 |
185 | //check if it's still visible
186 | if ($s.autoDispose && !$.contains(document.documentElement,this)) {
187 | //stop if it has been removed
188 | $(this).timeago("dispose");
189 | return this;
190 | }
191 |
192 | var data = prepareData(this);
193 |
194 | if (!isNaN(data.datetime)) {
195 | if ( $s.cutoff === 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
196 | $(this).text(inWords(data.datetime));
197 | } else {
198 | if ($(this).attr('title').length > 0) {
199 | $(this).text($(this).attr('title'));
200 | }
201 | }
202 | }
203 | return this;
204 | }
205 |
206 | function prepareData(element) {
207 | element = $(element);
208 | if (!element.data("timeago")) {
209 | element.data("timeago", { datetime: $t.datetime(element) });
210 | var text = $.trim(element.text());
211 | if ($t.settings.localeTitle) {
212 | element.attr("title", element.data('timeago').datetime.toLocaleString());
213 | } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
214 | element.attr("title", text);
215 | }
216 | }
217 | return element.data("timeago");
218 | }
219 |
220 | function inWords(date) {
221 | return $t.inWords(distance(date));
222 | }
223 |
224 | function distance(date) {
225 | return (new Date().getTime() - date.getTime());
226 | }
227 |
228 | // fix for IE6 suckage
229 | document.createElement("abbr");
230 | document.createElement("time");
231 | }));
232 |
--------------------------------------------------------------------------------
/bot-application/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |