summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules6
-rw-r--r--CMakeLists.txt13
-rw-r--r--sentence.cpp668
-rw-r--r--sentence.h38
-rw-r--r--support.cpp77
m---------vendor/libtwittercpp0
m---------vendor/verbly0
m---------vendor/yaml-cpp0
8 files changed, 802 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5c2582e --- /dev/null +++ b/.gitmodules
@@ -0,0 +1,6 @@
1[submodule "vendor/libtwittercpp"]
2 path = vendor/libtwittercpp
3 url = git@github.com:hatkirby/libtwittercpp
4[submodule "vendor/yaml-cpp"]
5 path = vendor/yaml-cpp
6 url = git@github.com:jbeder/yaml-cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..add6b55 --- /dev/null +++ b/CMakeLists.txt
@@ -0,0 +1,13 @@
1cmake_minimum_required (VERSION 3.1)
2project (support)
3
4add_subdirectory(vendor/verbly)
5add_subdirectory(vendor/libtwittercpp)
6add_subdirectory(vendor/yaml-cpp EXCLUDE_FROM_ALL)
7
8include_directories(vendor/verbly/lib vendor/libtwittercpp/src vendor/yaml-cpp/include)
9add_executable(support sentence.cpp support.cpp)
10set_property(TARGET support PROPERTY CXX_STANDARD 11)
11set_property(TARGET support PROPERTY CXX_STANDARD_REQUIRED ON)
12target_link_libraries(support verbly yaml-cpp twitter++)
13
diff --git a/sentence.cpp b/sentence.cpp new file mode 100644 index 0000000..3dabe58 --- /dev/null +++ b/sentence.cpp
@@ -0,0 +1,668 @@
1#include "sentence.h"
2#include <algorithm>
3#include <list>
4#include <set>
5
6sentence::sentence(
7 const verbly::database& database,
8 std::mt19937& rng) :
9 database_(database),
10 rng_(rng)
11{
12}
13
14std::string sentence::generate() const
15{
16 // Generate the form that the sentence should take.
17 std::vector<verbly::token> actions {
18 {"like", verbly::token(std::set<std::string>({"infinitive_phrase", "subjectless"}))},
19 {"have", verbly::token(std::set<std::string>({"gerund_phrase", "subjectless"}))}
20 };
21
22 verbly::token form = actions[
23 std::uniform_int_distribution<int>(0, actions.size()-1)(rng_)];
24
25 // Compile the form.
26 while (!form.isComplete())
27 {
28 visit(form);
29 }
30
31 std::string compiled = form.compile();
32 std::list<std::string> words =
33 verbly::split<std::list<std::string>>(compiled, " ");
34
35 verbly::token cased;
36 for (std::string& word : words)
37 {
38 if (std::bernoulli_distribution(1.0/2.0)(rng_))
39 {
40 cased << verbly::token::capitalize(verbly::token::casing::all_caps, word);
41 } else {
42 cased << word;
43 }
44 }
45
46 return cased.compile();
47}
48
49bool sentence::chooseSelrestr(std::set<std::string> selrestrs, std::set<std::string> choices) const
50{
51 int validChoices = 0;
52 for (const std::string& choice : choices)
53 {
54 if (selrestrs.count(choice))
55 {
56 validChoices++;
57 }
58 }
59
60 return std::bernoulli_distribution(static_cast<double>(validChoices)/static_cast<double>(selrestrs.size()))(rng_);
61}
62
63verbly::word sentence::generateStandardNoun(
64 std::string role,
65 std::set<std::string> selrestrs) const
66{
67 std::geometric_distribution<int> tagdist(0.5); // 0.06
68 std::vector<verbly::word> result;
69 bool trySelection = true;
70
71 while (result.empty())
72 {
73 verbly::filter condition =
74 (verbly::notion::partOfSpeech == verbly::part_of_speech::noun)
75 && (verbly::form::proper == false)
76 //&& (verbly::form::complexity == 1)
77 // && (verbly::word::tagCount >= tagdist(rng_)) // Favor more common words
78 && (verbly::word::tagCount >= 1)
79 && !(verbly::word::usageDomains %= (verbly::notion::wnid == 106718862)); // Blacklist ethnic slurs
80
81 // Only use selection restrictions for a first attempt.
82 if (trySelection)
83 {
84 verbly::filter selection(true);
85
86 for (const std::string& selrestr : selrestrs)
87 {
88 if (selrestr == "concrete")
89 {
90 selection += (verbly::notion::wnid == 100001930); // physical entity
91 } else if (selrestr == "time")
92 {
93 selection += (verbly::notion::wnid == 100028270); // time
94 } else if (selrestr == "state")
95 {
96 selection += (verbly::notion::wnid == 100024720); // state
97 } else if (selrestr == "abstract")
98 {
99 selection += (verbly::notion::wnid == 100002137); // abstract entity
100 } else if (selrestr == "scalar")
101 {
102 selection += (verbly::notion::wnid == 103835412); // number
103 } else if (selrestr == "currency")
104 {
105 selection += (verbly::notion::wnid == 105050379); // currency
106 } else if (selrestr == "location")
107 {
108 selection += (verbly::notion::wnid == 100027167); // location
109 } else if (selrestr == "organization")
110 {
111 selection += (verbly::notion::wnid == 100237078); // organization
112 } else if (selrestr == "int_control")
113 {
114 selection += (verbly::notion::wnid == 100007347); // causal agent
115 } else if (selrestr == "natural")
116 {
117 selection += (verbly::notion::wnid == 100019128); // natural object
118 } else if (selrestr == "phys_obj")
119 {
120 selection += (verbly::notion::wnid == 100002684); // physical object
121 } else if (selrestr == "solid")
122 {
123 selection += (verbly::notion::wnid == 113860793); // solid
124 } else if (selrestr == "shape")
125 {
126 selection += (verbly::notion::wnid == 100027807); // shape
127 } else if (selrestr == "substance")
128 {
129 selection += (verbly::notion::wnid == 100019613); // substance
130 } else if (selrestr == "idea")
131 {
132 selection += (verbly::notion::wnid == 105803379); // idea
133 } else if (selrestr == "sound")
134 {
135 selection += (verbly::notion::wnid == 107111047); // sound
136 } else if (selrestr == "communication")
137 {
138 selection += (verbly::notion::wnid == 100033020); // communication
139 } else if (selrestr == "region")
140 {
141 selection += (verbly::notion::wnid == 105221895); // region
142 } else if (selrestr == "place")
143 {
144 selection += (verbly::notion::wnid == 100586262); // place
145 } else if (selrestr == "machine")
146 {
147 selection += (verbly::notion::wnid == 102958343); // machine
148 } else if (selrestr == "animate")
149 {
150 selection += (verbly::notion::wnid == 100004258); // animate thing
151 } else if (selrestr == "plant")
152 {
153 selection += (verbly::notion::wnid == 103956922); // plant
154 } else if (selrestr == "comestible")
155 {
156 selection += (verbly::notion::wnid == 100021265); // food
157 } else if (selrestr == "artifact")
158 {
159 selection += (verbly::notion::wnid == 100021939); // artifact
160 } else if (selrestr == "vehicle")
161 {
162 selection += (verbly::notion::wnid == 104524313); // vehicle
163 } else if (selrestr == "human")
164 {
165 selection += (verbly::notion::wnid == 100007846); // person
166 } else if (selrestr == "animal")
167 {
168 selection += (verbly::notion::wnid == 100015388); // animal
169 } else if (selrestr == "body_part")
170 {
171 selection += (verbly::notion::wnid == 105220461); // body part
172 } else if (selrestr == "garment")
173 {
174 selection += (verbly::notion::wnid == 103051540); // clothing
175 } else if (selrestr == "tool")
176 {
177 selection += (verbly::notion::wnid == 104451818); // tool
178 } else if ((selrestr == "concrete_inanimate") || (selrestr == "inanimate"))
179 {
180 selection += (verbly::notion::wnid == 100021939); // artifact
181 selection += (verbly::notion::wnid == 100019128); // natural object
182 } else if (selrestr == "non_region_location")
183 {
184 selection += (verbly::notion::wnid == 102913152); // building
185 } else if (selrestr == "non_solid_food")
186 {
187 selection += (verbly::notion::wnid == 107881800); // beverage
188 } else if (selrestr == "solid_food")
189 {
190 selection += (verbly::notion::wnid == 107555863); // solid food
191 } else if (selrestr == "slinky")
192 {
193 selection += (verbly::notion::wnid == 103670849); // line
194 }
195 }
196
197 if (selection.compact().getType() != verbly::filter::type::empty)
198 {
199 condition &= (verbly::notion::fullHypernyms %= std::move(selection));
200 } else if (role == "Attribute")
201 {
202 condition &= (verbly::notion::fullHypernyms %= (verbly::notion::wnid == 100024264)); // attribute
203 } else if (role == "Instrument")
204 {
205 condition &= (verbly::notion::fullHypernyms %= (verbly::notion::wnid == 104451818)); // tool
206 } else if (role == "Agent")
207 {
208 condition &= (verbly::notion::fullHypernyms %= (verbly::notion::wnid == 100007347)); // causal agent
209 }
210
211 trySelection = false;
212 } else {
213 std::cout << "Selection failed" << std::endl;
214 }
215
216 result = database_.words(condition).all();
217 }
218
219 return result.front();
220}
221
222verbly::token sentence::generateStandardNounPhrase(
223 const verbly::word& noun,
224 std::string role,
225 bool plural,
226 bool definite) const
227{
228 verbly::token utter;
229 verbly::word sounder = noun;
230 verbly::word descript;
231
232 /*if (std::bernoulli_distribution(1.0/8.0)(rng_))
233 {
234 std::geometric_distribution<int> tagdist(0.2);
235 descript = database_.words(
236 (verbly::word::tagCount >= tagdist(rng_))
237 && (verbly::notion::partOfSpeech == verbly::part_of_speech::adjective)).first();
238
239 sounder = descript;
240 }*/
241
242 if ((std::bernoulli_distribution(1.0/3.0)(rng_)) && (definite))
243 {
244 utter << "the";
245
246 if (std::bernoulli_distribution(1.0/2.0)(rng_))
247 {
248 plural = true;
249 }
250 } else {
251 if ((role != "Theme") && (role != "Attribute") && std::bernoulli_distribution(1.0/2.0)(rng_))
252 {
253 utter << "your";
254 } else if (!plural) {
255 if (sounder.getBaseForm().startsWithVowelSound())
256 {
257 utter << "an";
258 } else {
259 utter << "a";
260 }
261 }
262 }
263
264 if (descript.isValid())
265 {
266 utter << descript;
267 }
268
269 if (plural && noun.hasInflection(verbly::inflection::plural))
270 {
271 utter << verbly::token(noun, verbly::inflection::plural);
272 } else {
273 utter << noun;
274 }
275
276 return utter;
277}
278
279verbly::token sentence::generateClause(
280 const verbly::token& it) const
281{
282 verbly::token utter;
283 std::geometric_distribution<int> tagdist(0.07);
284 std::vector<verbly::word> verbDataset;
285
286 verbly::filter frameCondition =
287 (verbly::frame::length >= 2)
288 && (verbly::frame::parts(0) %= (
289 (verbly::part::type == verbly::part_type::noun_phrase)
290 && (verbly::part::role == "Agent"))
291 && (verbly::frame::parts(1) %=
292 (verbly::part::type == verbly::part_type::verb))
293 && !(verbly::frame::parts() %= (
294 verbly::part::synrestrs %= "adjp")));
295
296 if (it.hasSynrestr("experiencer"))
297 {
298 frameCondition &=
299 (verbly::frame::parts(2) %=
300 (verbly::part::type == verbly::part_type::noun_phrase)
301 && !(verbly::part::synrestrs %= "genitive")
302 && ((verbly::part::role == "Patient")
303 || (verbly::part::role == "Experiencer")));
304 }
305
306 verbly::filter verbCondition =
307 (verbly::notion::partOfSpeech == verbly::part_of_speech::verb)
308 && frameCondition;
309
310 if (it.hasSynrestr("participle_phrase"))
311 {
312 verbCondition &= (verbly::word::forms(verbly::inflection::ing_form));
313 } else if (it.hasSynrestr("progressive"))
314 {
315 verbCondition &= (verbly::word::forms(verbly::inflection::s_form));
316 } else if (it.hasSynrestr("past_participle"))
317 {
318 verbCondition &= (verbly::word::forms(verbly::inflection::past_participle));
319 }
320
321 // Because of the tag distribution, it's possible (albeit extremely unlikely)
322 // for the verb query to fail, so we loop until it succeeds.
323 while (verbDataset.empty())
324 {
325 verbDataset = database_.words(
326 verbCondition
327 && (verbly::word::tagCount >= tagdist(rng_))
328 ).all();
329 }
330
331 verbly::word verb = verbDataset.front();
332 verbly::frame frame = database_.frames(frameCondition && verb).first();
333 std::list<verbly::part> parts(std::begin(frame.getParts()), std::end(frame.getParts()));
334
335 if (it.hasSynrestr("experiencer"))
336 {
337 // Ignore the direct object.
338 parts.erase(std::next(parts.begin(), 2));
339 }
340
341 if (it.hasSynrestr("subjectless"))
342 {
343 // Ignore the subject.
344 parts.pop_front();
345 }
346
347 for (const verbly::part& part : parts)
348 {
349 switch (part.getType())
350 {
351 case verbly::part_type::noun_phrase:
352 {
353 std::cout << "NP: ";
354 for (auto& s : part.getNounSynrestrs())
355 {
356 std::cout << s << " ";
357 }
358 std::cout << std::endl;
359
360 if (chooseSelrestr(part.getNounSelrestrs(), {"currency"}))
361 {
362 int lead = std::uniform_int_distribution<int>(1,9)(rng_);
363 int tail = std::uniform_int_distribution<int>(0,6)(rng_);
364 std::string tailStr(tail, '0');
365
366 utter << ("$" + std::to_string(lead) + tailStr);
367 } else if (part.nounHasSynrestr("adjp"))
368 {
369 utter << std::set<std::string>({"adjective_phrase"});
370 } else if ((part.nounHasSynrestr("be_sc_ing"))
371 || (part.nounHasSynrestr("ac_ing"))
372 || (part.nounHasSynrestr("sc_ing"))
373 || (part.nounHasSynrestr("np_omit_ing"))
374 || (part.nounHasSynrestr("oc_ing")))
375 {
376 utter << std::set<std::string>({"participle_phrase", "subjectless"});
377 } else if ((part.nounHasSynrestr("poss_ing"))
378 || (part.nounHasSynrestr("possing"))
379 || (part.nounHasSynrestr("pos_ing")))
380 {
381 utter << "your";
382 utter << std::set<std::string>({"participle_phrase", "subjectless"});
383 } else if (part.nounHasSynrestr("adv_loc"))
384 {
385 if (std::bernoulli_distribution(1.0/2.0)(rng_))
386 {
387 utter << "here";
388 } else {
389 utter << "there";
390 }
391 } else if (part.nounHasSynrestr("refl"))
392 {
393 utter << "yourself";
394 } else if ((part.nounHasSynrestr("sc_to_inf"))
395 || (part.nounHasSynrestr("ac_to_inf"))
396 || (part.nounHasSynrestr("vc_to_inf"))
397 || (part.nounHasSynrestr("rs_to_inf"))
398 || (part.nounHasSynrestr("oc_to_inf")))
399 {
400 utter << std::set<std::string>({"infinitive_phrase", "subjectless"});
401 } else if (part.nounHasSynrestr("oc_bare_inf"))
402 {
403 utter << std::set<std::string>({"infinitive_phrase", "bare", "subjectless"});
404 } else if (part.nounHasSynrestr("wh_comp"))
405 {
406 utter << "whether";
407
408 verbly::token sentence(std::set<std::string>({"progressive"}));
409 utter << generateClause(sentence);
410 } else if (part.nounHasSynrestr("that_comp"))
411 {
412 utter << "that";
413 utter << "they";
414
415 verbly::token sentence(std::set<std::string>({"subjectless"}));
416 utter << generateClause(sentence);
417 } else if (part.nounHasSynrestr("what_extract"))
418 {
419 utter << "what";
420
421 verbly::token sentence(std::set<std::string>({"progressive", "experiencer"}));
422 utter << generateClause(sentence);
423 } else if (part.nounHasSynrestr("how_extract"))
424 {
425 utter << "how";
426
427 verbly::token sentence(std::set<std::string>({"progressive"}));
428 utter << generateClause(sentence);
429 } else if (part.nounHasSynrestr("wh_inf"))
430 {
431 utter << "how";
432
433 verbly::token sentence(std::set<std::string>({"infinitive_phrase", "subjectless"}));
434 utter << generateClause(sentence);
435 } else if (part.nounHasSynrestr("what_inf"))
436 {
437 utter << "what";
438
439 verbly::token sentence(std::set<std::string>({"infinitive_phrase", "subjectless", "experiencer"}));
440 utter << generateClause(sentence);
441 } else if (part.nounHasSynrestr("wheth_inf"))
442 {
443 utter << "whether";
444
445 verbly::token sentence(std::set<std::string>({"infinitive_phrase", "subjectless"}));
446 utter << generateClause(sentence);
447 } else if (part.nounHasSynrestr("quotation"))
448 {
449 verbly::token sentence(std::set<std::string>({"participle_phrase"}));
450 while (!sentence.isComplete())
451 {
452 visit(sentence);
453 }
454
455 utter << ("\"" + sentence.compile() + "\"");
456 } else {
457 if (part.nounHasSynrestr("genitive"))
458 {
459 verbly::word noun = generateStandardNoun("Passive", {"animate"});
460 verbly::token owner = generateStandardNounPhrase(noun, "Passive", false, true);
461 std::string ownerStr = owner.compile() + "'s";
462 utter << ownerStr;
463 }
464
465 verbly::word noun = generateStandardNoun(part.getNounRole(), part.getNounSelrestrs());
466
467 bool plural = part.nounHasSynrestr("plural") || chooseSelrestr(part.getNounSelrestrs(), {"group", "plural"});
468
469 utter << generateStandardNounPhrase(
470 noun,
471 part.getNounRole(),
472 plural,
473 part.nounHasSynrestr("definite"));
474
475 if (part.nounHasSynrestr("acc_ing") || part.nounHasSynrestr("ac_ing"))
476 {
477 utter << std::set<std::string>({"participle_phrase", "subjectless"});
478 }
479 }
480
481 break;
482 }
483
484 case verbly::part_type::verb:
485 {
486 std::cout << "V: " << verb.getBaseForm().getText() << std::endl;
487
488 if (it.hasSynrestr("progressive"))
489 {
490 utter << verbly::token(verb, verbly::inflection::s_form);
491 } else if (it.hasSynrestr("past_participle"))
492 {
493 utter << verbly::token(verb, verbly::inflection::past_participle);
494 } else if (it.hasSynrestr("infinitive_phrase"))
495 {
496 if (!it.hasSynrestr("bare"))
497 {
498 utter << "to";
499 }
500
501 utter << verb;
502 } else if (it.hasSynrestr("participle_phrase"))
503 {
504 utter << verbly::token(verb, verbly::inflection::ing_form);
505 } else if (it.hasSynrestr("gerund_phrase"))
506 {
507 utter << verbly::token(verb, verbly::inflection::past_participle);
508 } else {
509 utter << verb;
510 }
511
512 break;
513 }
514
515 case verbly::part_type::preposition:
516 {
517 std::cout << "PREP" << std::endl;
518
519 if (part.isPrepositionLiteral())
520 {
521 int choiceIndex = std::uniform_int_distribution<int>(0, part.getPrepositionChoices().size()-1)(rng_);
522 utter << part.getPrepositionChoices()[choiceIndex];
523 } else {
524 verbly::filter pgf(true);
525 for (const std::string& choice : part.getPrepositionChoices())
526 {
527 pgf += (verbly::notion::prepositionGroups == choice);
528 }
529
530 utter << database_.words(pgf && (verbly::notion::partOfSpeech == verbly::part_of_speech::preposition)).first();
531 }
532
533 break;
534 }
535
536 case verbly::part_type::adjective:
537 {
538 std::cout << "ADJ" << std::endl;
539
540 utter << std::set<std::string>({"adjective_phrase"});
541
542 break;
543 }
544
545 case verbly::part_type::adverb:
546 {
547 std::cout << "ADV" << std::endl;
548
549 utter << std::set<std::string>({"adverb_phrase"});
550
551 break;
552 }
553
554 case verbly::part_type::literal:
555 {
556 std::cout << "LIT" << std::endl;
557
558 utter << part.getLiteralValue();
559
560 break;
561 }
562
563 case verbly::part_type::invalid:
564 {
565 // Nope
566
567 break;
568 }
569 }
570 }
571
572 if ((parts.size() == 1) && (std::bernoulli_distribution(1.0/4.0)(rng_)))
573 {
574 utter << std::set<std::string>({"adverb_phrase"});
575 }
576
577 return utter;
578}
579
580void sentence::visit(verbly::token& it) const
581{
582 switch (it.getType())
583 {
584 case verbly::token::type::utterance:
585 {
586 for (verbly::token& token : it)
587 {
588 if (!token.isComplete())
589 {
590 visit(token);
591
592 break;
593 }
594 }
595
596 break;
597 }
598
599 case verbly::token::type::fillin:
600 {
601 if (it.hasSynrestr("infinitive_phrase") || it.hasSynrestr("gerund_phrase"))
602 {
603 it = generateClause(it);
604 } else if (it.hasSynrestr("adjective_phrase"))
605 {
606 verbly::token phrase;
607
608 if (std::bernoulli_distribution(1.0/6.0)(rng_))
609 {
610 phrase << std::set<std::string>({"adverb_phrase"});
611 }
612
613 if (std::bernoulli_distribution(1.0/4.0)(rng_))
614 {
615 phrase << std::set<std::string>({"participle_phrase", "subjectless"});
616 } else {
617 std::geometric_distribution<int> tagdist(0.2);
618 phrase << database_.words(
619 (verbly::word::tagCount >= tagdist(rng_))
620 && (verbly::notion::partOfSpeech == verbly::part_of_speech::adjective)).first();
621 }
622
623 it = phrase;
624 } else if (it.hasSynrestr("adverb_phrase"))
625 {
626 std::geometric_distribution<int> tagdist(1.0/23.0);
627
628 it = database_.words(
629 (verbly::notion::partOfSpeech == verbly::part_of_speech::adverb)
630 && (verbly::word::tagCount >= tagdist(rng_))
631 ).first();
632 } else if (it.hasSynrestr("participle_phrase"))
633 {
634 if (std::bernoulli_distribution(1.0/2.0)(rng_))
635 {
636 it = verbly::token(
637 database_.words(
638 (verbly::notion::partOfSpeech == verbly::part_of_speech::verb)
639 && (verbly::word::forms(verbly::inflection::ing_form))).first(),
640 verbly::inflection::ing_form);
641 } else {
642 it = generateClause(it);
643 }
644 } else {
645 it = "*the reality of the situation*";
646 }
647
648 break;
649 }
650
651 case verbly::token::type::transform:
652 {
653 visit(it.getInnerToken());
654
655 break;
656 }
657
658 case verbly::token::type::word:
659 case verbly::token::type::literal:
660 case verbly::token::type::part:
661 {
662 // Nope
663
664 break;
665 }
666 }
667}
668
diff --git a/sentence.h b/sentence.h new file mode 100644 index 0000000..e3f2a03 --- /dev/null +++ b/sentence.h
@@ -0,0 +1,38 @@
1#ifndef SENTENCE_H_81987F60
2#define SENTENCE_H_81987F60
3
4#include <verbly.h>
5#include <random>
6#include <string>
7
8class sentence {
9public:
10
11 sentence(
12 const verbly::database& database,
13 std::mt19937& rng);
14
15 std::string generate() const;
16
17private:
18
19 bool chooseSelrestr(std::set<std::string> selrestrs, std::set<std::string> choices) const;
20
21 verbly::word generateStandardNoun(std::string role, std::set<std::string> selrestrs) const;
22
23 verbly::token generateStandardNounPhrase(
24 const verbly::word& noun,
25 std::string role,
26 bool plural,
27 bool definite) const;
28
29 verbly::token generateClause(const verbly::token& it) const;
30
31 void visit(verbly::token& it) const;
32
33 const verbly::database& database_;
34 std::mt19937& rng_;
35};
36
37#endif /* end of include guard: SENTENCE_H_81987F60 */
38
diff --git a/support.cpp b/support.cpp new file mode 100644 index 0000000..8dc6c4e --- /dev/null +++ b/support.cpp
@@ -0,0 +1,77 @@
1#include <verbly.h>
2#include <algorithm>
3#include <iostream>
4#include <random>
5#include <vector>
6#include <yaml-cpp/yaml.h>
7#include <twitter.h>
8#include "sentence.h"
9
10int main(int argc, char** argv)
11{
12 if (argc != 2)
13 {
14 std::cout << "usage: support [configfile]" << std::endl;
15 return -1;
16 }
17
18 std::string configfile(argv[1]);
19 YAML::Node config = YAML::LoadFile(configfile);
20
21 twitter::auth auth;
22 auth.setConsumerKey(config["consumer_key"].as<std::string>());
23 auth.setConsumerSecret(config["consumer_secret"].as<std::string>());
24 auth.setAccessKey(config["access_key"].as<std::string>());
25 auth.setAccessSecret(config["access_secret"].as<std::string>());
26
27 twitter::client client(auth);
28
29 std::random_device randomDevice;
30 std::mt19937 rng{randomDevice()};
31
32 verbly::database database(config["verbly_datafile"].as<std::string>());
33 sentence generator(database, rng);
34
35 for (;;)
36 {
37 verbly::word adjective = database.words(
38 (verbly::notion::partOfSpeech == verbly::part_of_speech::adjective)
39 && (verbly::word::antiPertainyms %=
40 (verbly::word::forms(verbly::inflection::plural)))).first();
41
42 verbly::word noun = database.words(
43 (verbly::notion::partOfSpeech == verbly::part_of_speech::noun)
44 && (verbly::word::pertainyms %= adjective)
45 && (verbly::word::forms(verbly::inflection::plural))).first();
46
47 verbly::token action = {
48 "RT if you ARE",
49 verbly::token::punctuation(",", adjective),
50 "if you SUPPORT",
51 verbly::token::punctuation(",",
52 verbly::token(noun, verbly::inflection::plural)),
53 "or if you",
54 generator.generate()};
55
56 std::string result = action.compile();
57 if (result.length() <= 140)
58 {
59 std::cout << result << std::endl;
60
61 try
62 {
63 client.updateStatus(result);
64
65 std::cout << "Tweeted!" << std::endl;
66 } catch (const twitter::twitter_error& e)
67 {
68 std::cout << "Twitter error: " << e.what() << std::endl;
69 }
70
71 std::this_thread::sleep_for(std::chrono::hours(1));
72
73 std::cout << std::endl;
74 }
75 }
76}
77
diff --git a/vendor/libtwittercpp b/vendor/libtwittercpp new file mode 160000
Subproject df906121dd862c0f704e44f28ee079158c431c4
diff --git a/vendor/verbly b/vendor/verbly new file mode 160000
Subproject 59eab842de02b2b2ba8bf53e2214b558457e635
diff --git a/vendor/yaml-cpp b/vendor/yaml-cpp new file mode 160000
Subproject bedb28fdb4fd52d97e02f6cb946cae631037089