-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Voice entry demo #31010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Voice entry demo #31010
Changes from 52 commits
5d69fce
74d09de
c9cdba2
e6dc6f7
248fe17
b4980a6
7a95204
f619eb7
4677b04
105aedb
7854f96
6bcc4cc
87a2891
5d1c47d
a3c28fc
415d27c
6338af3
fa04d3d
70605c5
0ab436c
95373f9
f2c07dc
606fff2
23e500b
fa3aa0b
c07ce00
acdb3af
43e763d
5174581
f739b11
18dcfed
d0b875a
f0d7c6f
4884cf8
f48cfbe
edfa000
c8aeda3
c90fc4f
11ad162
6f2e24c
523080f
0d36434
60cb674
b7dcf8d
9d5e429
33bde7d
60d7e69
2841aff
0a60f5f
7be0f17
04c571c
fa7c4bc
b651db3
2d2dc83
7dfe752
207123b
b9f64a5
e809f8e
52a3daa
6d2d7f2
9c045db
1d12867
a967a15
abbafb6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| #include "assistant.h" | ||
|
|
||
| AssistantOverlay::AssistantOverlay(QWidget *parent) : QLabel(parent) { | ||
|
|
||
| setStyleSheet("QLabel {" | ||
| " background-color: #373737;" | ||
| " border-radius: 20px;" | ||
| " font-family: 'Inter';" | ||
| " font-size: 60px;" | ||
| " color: white;" // Text color | ||
| "}"); | ||
|
|
||
| // Set up the animations | ||
| showAnimation = new QPropertyAnimation(this, "geometry"); | ||
| showAnimation->setDuration(250); // Duration in milliseconds | ||
|
|
||
| hideAnimation = new QPropertyAnimation(this, "geometry"); | ||
| hideAnimation->setDuration(250); | ||
|
|
||
| int height = 100; // Fixed height | ||
| setGeometry(0, 0, 0, height); | ||
|
|
||
| hideTimer = new QTimer(this); | ||
| connect(hideTimer, &QTimer::timeout, this, &AssistantOverlay::animateHide); | ||
|
|
||
| QObject::connect(uiState(), &UIState::uiUpdate, this, &AssistantOverlay::updateState); | ||
| hide(); | ||
| } | ||
|
|
||
| void AssistantOverlay::animateShow() { | ||
| parentCenterX = parentWidget()->width() / 2; | ||
| finalWidth = parentWidget()->width() * 0.5; | ||
| startX = parentCenterX - finalWidth / 2; | ||
| QRect startRect(parentCenterX, 0, 0, height()); // Centered, zero width | ||
| QRect endRect(startX, 0, finalWidth, height()); // Adjusted x, final width | ||
| showAnimation->setStartValue(startRect); | ||
| showAnimation->setEndValue(endRect); | ||
| show(); | ||
| showAnimation->start(); | ||
| } | ||
|
|
||
| void AssistantOverlay::animateHide() { | ||
| parentCenterX = parentWidget()->width() / 2; | ||
| finalWidth = parentWidget()->width() * 0.5; | ||
| startX = parentCenterX - finalWidth / 2; | ||
| QRect startRect(startX, 0, finalWidth, height()); // Adjusted x, final width | ||
| QRect endRect(parentCenterX, 0, 0, height()); // Centered, zero width | ||
| hideAnimation->setStartValue(startRect); | ||
| hideAnimation->setEndValue(endRect); | ||
| hideAnimation->start(); | ||
| hideTimer->stop(); | ||
| } | ||
|
|
||
| void AssistantOverlay::updateText(QString text) { | ||
| this->setText(text); | ||
| this->setAlignment(QFontMetrics(this->font()).horizontalAdvance(text) > this->finalWidth ? Qt::AlignRight : Qt::AlignCenter); | ||
| } | ||
|
|
||
| void AssistantOverlay::updateState(const UIState &s) { | ||
| const SubMaster &sm = *(s.sm); | ||
| static bool show_allowed = false; | ||
| static bool visable = false; | ||
| if (!sm.updated("speechToText")) { | ||
| return; // Early exit if speechToText is not updated | ||
| } | ||
| // Should probably refactor to a switch statement but its working. | ||
| if (cereal::SpeechToText::State::BEGIN == sm["speechToText"].getSpeechToText().getState()) { | ||
| show_allowed = true; | ||
| this->animateShow(); | ||
| updateText("Hello, I'm listening"); | ||
| if (hideTimer->isActive()) { | ||
| hideTimer->stop(); | ||
| } | ||
| visable = true; // Require begin state or not valid to show | ||
| } else if (!sm["speechToText"].getValid()){ // show if not valid and show set the error text, then lock out and hide until next begin | ||
| if (!visable && show_allowed) {this->animateShow(); visable = true;} | ||
| updateText("Sorry, an error occorred"); | ||
| hideTimer->start(8000); | ||
| show_allowed = false; | ||
| } else if (cereal::SpeechToText::State::EMPTY == sm["speechToText"].getSpeechToText().getState()){ | ||
| updateText("Sorry, I didn't catch that"); | ||
| hideTimer->start(8000); | ||
| visable = false; | ||
| show_allowed = false; | ||
| } else if (show_allowed){ // Interim and Final Results | ||
| updateText(QString::fromStdString(sm["speechToText"].getSpeechToText().getResult())); | ||
| if (sm["speechToText"].getSpeechToText().getFinalResultReady()) { | ||
| hideTimer->start(8000); | ||
| visable = false; | ||
| } | ||
| } else { //shouldn't get here unless I missed something | ||
| qWarning() << "AssistantOverlay in bad state"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #pragma once | ||
|
|
||
| #include "selfdrive/ui/ui.h" | ||
| #include <QLabel> | ||
| #include <QPropertyAnimation> | ||
|
|
||
| class AssistantOverlay : public QLabel { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| explicit AssistantOverlay(QWidget *parent = nullptr); | ||
| void animateShow(); | ||
| void animateHide(); | ||
|
|
||
| private: | ||
| void updateText(const QString text); | ||
| void startHideTimer(); | ||
| QTimer *hideTimer; | ||
| QPropertyAnimation *showAnimation; | ||
| QPropertyAnimation *hideAnimation; | ||
| int parentCenterX; | ||
| int finalWidth; | ||
| int startX; | ||
|
|
||
| private slots: | ||
| void updateState(const UIState &s); | ||
|
|
||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,10 +8,12 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { | |
| main_layout = new QStackedLayout(this); | ||
| main_layout->setMargin(0); | ||
|
|
||
| assistantOverlay = new AssistantOverlay(this); | ||
| homeWindow = new HomeWindow(this); | ||
| main_layout->addWidget(homeWindow); | ||
| QObject::connect(homeWindow, &HomeWindow::openSettings, this, &MainWindow::openSettings); | ||
| QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings); | ||
| QObject::connect(homeWindow, &HomeWindow::requestRaiseAssistantOverlay, this, &MainWindow::raiseAssistantOverlay); | ||
|
|
||
| settingsWindow = new SettingsWindow(this); | ||
| main_layout->addWidget(settingsWindow); | ||
|
|
@@ -33,15 +35,18 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { | |
| main_layout->setCurrentWidget(onboardingWindow); | ||
| } | ||
|
|
||
|
|
||
|
||
| QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { | ||
| if (!offroad) { | ||
| closeSettings(); | ||
| } | ||
| assistantOverlay->raise(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make sure all these raises are required |
||
| }); | ||
| QObject::connect(device(), &Device::interactiveTimeout, [=]() { | ||
| if (main_layout->currentWidget() == settingsWindow) { | ||
| closeSettings(); | ||
| } | ||
| assistantOverlay->raise(); | ||
| }); | ||
|
|
||
| // load fonts | ||
|
|
@@ -68,6 +73,7 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { | |
| void MainWindow::openSettings(int index, const QString ¶m) { | ||
| main_layout->setCurrentWidget(settingsWindow); | ||
| settingsWindow->setCurrentPanel(index, param); | ||
| assistantOverlay->raise(); | ||
| } | ||
|
|
||
| void MainWindow::closeSettings() { | ||
|
|
@@ -80,6 +86,7 @@ void MainWindow::closeSettings() { | |
| homeWindow->showMapPanel(true); | ||
| } | ||
| } | ||
| assistantOverlay->raise(); | ||
| } | ||
|
|
||
| bool MainWindow::eventFilter(QObject *obj, QEvent *event) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,20 +6,23 @@ | |
| #include "selfdrive/ui/qt/home.h" | ||
| #include "selfdrive/ui/qt/offroad/onboarding.h" | ||
| #include "selfdrive/ui/qt/offroad/settings.h" | ||
| #include "selfdrive/ui/qt/widgets/assistant.h" | ||
|
|
||
| class MainWindow : public QWidget { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| explicit MainWindow(QWidget *parent = 0); | ||
|
|
||
|
||
| private: | ||
| bool eventFilter(QObject *obj, QEvent *event) override; | ||
| void openSettings(int index = 0, const QString ¶m = ""); | ||
| void closeSettings(); | ||
| void raiseAssistantOverlay() {assistantOverlay->raise();}; | ||
|
|
||
| QStackedLayout *main_layout; | ||
| HomeWindow *homeWindow; | ||
| SettingsWindow *settingsWindow; | ||
| OnboardingWindow *onboardingWindow; | ||
| AssistantOverlay *assistantOverlay; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| The openwakeword driectory code was copied from https://github.com/dscripka/openWakeWord | ||
| and then stripped down to the essentials for Openpilot's purposes. | ||
|
|
||
| To test wake word detection on the comma device or PC, run wakeword.py and say "alexa". | ||
| Make sure you have onnxruntime==1.16.3 when running on the comma device. | ||
|
|
||
| pip install onnxruntime==1.16.3 | ||
|
|
||
| You can also run rev_speechd.py which will wait for the "WakeWordDetected" param to be set. | ||
| To setup the Rev.Ai api you need to install rev_ai: | ||
|
|
||
| pip install rev_ai | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my PR for rev_ai revdotcom/revai-python-sdk#111 |
||
|
|
||
| You also need to set your rev ai acccess token which can be obtained with a free account. https://www.rev.ai/access-token | ||
| Once you have your token you can paste it in launch_openpilot.sh. | ||
|
|
||
| export REVAI_ACCESS_TOKEN="" | ||
|
|
||
| Once you have everything set up you can run ./launch_openpilot and see the assistant overlay on the UI. You can also run ./ui, rev_speechd.py, wakeword.py, micd.py in their own terminals for testing. | ||
Uh oh!
There was an error while loading. Please reload this page.