diff --git a/.coverage b/.coverage new file mode 100644 index 0000000..67e8ec9 --- /dev/null +++ b/.coverage @@ -0,0 +1 @@ +!coverage.py: This is a private format, don't read it directly!{"lines":{"/ravestate/modules/ravestate/__init__.py":[1,2,3,4,5,6,7,8,9,10,11],"/ravestate/modules/ravestate/activation.py":[2,3,5,6,7,9,10,11,12,13,14,15,17,18,21,25,28,30,31,32,33,34,35,36,37,38,39,40,41,43,58,61,64,77,88,127,148,159,173,180,192,203,209,216,234,315,321,325,330,333,44,45,46,47,48,49,50,51,52,53,54,55,56,84,85,86,59,62,142,157,68,69,214,143,331,145,146,75,111,112,113,114,115,123,124,190,207,243,247,250,251,252,304,313,255,258,259,260,261,262,264,265,266,267,268,272,276,278,281,282,283,287,288,291,294,295,298,316,317,318,319,334,335,336,337,339,340,346,347,348,349,350,351,352,301,178,367,368,369,370,371,372,375,328,376,377,378,382,169,170,171,323,270,271,273,305,311,116,117,118,119,120,121,125,144,355,360,362,227,228,229,230,231,232,292,306,307,308,309,356,357,244],"/ravestate/modules/ravestate/property.py":[3,4,5,6,8,9,12,22,26,27,28,29,30,31,32,33,34,35,61,64,78,81,84,100,109,112,115,124,141,159,177,183,189,195,201,207,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,58,59,90,91,92,93,94,95,96,62,181,199,187,193,79,212,213,214,216,218,219,220,205,215,217,110,132,135,139,113,136,137,104,105,107,149,152,155,156,157,119,122,167,170,171,172,150,151,168,169,106],"/ravestate/modules/ravestate/constraint.py":[1,2,3,4,5,8,9,12,15,16,18,22,25,27,31,35,39,44,45,49,53,57,61,66,70,72,73,74,75,76,77,84,89,91,93,112,120,131,135,138,141,144,147,150,154,166,170,171,188,196,200,204,207,217,222,227,233,240,242,250,254,263,264,265,266,268,277,281,289,300,303,306,309,312,319,334,338,339,345,351,354,358,369,373,384,385,387,394,398,406,421,424,428,434,438,439,443,447,451,455,459,94,95,96,97,98,99,100,101,102,108,109,110,243,244,245,246,247,248,269,270,273,136,251,274,275,388,389,392,304,19,218,219,220,223,224,225,121,122,145,113,115,116,422,425,426,313,314,315,316,317,310,132,307,429,430,431,320,322,323,324,327,328,155,156,157,159,161,162,163,330,331,332,432,452,453,355,356,201,205,167,202,164,28,29,32,33,36,37,40,41,46,47,50,51,148,114,123,125,126,127,395,396,128,278,279,129,435,335,326,172,173,184,185,186,190,191,192,193,194,142,117,118,124,290,291,282,284,285,286,287,292,293,294,295,296,298,283,399,401,402,400,403,404,407,408,409,411,412,413,414,416,417,418,419,301,440,441,340,341,448,449,352,151,152,133,444,445,346,347,342,343,456,457,362,363,364,365,208,209,210,211,212,213,214,215,366,367,174,175,176,179,348,349],"/ravestate/modules/ravestate/spike.py":[3,4,5,6,8,9,12,17,20,23,26,29,32,37,42,45,48,51,55,56,57,58,94,97,100,103,112,120,132,144,171,179,185,191,201,207,74,75,76,78,79,80,81,82,83,84,85,86,87,88,89,91,92,118,101,189,205,98,95,77,127,128,129,130,156,157,158,160,162,164,165,166,167,168,211,183,110,90,177,161,139,142],"/ravestate/modules/ravestate/causal.py":[3,4,5,6,8,9,12,20,23,25,43,66,67,68,69,70,71,72,83,84,85,86,87,100,101,102,103,104,109,112,114,131,136,148,159,162,165,172,216,247,286,336,348,360,382,398,422,427,444,453,118,119,120,121,122,123,126,128,129,139,140,141,145,146,423,424,149,150,151,153,163,234,237,238,240,241,125,242,428,429,430,431,433,436,437,439,244,166,167,170,245,132,133,134,263,275,264,276,282,284,160,180,183,186,187,367,369,370,373,377,378,380,188,368,189,196,199,205,206,209,210,211,212,213,214,389,394,396,390,300,301,302,303,308,309,310,311,312,313,314,324,333,334,346,406,407,408,409,425,277,278,265,266,267,268,273,279,280,315,316,317,318,325,326,327,328,331,321,322,413,419,420,374,375,376,270,379,438,440,445,446,447,442,460,461,462,448,449,450,451,463,464,465,466,467,468,469,470,473,474,475,476,477,481,485,441,169,471,472,478,480,395,391,392,393],"/ravestate/modules/reggol/__init__.py":[1,2,3,5,6,7,9,10,13,24,38,64,65,66,67,68,71,80,91,92,93,94,21,95,32,34,35,52,53,54,55,56,57,58,59,60,77,88],"/ravestate/modules/reggol/colored_formatter.py":[1,2,5,22,23,24,25,27,29,30,31,32,33,36,38,40,46,41,42,43,44,47,48,49,50,53,13,14,15,16,17,18,19,54],"/ravestate/modules/reggol/logger.py":[1,2,3,5,7,8,10,11,12,13,14,17,19,26,27,28,36,42,46,20,21,22,37,38,39,40,30,31,32,33,34],"/ravestate/modules/ravestate/threadlocal.py":[1,5],"/ravestate/modules/ravestate/state.py":[3,4,6,7,8,9,11,12,15,18,21,24,27,30,38,39,43,47,48,51,57,58,62,67,68,71,75,77,78,79,80,81,82,83,84,85,87,88,89,90,91,95,103,104,105,106,107,162,166,169,172,175,189,197,209,224,225,226,227,228,229,230,231,246,258,248,249,250,251,252,253,254,255,256,257,109,110,111,112,115,120,122,124,125,126,127,128,129,132,139,142,143,144,145,146,147,148,149,150,151,152,153,154,155,158,159,160,123,140,121,173,194,195,170,182,183,163,164,59,202,203,204,220,167,133,134,135,40,207,184,185,186],"/ravestate/modules/ravestate/consumable.py":[4,6,7,10,14,16,17],"/ravestate/modules/ravestate/wrappers.py":[3,4,5,6,7,8,9,11,12,15,22,24,29,45,49,62,101,123,144,154,158,160,182,190,200,217,220,223,228,259,293,161,162,163,164,165,168,31,32,33,34,35,36,37,39,40,41,42,70,73,99,46,47,75,83,92,93,94,95,96,97,98,77,78,79,80,81,82,170,171,172,174,175,176,177,178,179,180,85,86,87,88,89,90,209,215,218,221,240,243,245,246,110,113,114,115,116,117,118,119,120,247,248,249,250,251,252,253,254,297,299,300,148,151,191,193,194,55,58,59,183,185,186,268,270,271,274,275,276,131,134,135,136,137,138,139,140,141,277,279,281,282,285,283,284,43,60,56,57,71,72,121,142,184,224,225,226,192,298,244,195,196,210,211,212,213,214],"/ravestate/modules/ravestate/module.py":[3,4,5,7,8,9,10,12,13,16,27,29,30,32,69,77,80,100,111,47,49,50,51,52,53,54,55,56,57,59,60,61,62,63,67,70,71,74,75,81,82,85,86,87,90,93,94,95,88,89,78,48,91,92,108,122,123,58,72,83,84],"/ravestate/modules/ravestate/argparser.py":[3,4,5,6,8,9,12,26,27,28,30,31,32,48,51,52,58,59,72,73,79,80,81,84,86,87,88,89,95,97,98,99,100,108,109,110,54,56,112,61,63,64,65,66,69,70,67,75,77],"/ravestate/modules/ravestate/config.py":[4,5,6,8,9,11,13,14,17,31,33,45,59,75,94,124,137,162,40,41,42,54,56,57,169,170,85,88,89,92,144,145,146,150,151,152,153,154,155,156,159,160,43,70,73,171,175,177,178,105,108,109,112,113,118,119,120,121,122,55,114,115,116,117,71,72,106,107,110,111,130,131,132,133,134,135,172,173,86,87],"/ravestate/modules/ravestate/context.py":[2,3,4,5,6,7,8,10,12,13,14,15,16,17,18,19,20,22,23,26,27,28,30,31,34,41,48,50,51,52,53,54,55,56,57,58,60,61,62,63,64,65,66,67,68,71,79,89,90,94,97,104,105,106,108,110,111,112,113,114,121,125,126,127,128,129,136,138,139,140,141,143,185,217,236,247,253,262,281,347,369,389,413,433,450,467,484,505,516,535,626,630,633,639,653,668,675,686,692,697,707,733,755,784,789,154,155,156,157,158,159,160,161,162,163,164,167,271,274,276,277,278,279,654,656,658,659,660,661,378,382,384,386,387,634,636,637,662,663,635,664,666,168,446,447,627,171,175,179,180,288,293,294,299,300,307,316,317,322,323,324,325,524,525,526,527,530,531,326,329,693,695,532,332,335,336,698,699,700,701,702,703,708,710,722,723,735,737,740,745,746,747,748,736,724,731,749,750,751,753,728,729,711,712,713,714,715,716,717,718,719,720,704,705,338,340,669,670,671,672,673,344,345,459,461,462,463,514,204,206,207,208,209,210,211,212,213,214,215,205,226,227,228,229,230,240,243,244,785,786,245,257,258,259,260,241,242,251,396,400,401,402,404,405,640,641,642,643,644,646,647,648,649,650,651,407,408,409,410,411,355,358,360,363,676,678,679,682,683,684,365,367,356,357,318,533,741,361,680,681,397,398,289,290,687,688,301,302,306,308,309,313,303,304,310,311,295,296,379,380,428,429,430,75,76,172,176,177,181,182,628,665,550,554,555,559,560,561,580,581,582,584,585,586,587,593,594,595,599,690,600,498,499,502,503,601,631,605,606,607,608,616,617,618,622,624,756,757,758,759,760,761,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,565,566,567,568,576,583,610,611,612,762,477,478,481,482,569,570,571,572,573,574,431,657,655,778,779,780,781,782,794,795,796,797,798,799,800,801,802,804,803],"/ravestate/modules/ravestate/receptor.py":[2,3,4,5,6,7,10,36,56,38,41,42,43,44,45,46,47,48,50,54,52,39],"/ravestate/modules/ravestate/testfixtures.py":[1,3,4,6,8,9,10,11,12,13,15,16,18,19,20,21,24,33,42,51,60,69,74,75,81,88,93,94,98,99,104,109,26,29,30,71,76,77,78,83,84,85,95,100,101,106,35,38,39,44,47,48,53,56,57,62,65,66,90],"/ravestate/modules/ravestate_conio/__init__.py":[2,3,5,6,9,11,12,17,13,19],"/ravestate/modules/ravestate_rawio/__init__.py":[1,3,5,6,7,8,9,10,12,13,14,15,16,17,18,20,21,22,23,24,25,28],"/ravestate/modules/ravestate_fillers/__init__.py":[1,3,4,5,8,10,11,12],"/ravestate/modules/ravestate_idle/__init__.py":[1,3,4,6,7,10,11,14,16,17,19,20,21,22,23,30,31,32,33,27,34,28],"/ravestate/modules/ravestate_verbaliser/__init__.py":[1,2,3,5,6,8,10,11,12,13,14,15,16,18,24,25,26,27,29],"/ravestate/modules/ravestate_verbaliser/verbaliser.py":[1,2,3,4,6,7,8,15,16,17,18,21,35,68,80,92,104,116,128,140,153,165,178,190,203,215,28,29,30,44,45,46,48,49,50,53,62,54,55,58,89,125,113,77,150,137,101,51,52,162,175,187,200,212,225,63,64,65,56,57],"/ravestate/modules/ravestate_verbaliser/qa_phrases.py":[1,4,10,35,36,37,38,39,40,42,51,52,54,60,53,5,6,55,56,57,58,59,61,62,63,64,65,7],"/ravestate/modules/ravestate_phrases_basic_en/__init__.py":[2,3,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21],"/ravestate/modules/ravestate_nlp/__init__.py":[1,3,4,5,7,8,9,10,12,13,16,42,19,20,25,26,29,31,34,35,36,37,38,39,45,47,48,49,50,51,52,53,54,56,57,58,59,60,62,103,108,113,119,125,131,64,65,67,68,70,71,72,74,75,76,78,79,80,82,83,84,86,87,88,90,91,135,136,92,93,95,32,96,97,99,100,101,127,128,121,122,123,110,105,115,116,111,106],"/ravestate/modules/ravestate_nlp/question_word.py":[1,4,5,6,7,8,9,10,11,13,15,16,17,18,19,20,21,24,25,26,27,28,29,30],"/ravestate/modules/ravestate_nlp/triple.py":[1,2,3,4,7,9,10,11,12,14,19,22,25,28,31,34,37,40,43,46,49,52,64,93,101,110,121,124,15,20,16,23,17,26,53,54,55,56,57,58,59,60,61,62,32,103,105,107,125,122,111,113,114,116,117,118,38,108,29,112,119,71,73,85,87,74,75,83,88,89,76,78,79,80,81,82,91,77,104,94,97,98,99,50,95],"/ravestate/modules/ravestate_nlp/triple_match_result.py":[1,3,8,11,4,5,6,9],"/ravestate/modules/ravestate_nlp/extract_triples.py":[1,2,3,5,6,7,8,9,10,13,50,41,42,43,44,55,56,57,62,64,65,66,67,68,70,63,45,46,47,58,59,60,61,69],"/ravestate/modules/ravestate_nlp/yes_no.py":[1,3,4,5,6,7,10,11,12,13,14,15,16,19,20,22,66,74,79,84,89,94,98,23,24,26,27,28,29,30,32,42,55,61,64,102,90,92,43,46,53,54,75,76,56,59,60,62,63,33,36,39,40,41,34,35,37,38,77,80,81,82,47,68,69,70,72,50,51,57,58,85,86,87],"/ravestate/modules/ravestate_interloc/__init__.py":[1,2,3,5,6,8,9,11,12,15,18,19,20,22,35,24,25,26,27,28,29,30,31,32,33],"/ravestate/modules/ravestate_ontology/__init__.py":[1,2,3,5,6,8,9,11,13,14,16,17,18,20,21,22,24,25,26,29,31,62,70,44,46,47,48,49,50,51,59,71,72,75,63,64,67],"/ravestate/modules/ravestate_ontology/dummy_session.py":[1,4,7,9,12,15,18,21],"/ravestate/modules/ravestate_persqa/__init__.py":[1,2,3,4,5,6,7,9,10,11,12,14,15,16,18,19,21,23,24,25,26,27,28,29,30,31,32,39,46,48,49,50,51,52,53,54,56,57,58,59,60,61,62,64,65,66,67,68,69,70,72,73,74,75,76,77,79,81,83,89,98,171,172,173,174,175,182,183,184,185,192,199,201,202,203,204,228,229,230,231,232,179,180,100,102,103,104,105,106,107,108,109,110,148,149,150,151,152,168,169,111,112,114,115,118,119,120,121,122,123,194,195,211,212,214,215,216,218,220,221,224,225,226,237,238,239,240,241,242,244,245,247,249,250,251,90,91,92,93,96,255,256,257,267,268,269,270,197,117,84,85,86,222,223,258,259,260,261,262,263,264,265],"/ravestate/modules/ravestate_roboyqa/__init__.py":[1,2,3,4,5,6,8,9,10,12,13,14,16,17,19,21,24,25,26,27,29,33,151,249,62,63,65,66,67,68,71,152,153,155,156,157,158,159,161,162,163,165,166,167,169,170,171,172,173,175,176,177,178,179,180,182,183,184,185,187,188,189,190,191,193,194,195,197,198,199,200,201,203,204,205,206,207,211,212,214,215,216,219,220,221,222,223,224,225,226,228,229,231,232,233,234,235,236,237,238,239,240,241,242,243,245,246,72,73,74,80,82,83,86,103,110,111,113,115,118,119,135,139,140,141,143,144,69,87,89,91,93,96,97,98,120,124,125,126,127,254,255,256,257,258,261,94,95,88,136,137,104,105,106,107,112,114,116,99,100,92,90],"/ravestate/modules/ravestate_telegramio/__init__.py":[1,2,4,5,6,7,12,14,17,19,21,24,25,26,27,29,30,31,32,33,34],"/ravestate/modules/ravestate_telegramio/telegram_bot.py":[1,2,3,4,5,6,7,8,10,12,13,15,16,17,19,20,22,23,24,25,26,29,30,31,32,33,34,37,38,40,43,46,53,57,59,60,61,62,65,66,306,333,334,342,343,348,349,354,355,360,361,71,72,78,79,85,86,93,132,139,157,170,192,198,241,274,298,299,300,301,246,247,248,249,250,251,252,253,254,255,338,339,311,314,316,317,318,319,324,325,327,330,41,47,44],"/ravestate/modules/ravestate_emotion/__init__.py":[1,3,4,5,6,7,10,11,12,13,15,16,17,18,21,23,25,26,27,28,30,31,37,38,44,45,51,52],"/ravestate/modules/ravestate_visionio/__init__.py":[1,2,3,4,6,7,8,9,10,11,13,14,16,17,18,19,28,30,31,32,33,34,35,38,39,40,41,42,43,46,48,49,50,51,52,53,54,57,58,59,60,61,64,65,74,75,76,78,91,92,93,94,96,162,163,164,166,184,84,89,103,104,107,108,109,111,112,114,116,117,118,120,121,122,133,137,151,152,154,155,156,157,158,159,128,129,130],"/ravestate/modules/ravestate_visionio/faceoraclefilter.py":[1,2,3,4,6,7,9,10,11,21,22,25,26,29,31,63,137,150,170,188,41,46,51,56,61,72,73,76,79,95,109,112,131,132,133,135,157,158,159,160,161,162,163,164,165,166,167,117,141,142,144,148,118,126,128,129],"/ravestate/modules/ravestate_hibye/__init__.py":[1,3,4,5,6,8,10,11,13,15,16,17,26,27,18,19,20,21,22,24],"/ravestate/modules/ravestate_genqa/__init__.py":[1,2,4,5,6,7,9,10,12,13,15,16,18,21,23,32,36,62,25,26,27,28],"/ravestate/modules/ravestate/__main__.py":[],"/ravestate/modules/ravestate_wildtalk/server.py":[],"/ravestate/modules/ravestate_wildtalk/convai_gpt_backend.py":[],"/ravestate/modules/ravestate_wildtalk/__init__.py":[],"/ravestate/modules/ravestate_wildtalk/gpt2_backend.py":[],"/ravestate/modules/ravestate_wildtalk/parlai_backend.py":[]}} \ No newline at end of file diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..92b5c7e --- /dev/null +++ b/.coveragerc @@ -0,0 +1,17 @@ +[run] +omit = + # exclude roboyio, too volatile + */ravestate_roboyio/* + # exclude ui + */raveboard/* + */ravestate_ui/* + # exclude akinator + */ravestate_akinator/* + # exlude interfaces + */ravestate/i* + # exlude ros1 abstraction + */ravestate_ros1/* + # exlude ros2 abstraction + */ravestate_ros2/* + # exclude sendpics, nobody cares + */ravestate_sendpics/* diff --git a/.gitignore b/.gitignore index 46846de..621ba4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.key *.default -.coverage .pytest_cache .idea __pycache__ @@ -17,3 +16,4 @@ ros2/install ros2/log venv/* mkdocs.yml +db/* diff --git a/.travis.yml b/.travis.yml index 49320c4..ad3b178 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,21 +2,19 @@ language: python os: linux python: - "3.6" - + # Enable 3.7 without globally enabling sudo and dist: xenial for other build jobs matrix: include: - python: 3.7 dist: xenial sudo: true - -# command to install dependencies -install: - - pip install -r requirements.txt -r requirements-dev.txt -# command to run tests -script: - - ./run_tests.sh +services: docker + +before_install: + - docker build -t ravestate . + +script: docker run -t -v $(pwd):/ravestate -w /ravestate ravestate ./run_tests.sh -after_success: - - codecov +after_success: codecov diff --git a/CODEOWNERS b/CODEOWNERS index 624e4bf..97ded95 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,3 @@ # These owners will be the default owners for everything in the repo. -* @toseban @NeginsCode @josephbirkner @l-laura @emlozin +* @toseban @NeginsCode @josephbirkner @l-laura @emlozin @nbasargin + diff --git a/Dockerfile b/Dockerfile index 39b3666..4eefe3e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,56 @@ -FROM missxa/melodic-crystal-roboy +FROM missxa/melodic-dashing-roboy +# PLEASE INSERT ADDITIONAL LAYERS AT THE END OF THE FILE + +# ------------------------------------------------------ +# install neo4j +RUN wget -O - https://debian.neo4j.org/neotechnology.gpg.key | apt-key add - +RUN echo 'deb https://debian.neo4j.org/repo stable/' | tee /etc/apt/sources.list.d/neo4j.list +RUN apt-get update && apt-get install -y neo4j +RUN neo4j-admin set-initial-password test + +# ------------------------------------------------------ +# install redis +RUN apt-get install -y redis + +# ------------------------------------------------------ # install ravestate dependencies ADD requirements.txt /tmp/requirements.txt ADD requirements-dev.txt /tmp/requirements-dev.txt RUN pip3 install -r /tmp/requirements.txt RUN pip3 install -r /tmp/requirements-dev.txt + +# ------------------------------------------------------ +# download wildtalk and spacy models +RUN python3 -c "from roboy_parlai import wildtalk" +RUN python3 -c "from pytorch_pretrained_bert import cached_path; \ + cached_path('https://s3.amazonaws.com/models.huggingface.co/transfer-learning-chatbot/finetuned_chatbot_gpt.tar.gz')" +RUN python3 -c "from pytorch_transformers import GPT2Tokenizer, GPT2LMHeadModel; \ + GPT2Tokenizer.from_pretrained('gpt2-medium'); GPT2LMHeadModel.from_pretrained('gpt2-medium')" +RUN python3 -c "from spacy.cli import download as spacy_download; spacy_download('en_core_web_sm')" + +# ------------------------------------------------------ +# install pyroboy with melodic +# add github repo metadata to bust cache when repo is updated +# => bad idea due to github API rate limit, fails Travis builds now and then. +# ADD https://api.github.com/repos/roboy/pyroboy/git/refs/heads/melodic pyroboy_version.json +RUN cd ~/melodic_ws/src && git clone https://github.com/Roboy/pyroboy.git && \ + cd ~/melodic_ws/src/pyroboy && git checkout melodic && \ + cd ~/melodic_ws/src/roboy_communication && git pull && \ + cd ~/melodic_ws && . /opt/ros/melodic/setup.sh && catkin_make && . /opt/ros/melodic/setup.sh + +# ------------------------------------------------------ +# install face_oracle +RUN pip3 install ecdsa +RUN pip install -U face_recognition websocket_client pillow opencv-python numpy +# add github repo metadata to bust cache when repo is updated +# => bad idea due to github API rate limit, fails Travis builds now and then. +# ADD https://api.github.com/repos/roboy/face_oracle/git/refs/heads/visionio_messages faceoracle_version.json +RUN cd ~/melodic_ws/src && git clone https://github.com/Roboy/face_oracle.git && \ + cd ~/melodic_ws/src/face_oracle && git checkout visionio_messages && git pull && cd ~/melodic_ws && \ + . /opt/ros/melodic/setup.sh && catkin_make && . /opt/ros/melodic/setup.sh + +# install speech recognition requirements and download speech recognition +# RUN apt install -y libasound-dev portaudio19-dev libportaudio2 libportaudiocpp0 python3-pyaudio +# RUN pip3 install webrtcvad monotonic SpeechRecognition pyaudio +# RUN cd /root/ros2_ws/src && git clone https://github.com/Roboy/ros2_speech_recognition.git diff --git a/README.md b/README.md index 27f5cf7..c236736 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,12 @@ \____/ \____/ Olà! - ``` -Ravestate is a reactive library for real-time natural language dialog systems. It combines elements from event-based and reactive programming into an API, where application states are defined as functions that are run when a certain boolean set of criteria (signals) in the current application context is satisfied. It is the first reactive API to allow for boolean combinations of events. You may find a short introductory video [here](http://www.youtube.com/watch?v=6GMmY-xvA_Y "Introduction to Ravestate"). +Ravestate is a reactive library for real-time natural language dialog systems. +It combines elements from event-based and reactive programming into an API, +where application states are defined as functions that are run when a certain +boolean set of criteria (signals) in the current application context is satisfied. +It is the first reactive API to allow for boolean combinations of events. +You may find a short introductory video [here](http://www.youtube.com/watch?v=6GMmY-xvA_Y "Introduction to Ravestate"). ### Reactive Hello World @@ -31,7 +36,7 @@ import ravestate_conio # Ravestate applications should always be wrapped in a Module. # This allows easier scoping, and enables separation of concerns # beyond states. -with rs.Module(name="hi!"): +with rs.Module(name="hi!", depends=(rawio.mod,)): # Create an application state which reacts to the `:startup` signal, # and writes a string to raw:out. Note: State functions are @@ -41,14 +46,22 @@ with rs.Module(name="hi!"): context[rawio.prop_out] = "Waddup waddup waddup!" # Run context with console input/output and our 'hi!' module. -rs.Context("conio", "hi!").run() +rs.Context("hi!").run() ``` -### Visualization +### Raveboard -Ravestate has a [d3.js](https://d3js.org)-based visualization. When using `ravestate_ui.UIContext` instead of `Context`, or `python3 -m ravestate_ui` instead of `python3 -m ravestate`, a real-time visualization of all states/properties/signals in the state machine will be hosted on port 5001. Here is the view of `http://localhost:5001` after launching `python3 ravestate_ui -f generic.yml`: +Ravestate has an [angular](https://angular.io)/[socket.io](https://socket.io)-based +interactive (beta) UI called __Raveboard__. It shows the events (spikes) that are +currently relevant, as well as potential state activations that are referencing these spikes. - +When using `raveboard.UIContext` instead of `Context`, or `python3 -m raveboard` instead of +`python3 -m ravestate`, a real-time visualization of all spikes/activations, as well as a chat window, +will be hosted on a configurable port. You can find dedicated docs [here](modules/raveboard/README.md). + +The following GIF shows raveboard together with [ravestate_visionio](modules/ravestate_visionio/README.md): + +![Raveboard](resources/docs/raveboard.gif) ## Installation @@ -68,15 +81,87 @@ For reliability, we recommend using an environment virtualization tool, like [virtualenv](https://virtualenv.pypa.io/en/latest/) or [conda](https://conda.io/en/latest/). -### For developers +### Via Docker/Docker-compose + +#### Why Docker? + +Ravestate offers a docker image that bundles runtime dependencies that are required +for advanced cognitive dialog systems/chatbots: + +* [📦 Neo4j](https://neo4j.com): The Neo4j Graph DBMS is used by [Scientio](https://github.com/roboy/scientio) for long-term memory. +* [💡 Redis](https://redis.io): A Redis in-memory DB is used for fast short-term memory, e.g. to store/recall facial feature vectors. +* [🤦 FaceOracle](https://github.com/roboy/face_oracle): A Roboy-developed server-client architecture used by `ravestate_visionio` for real-time face recognition. +* [🤖 ROS Melodic](https://ros.org): Version 1 of the *Robot Operating System* for distributed real-time communication. + This version of ROS requires a broker process (`roscore`), which is started automatically inside the container. +* [🤖 ROS2 Dashing](https://index.ros.org/doc/ros2): Version 2 of the *Robot Operating System* for distributed real-time communication. +* [🤗 HuggingFace Transformer Models](https://github.com/huggingface/transformers): Language models (ConvAI GPT/OpenAI GPT2) + for neural-network-generated conversation. +* [💌 Roboy ROS Messages](https://github.com/roboy/roboy_communication): Message defs. that are required to interact with Roboy hardware. + +Installing these dependencies by hand is time-consuming and error-prone, so using Docker +to ship them makes everyone's lives easier! + +#### How to build? + +Clone ravestate: + +```bash +git clone git@github.com:roboy/ravestate && cd ravestate +``` + +You can build the ravestate container using the provided `Dockerfile`: + +```bash +docker build -t ravestate . +``` + +__Note: Building the container takes time and requires a good internet connection, since +all of the dependencies are several Gigabytes in size.__ + +#### How to run? + +Use one of the following docker-compose commands to run ravestate in Docker: + +Platform | Command +---------|--------------------- +Linux | `docker-compose up -d rs-linux` +macOS | `docker-compose up -d rs-macos` +Windows | Not supported yet. + +The container is now running and a shell inside the container can be opened with: + +```bash +docker exec -it rs bash +``` + +You can now start ravestate or raveboard as described in the section [Running Hello World](#running-hello-world). + +```bash +python3 -m ravestate [...] +``` + +#### Which services are exposed from the container? + +Service | Port | Description +---------|------|------------------------------------- +Neo4j UI | 7474 | Neo4j UI for DB stored under `/db/neo4j` +Neo4j Bolt Interface | 7687 | Communication with Neo4j DBMS +Redis Database Dump | - | A dump of the Redis DB in the container can be found under `/db/redis` +FaceOracle Client Interface | 8088 | Visualisation for the FaceOracle client. +Raveboard | 42424 | Default port for raveboard, the ravestate debug UI. + + +### For development #### Initial configuration and setup Clone the repository and install dependencies: ```bash +cd ~ + # Create a virtual python environment to not pollute the global setup -python3 -m virtualenv python-ravestate +python3 -m virtualenv -p python3 python-ravestate # Source the virtual environment . python-ravestate/bin/activate @@ -94,18 +179,9 @@ pip install -r requirements-dev.txt pip install -e . ``` -Now, launch a Neo4j docker instance to serve [Scientio](https://github.com/roboy/scientio), so the dialog system has a memory: -```bash -docker run \ - --publish=7474:7474 --publish=7687:7687 \ - --volume=$HOME/neo4j/data:/data \ - --volume=$HOME/neo4j/logs:/logs \ - neo4j:latest - -# Open the address localhost:7474 in a browser, and enter the -# credentials `neo4j`/`neo4j`. You will then be prompted to enter -# your own password. Remember this password. -``` +Launch the ravestate docker container as described above. It will serve you Neo4j, +which is a backend for [Scientio](https://github.com/roboy/scientio), Roboy's +long-term memory system. In the `config` folder, create a file called `keys.yml`. It should have the following content: @@ -114,19 +190,16 @@ module: telegramio config: telegram-token: # This is where your own telegram bot token # will go later ---- -module: ontology -config: - neo4j_address: bolt://localhost:7687 # Your neo4j server uri here - neo4j_username: neo4j # Your neo4j user here - neo4j_pw: test # Your neo4j pw here ``` You may now conduct your first conversation with ravestate: ```bash -python3 -m ravestate -f config/generic.yml -f config/keys.yml +python3 -m raveboard -f config/generic.yml -f config/keys.yml ``` +Open raveboard on `localhost:42424/ravestate/index.html?rs-sio-url=http%3A//localhost%3A42424` +to conduct your first conversation with ravestate. + After the conversation, check the Neo4j interface under `localhost:7474`. It should now contain some nodes! __Reminder: Whenever you use ravestate from the command line, source the virtual environment first!__ @@ -143,10 +216,10 @@ just run `telegram_test.yml` instead of `generic.yml`. This will load the `raves 3. Mark the `modules` folder as sources root via the right-click context menu. 4. Create a run config via the "Edit configurations menu":
• Create a new Python configuration.
- • Set `modules/ravestate/__main__.py` as the script to execute
+ • Set `raveboard` as the __module__ to execute
• Set the working directory to the git clone directory.
• Set parameters to `-f config/generic.yml -f config/keys.yml`.
-5. You should now be able to run the generic ravestate config from pycharm. +5. You should now be able to run the generic ravestate config from PyCharm. ## Running Hello World @@ -191,7 +264,7 @@ Then, run `ravestate` with this config file: python3 -m ravestate -f hello_world.yml ``` -## Module overview +## Modules Ravestate offers a landscape of fine-grained modules for different aspects of dialog application tasks, which @@ -202,7 +275,6 @@ External (Red) and Skills (Green): #### Core Modules - | Module name | Description | |----------------------|-------------| @@ -213,7 +285,9 @@ External (Red) and Skills (Green): | ravestate_idle | Provides `bored` and `impatient` signals, as specified [here](https://github.com/Roboy/ravestate/issues/12). | ravestate_verbaliser | Utilities for easy management of conversational text, documented [here](modules/ravestate_verbaliser/README.md). | ravestate_nlp | Spacy-based NLP properties and signals, documented [here](modules/ravestate_nlp/README.md). - | ravestate_ros2 | Provides specific `Ros2PubProperty`, `Ros2SubProperty` and `Ros2CallProperty` context props., which greatly simplify working with ROS2 in ravestate. + | ravestate_emotion | Generates signals for, and recognizes specific emotions (`sig_shy`, `sig_surprise`, `sig_happy`, `sig_affectionate`). + | ravestate_ros1 | Provides specific `Ros1PubProperty`, `Ros1SubProperty` and `Ros1CallProperty` context properties, which greatly simplify working with ROS1 in ravestate. Documentation [here](modules/ravestate_ros1/README.md). + | ravestate_ros2 | Provides specific `Ros2PubProperty`, `Ros2SubProperty` and `Ros2CallProperty` context properties, which greatly simplify working with ROS2 in ravestate. #### IO Modules @@ -223,66 +297,31 @@ External (Red) and Skills (Green): | ravestate_conio | Simple command-line based IO for development purposes. | ravestate_telegramio | Single- or Multi-process Telegram server module, documented [here](modules/ravestate_telegramio/README.md). | ravestate_roboyio | [PyroBoy](https://github.com/roboy/pyroboy) -based STT/TTS with ROS2. + | ravestate_visionio | See dedicated docs [here](modules/ravestate_visionio/README.md). Enables face-recognition based dialog interactions. #### Skill Modules | Module name | Description | |----------------------|-------------| - | ravestate_wildtalk | [ParlAI](https://github.com/roboy/parlai) -based generative conversational module. + | ravestate_wildtalk | See docs [here](modules/ravestate_wildtalk/README.md) - runs generative language models (GPT-2, ConvAi, ParlAi)! | ravestate_hibye | Simply voices __Hi!__ (or the likes thereof) when an interlocutor is added, and __Bye__ when one is removed. | ravestate_persqa | Conducts personalized smalltalk with interlocutors, interacts with Scientio to persist trivia. | ravestate_genqa | [DrQA](https://github.com/roboy/drqa) -based general question answering module. | ravestate_roboyqa | QA module which provides answers to questions about Roboy, such as __Who is your dad?__ - | ravestate_akinator | Enables dialog-based play of [Akinator!](modules/ravestate_akinator/README.md) - | ravestate_sendpics | Uses face recognition to extract facial features and an assiciated Person with `pic_in` and ontology, which are then persisted in Redis and Scientio. - | ravestate_stalker | Uses `facial feature <-> person` tuples generated by sendpics, to surprise people in front of a camera with knowledge of their names. + | ravestate_akinator __(*)__ | Enables dialog-based play of [Akinator!](modules/ravestate_akinator/README.md) + | ravestate_sendpics __(*)__ | Uses face recognition to extract facial features and an assiciated Person with `pic_in` and ontology, which are then persisted in Redis and Scientio. | ravestate_fillers | Recognize when the dialog context is taking a long time to produce an answer, and voice a filler like __"Uhm"__ or __"Let's see..."__. +**Note:** __(*)__ = deprecated. ## Running tests -If you have installed the dependencies from ``requirements-dev.txt`` you -may run the ravestate test suite as follows: - -`` -./run_tests.sh -`` - -## Docker for ROS and ROS2 - -There is a Dockerfile for ROS and ROS2 support which can be built with -```bash -docker build -t ravestate-ros2-image . -``` -The image contains ROS, ROS2 and a ROS Bridge to connect ROS with ROS2. -Furthermore the roboy_communication message and service types are installed. - -A container can then be created with the docker-compose.yml: -```bash -docker-compose up --detach ravestate -``` -The container is now running and a connection into the container can be -established with: -```bash -docker exec -it ravestate-ros2-container bash -``` -Inside the container, first source the ROS2 setups and then -ravestate can be run with ROS2 and rclpy available. -```bash -source ~/ros2_ws/install/setup.sh -python3 -m ravestate [...] -``` +If you have built the ravestate docker image as described above, +you may run the test suite as follows: -### Start ROS Bridge -In order to start ROS Bridge, the image and container have to be set up -as above. After connecting into the container run from inside the container: ```bash -export ROS_IP=192.168.0.105 -source ~/melodic_ws/devel/setup.sh -source ~/ros2_ws/install/setup.sh -source ~/ros1_bridge_ws/install/setup.sh -ros2 run ros1_bridge dynamic_bridge +docker run -t -v $(pwd):/ravestate -w /ravestate ravestate ./run_tests.sh ``` ## Building/maintaining the docs @@ -300,4 +339,4 @@ git add docs/* # For inspection: python3 -m http.server --directory docs ``` -The structure and content of the docs are defined in the file ``pydocmd.yml``. +The structure and content of the docs are defined in the file `pydocmd.yml`. diff --git a/codecov.yml b/codecov.yml index af37d9e..14cf94c 100644 --- a/codecov.yml +++ b/codecov.yml @@ -16,3 +16,15 @@ comment: layout: "reach, diff, flags, files, footer" behavior: default require_changes: no + +#ignore: +# - raveboard # exclude ui +# - ravestate_ui # +# - akinator # exclude akinator +# - ravestate/i* # exlude interfaces +# - ravestate_ros1 # exlude interfaces +# - ravestate_ros2 # exlude interfaces +# - "path/to/folder" # ignore folders and all its contents +# - "test_*.rb" # wildcards accepted +# - "**/*.py" # glob accepted +# - "[a-z]+/test_.*" # regexp accepted \ No newline at end of file diff --git a/config/roboy.yml b/config/roboy.yml index a9a7fe8..1d6ecde 100644 --- a/config/roboy.yml +++ b/config/roboy.yml @@ -18,17 +18,23 @@ module: core config: tickrate: 10 import: - - ravestate_conio + #- ravestate_conio - ravestate_roboyio - ravestate_roboyqa - ravestate_genqa - ravestate_persqa - ravestate_wildtalk - ravestate_hibye - - ravestate_stalker + #- ravestate_stalker - ravestate_fillers #- ravestate_akinator +--- +module: idle +config: + impatience_threshold: 9.0 # number of seconds of "pressure" after which a filler should be sent + bored_threshold: 12.0 # number of seconds of "no activity" after which active engagement should activate + --- module: genqa config: @@ -36,6 +42,37 @@ config: roboy_answer_sanity: 1000 --- -module: akinator +module: roboyqa +config: + roboy_node_id: 356 + +--- +module: roboyio +config: + head_axis0_lower_limit: -0.3 # minimum lean backwards + head_axis0_upper_limit: 0.3 # maximum lean forwards + head_axis1_lower_limit: -0.3 # minimum lean right + head_axis1_upper_limit: 0.3 # maximum lean left + head_axis2_lower_limit: -0.3 # minimum turn right + head_axis2_upper_limit: 0.3 # maximum turn left + head_movement_probability: 0.5 # probability for a head axis to move on input/bored; decided separately for each axis + eye_movement_probability: 0.5 # probability for eyes to look left/right on input/bored + +--- +module: emotion +config: + shy_probability: 0.2 # Probability for being shy when input is about Roboy + surprise_probability: 0.1 # Probability for being surprised when input is question + happy_probability: 0.1 # Probability for being happy when output is generated + affectionate_probability: 0.5 # Probability for being affectionate when keyword is in input and input is about Roboy +--- +module: wildtalk config: - certainty_percentage: 90 + model: "convai_gpt" # one of "convai_gpt", "gpt2", "parlai" + server_address: "http://35.246.158.89" # can be changed if server is running on its own on a separate machine + server_port: 5100 + temperature: 0.7 # convai_gpt, gpt2: higher value -> more variation in output + max_length: 20 # convai_gpt, gpt2: maximal length of generated output + top_k: 0 # convai_gpt, gpt2: <=0: no filtering, >0: keep only top k tokens with highest probability. + top_p: 0.9 # convai_gpt: <=0.0 no filtering, >0.0: keep smallest subset whose total probability mass >= top_p + max_history: 4 # convai_gpt: maximal number of previous dialog turns to be used for output generation diff --git a/config/roboy_telegram_bot_child.yml b/config/roboy_telegram_bot_child.yml index ea63e9d..d0d5095 100644 --- a/config/roboy_telegram_bot_child.yml +++ b/config/roboy_telegram_bot_child.yml @@ -23,7 +23,7 @@ config: - ravestate_roboyqa - ravestate_genqa - ravestate_persqa - - ravestate_sendpics + #- ravestate_sendpics #- ravestate_akinator --- @@ -36,3 +36,30 @@ config: module: akinator config: certainty_percentage: 90 +--- +module: roboyqa +config: + roboy_node_id: 356 +--- +module: idle +config: + impatience_threshold: 6.0 # number of seconds of "pressure" after which a filler should be sent + bored_threshold: 12.0 # number of seconds of "no activity" after which active engagement should activate +--- +module: emotion +config: + shy_probability: 0.2 # Probability for being shy when input is about Roboy + surprise_probability: 0.1 # Probability for being surprised when input is question + happy_probability: 0.1 # Probability for being happy when output is generated + affectionate_probability: 0.5 # Probability for being affectionate when keyword is in input and input is about Roboy +--- +module: wildtalk +config: + model: "convai_gpt" # one of "convai_gpt", "gpt2", "parlai" + server_address: "http://35.246.158.89" # can be changed if server is running on its own on a separate machine + server_port: 5100 + temperature: 0.7 # convai_gpt, gpt2: higher value -> more variation in output + max_length: 20 # convai_gpt, gpt2: maximal length of generated output + top_k: 0 # convai_gpt, gpt2: <=0: no filtering, >0: keep only top k tokens with highest probability. + top_p: 0.9 # convai_gpt: <=0.0 no filtering, >0.0: keep smallest subset whose total probability mass >= top_p + max_history: 4 # convai_gpt: maximal number of previous dialog turns to be used for output generation diff --git a/config/roboy_telegram_bot_master.yml b/config/roboy_telegram_bot_master.yml index ee4cd4b..69e8024 100644 --- a/config/roboy_telegram_bot_master.yml +++ b/config/roboy_telegram_bot_master.yml @@ -10,7 +10,7 @@ --- module: core config: - tickrate: 2 + tickrate: 10 import: - ravestate_telegramio diff --git a/config/visionio-docker.yml b/config/visionio-docker.yml new file mode 100644 index 0000000..eb2deae --- /dev/null +++ b/config/visionio-docker.yml @@ -0,0 +1,37 @@ +# This configuration is designed to be used with ravestate inside +# the ravestate docker container, run with docker-compose +# as described in README.md. + +--- +module: core +config: + tickrate: 10 + import: + - ravestate_conio + - ravestate_visionio + - ravestate_fillers + - ravestate_wildtalk + - ravestate_hibye + - ravestate_genqa + - ravestate_roboyqa + - ravestate_persqa + ros2-node-name: "ros2-node-name" + +--- +module: genqa +config: + drqa_server_address: http://35.246.158.89:5000 + roboy_answer_sanity: 1000 + +--- +module: ontology +config: + neo4j_address: bolt://localhost:7687 + neo4j_username: neo4j + neo4j_pw: test + +--- +module: visionio +config: + redis_host: localhost + redis_pass: "" diff --git a/docker-compose.yml b/docker-compose.yml index 0d8941a..b61106a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,24 +1,82 @@ version: '2.1' services: - ravestate: - image: ravestate-ros2-image - container_name: ravestate-ros2-container + + rs-linux: + image: ravestate + container_name: rs build: context: . dockerfile: Dockerfile network_mode: host volumes: - .:/ravestate + - ./db/neo4j:/var/lib/neo4j/data/databases + - ./db/redis:/redis_db + devices: + - /dev/snd:/dev/snd + - /dev/video0:/dev/video0 + ports: + - "10002:10002" + - "9000:9000" + - "9001:9001" + - "8088:8088" + - "5000:5000" + - "4200:4200" + - "42424:42424" + - "7687:7687" + - "7474:7474" + environment: + - PYTHONPATH=$PYTHONPATH:/ravestate/modules + - PYTHONUNBUFFERED=1 + - NEO4J_ADDRESS=bolt://localhost:7687 + - NEO4J_USERNAME=neo4j + - NEO4J_PASSWORD=test + - REDIS_HOST=localhost + - REDIS_PASSWORD= + # - FACEORACLE_VIDEO_DEVICE=/ravestate/resources/obama.mp4 + - FACEORACLE_VIDEO_DEVICE=0 + # After starting container, attach console and enter python3 -m ravestate [...] + # This enables "hot reload" in the running container because the source directory is mounted + tty: true + stdin_open: true + entrypoint: + - /ravestate/docker-entrypoint.sh + + rs-macos: + image: ravestate + container_name: rs + build: + context: . + dockerfile: Dockerfile + network_mode: bridge + volumes: + - .:/ravestate + - ./db/neo4j:/var/lib/neo4j/data/databases + - ./db/redis:/redis_db ports: - "10002:10002" - "9000:9000" - "9001:9001" + - "8088:8088" + - "5000:5000" + - "4200:4200" + - "42424:42424" + - "7687:7687" + - "7474:7474" environment: - PYTHONPATH=$PYTHONPATH:/ravestate/modules - PYTHONUNBUFFERED=1 + - NEO4J_ADDRESS=bolt://localhost:7687 + - NEO4J_USERNAME=neo4j + - NEO4J_PASSWORD=test + - REDIS_HOST=localhost + - REDIS_PASSWORD= + # - FACEORACLE_VIDEO_DEVICE=/ravestate/resources/obama.mp4 + - FACEORACLE_VIDEO_DEVICE=rtmp://host.docker.internal/live/faceoracle # After starting container, attach console and enter python3 -m ravestate [...] # This enables "hot reload" in the running container because the source directory is mounted - command: bash tty: true stdin_open: true + entrypoint: + - /ravestate/docker-entrypoint.sh diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..2189fea --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +################################################################################# +# +# NOTE: This file is designed to be run inside the ravestate docker container via +# +# `docker-compose start rs-{macos|linux}` +# +################################################################################# + +set -x + +# Make sure ROS is sourced, also in future terminal sessions +. ~/melodic_ws/devel/setup.bash + +# Prepare .bashrc +echo ". ~/melodic_ws/devel/setup.bash" >> /root/.bashrc +echo "echo '============================================================='" >> /root/.bashrc +echo "echo '>>>>>>>> Welcome to the Ravestate Docker Container <<<<<<<<<<'" >> /root/.bashrc +echo "echo ' This container is intended for development purposes only. '" >> /root/.bashrc +echo "echo '============================================================='" >> /root/.bashrc + +# Make sure Neo4j is advertised outside of the container +echo dbms.connectors.default_listen_address=0.0.0.0 >> /etc/neo4j/neo4j.conf + +# Start Neo4j, Roscore, Redis +neo4j start +roscore & +cd /redis_db && redis-server & + +echo "----------------------------------------------" +echo "Sleeping 10 s to wait for neo4j and roscore ..." +echo "----------------------------------------------" +sleep 10 + +# Start face_oracle server and client +cd /root/melodic_ws/src/face_oracle +python3 ws_server.py --redis-host "$REDIS_HOST" --redis-pass "$REDIS_PASSWORD" & +python webcam_video_processor.py -i $FACEORACLE_VIDEO_DEVICE -q ws://localhost:8765 & + +# Start to keep the container open +bash diff --git a/docs/404.html b/docs/404.html index 8ac8fbe..72edc8c 100644 --- a/docs/404.html +++ b/docs/404.html @@ -194,6 +194,18 @@ +
  • + + Raveboard + +
  • + + + + + + +
  • NLP @@ -206,6 +218,30 @@ +
  • + + Wildtalk + +
  • + + + + + + + +
  • + + ROS + +
  • + + + + + + +
  • Verbaliser @@ -230,6 +266,18 @@ +
  • + + VisionIO + +
  • + + + + + + +
  • Akinator @@ -252,10 +300,46 @@ +
  • + + + + + + + +
  • + + + + +
  • - - Visualization + + Raveboard
  • @@ -233,8 +233,49 @@
  • - - For developers + + Via Docker/Docker-compose + + + + +
  • + +
  • + + For development
  • - - Module overview + + Modules
  • - -
  • - - Docker for ROS and ROS2 - - - -
  • @@ -401,6 +422,18 @@ +
  • + + Raveboard + +
  • + + + + + + +
  • NLP @@ -413,6 +446,30 @@ +
  • + + Wildtalk + +
  • + + + + + + + +
  • + + ROS + +
  • + + + + + + +
  • Verbaliser @@ -437,6 +494,18 @@ +
  • + + VisionIO + +
  • + + + + + + +
  • Akinator @@ -459,10 +528,46 @@ +
  • + + + + + + + +
  • + + + + +