mainwindow.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include "audiocapture.h"
  4. #include "asrclient.h"
  5. #include <QMessageBox>
  6. #include <QDateTime>
  7. #include <QJsonDocument>
  8. #include <QJsonObject>
  9. #include <QAudioDevice>
  10. MainWindow::MainWindow(QWidget* parent)
  11. : QMainWindow(parent)
  12. , ui(new Ui::MainWindow)
  13. , m_audioCapture(nullptr)
  14. , m_asrClient(nullptr)
  15. , m_isRecording(false)
  16. , m_isConnected(false)
  17. , m_transcribeTimer(nullptr)
  18. {
  19. ui->setupUi(this);
  20. m_audioCapture = new AudioCapture(this);
  21. m_asrClient = new AsrClient(this);
  22. m_transcribeTimer = new QTimer(this);
  23. connect(ui->btnConnect, &QPushButton::clicked, this, &MainWindow::onConnectClicked);
  24. connect(ui->btnStartStop, &QPushButton::clicked, this, &MainWindow::onStartStopClicked);
  25. connect(ui->btnClear, &QPushButton::clicked, this, &MainWindow::onClearClicked);
  26. connect(ui->actionExit, &QAction::triggered, this, &QMainWindow::close);
  27. connect(ui->actionAbout, &QAction::triggered, this, [this]() {
  28. QMessageBox::about(this, "About",
  29. "Whisper ASR Client v1.0\n\n"
  30. "Real-time speech recognition using faster-whisper.\n\n"
  31. "Start the ASR server first:\n"
  32. " python -m whisper_asr.server --model small");
  33. });
  34. connect(m_asrClient, &AsrClient::connected, this, &MainWindow::onConnected);
  35. connect(m_asrClient, &AsrClient::disconnected, this, &MainWindow::onDisconnected);
  36. connect(m_asrClient, &AsrClient::connectionError, this, &MainWindow::onConnectionError);
  37. connect(m_asrClient, &AsrClient::transcriptReceived, this, &MainWindow::onTranscriptReceived);
  38. connect(m_audioCapture, &AudioCapture::audioDataReady, this, &MainWindow::onAudioDataReady);
  39. connect(m_audioCapture, &AudioCapture::audioLevelChanged, this, &MainWindow::onAudioLevelChanged);
  40. connect(m_audioCapture, &AudioCapture::errorOccurred, this, [this](const QString& error) {
  41. QMessageBox::warning(this, "Audio Error", error);
  42. });
  43. connect(m_transcribeTimer, &QTimer::timeout, this, [this]() {
  44. if (m_isRecording && m_asrClient->isConnected()) {
  45. m_asrClient->requestTranscribe();
  46. }
  47. });
  48. updateUiState();
  49. // Auto-connect on startup
  50. QTimer::singleShot(500, this, [this]() {
  51. onConnectClicked();
  52. });
  53. // Auto-start recording after connect
  54. QTimer::singleShot(1500, this, [this]() {
  55. if (m_isConnected) {
  56. onStartStopClicked();
  57. }
  58. });
  59. }
  60. MainWindow::~MainWindow()
  61. {
  62. if (m_isRecording) {
  63. m_audioCapture->stop();
  64. }
  65. if (m_isConnected) {
  66. m_asrClient->disconnectFromServer();
  67. }
  68. }
  69. void MainWindow::onConnectClicked()
  70. {
  71. if (m_isConnected) {
  72. m_asrClient->disconnectFromServer();
  73. return;
  74. }
  75. QString host = ui->lineEditHost->text();
  76. quint16 port = ui->lineEditPort->text().toUShort();
  77. ui->labelStatus->setText("Connecting...");
  78. ui->btnConnect->setEnabled(false);
  79. m_asrClient->connectToServer(host, port);
  80. }
  81. void MainWindow::onStartStopClicked()
  82. {
  83. if (m_isRecording) {
  84. m_audioCapture->stop();
  85. m_transcribeTimer->stop();
  86. m_isRecording = false;
  87. ui->btnStartStop->setText("Start Recording");
  88. if (m_isConnected) {
  89. m_asrClient->requestTranscribe();
  90. }
  91. } else {
  92. if (m_audioCapture->start()) {
  93. m_isRecording = true;
  94. ui->btnStartStop->setText("Stop Recording");
  95. m_transcribeTimer->start(2000);
  96. }
  97. }
  98. updateUiState();
  99. }
  100. void MainWindow::onClearClicked()
  101. {
  102. ui->textEditTranscript->clear();
  103. if (m_isConnected) {
  104. m_asrClient->clearBuffer();
  105. }
  106. }
  107. void MainWindow::onConnected()
  108. {
  109. m_isConnected = true;
  110. ui->labelStatus->setText("Connected");
  111. ui->btnConnect->setText("Disconnect");
  112. ui->btnConnect->setEnabled(true);
  113. updateUiState();
  114. }
  115. void MainWindow::onDisconnected()
  116. {
  117. m_isConnected = false;
  118. ui->labelStatus->setText("Disconnected");
  119. ui->btnConnect->setText("Connect");
  120. ui->btnConnect->setEnabled(true);
  121. if (m_isRecording) {
  122. m_audioCapture->stop();
  123. m_transcribeTimer->stop();
  124. m_isRecording = false;
  125. ui->btnStartStop->setText("Start Recording");
  126. }
  127. updateUiState();
  128. }
  129. void MainWindow::onConnectionError(const QString& error)
  130. {
  131. m_isConnected = false;
  132. ui->labelStatus->setText("Connection Error");
  133. ui->btnConnect->setText("Connect");
  134. ui->btnConnect->setEnabled(true);
  135. QMessageBox::warning(this, "Connection Error", error);
  136. updateUiState();
  137. }
  138. void MainWindow::onTranscriptReceived(const QString& text, const QString& language)
  139. {
  140. if (!text.isEmpty()) {
  141. appendTranscript(text);
  142. }
  143. }
  144. void MainWindow::onAudioLevelChanged(qreal level)
  145. {
  146. int percent = static_cast<int>(level * 100);
  147. ui->labelAudioLevel->setText(QString("Audio Level: %1%").arg(percent));
  148. }
  149. void MainWindow::onAudioDataReady(const QByteArray& data)
  150. {
  151. qDebug() << "onAudioDataReady: data size =" << data.size();
  152. if (m_isConnected) {
  153. qDebug() << "Sending audio to server...";
  154. m_asrClient->sendAudio(data);
  155. }
  156. }
  157. void MainWindow::updateUiState()
  158. {
  159. ui->lineEditHost->setEnabled(!m_isConnected);
  160. ui->lineEditPort->setEnabled(!m_isConnected);
  161. ui->btnStartStop->setEnabled(m_isConnected);
  162. }
  163. void MainWindow::appendTranscript(const QString& text)
  164. {
  165. QString timestamp = QDateTime::currentDateTime().toString("HH:mm:ss");
  166. ui->textEditTranscript->append(QString("[%1] %2").arg(timestamp).arg(text));
  167. QTextCursor cursor = ui->textEditTranscript->textCursor();
  168. cursor.movePosition(QTextCursor::End);
  169. ui->textEditTranscript->setTextCursor(cursor);
  170. }