<reponame>hyperClink/chinese-trainer-demo
from __future__ import division

import asyncio
import sys
import threading
import string
import random

import pyaudio
import qasync
from google.cloud import speech_v1p1beta1 as speech
from six.moves import queue

import re
import codecs

import os

#get google to auth
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] =  'path here'

# Audio recording parameters
RATE = 16000
CHUNK = int(RATE / 10)  # 100ms

# String that the user is supposed to pronounce
# pronounce_task = "我要去大学学汉语"
# pronounce_task_internal = "我要去大学学汉语"
file = codecs.open("chinese_db.txt", "r", "utf-8")
tasks_table = file.read().splitlines()
file.close()

#probably not the best way to do that? its 2am i went to stackoverflow
from itertools import groupby
tasks_table_by_lesson = list((list(g) for k,g in groupby(tasks_table, key=lambda x: x.isnumeric() != True) if k))

#for debugging purposes also looks cool
for chunk in tasks_table_by_lesson:
    print(chunk)

#tasks_table = [
#    "我要去大学学汉语。",
#    "我知道汉语很好。",
#    "他叫什么名字？",
#    "我要一杯啤#酒。",
#    "我有一支电话。",
#    "我很好！",
#]

final_result_internal = ""
# globaly accessible transcription string
current_text = ""
# globally accessible transcription state
finality = False
# yet another global to see the current lesson. idk what im doing!
current_lesson = 1

pronounce_task = ""
pronounce_task_internal = ""

def GetRandomTask():
    global pronounce_task
    global pronounce_task_internal
    pronounce_task = random.choice(tasks_table_by_lesson[current_lesson-1])
    pronounce_task_internal = re.sub(r'[^\w\s]', '', pronounce_task)
    print(pronounce_task_internal)
    print(pronounce_task)

GetRandomTask()

class MicrophoneStream(object):
    """Opens a recording stream as a generator yielding the audio chunks."""

    def __init__(self, rate, chunk):
        self._rate = rate
        self._chunk = chunk

        # Create a thread-safe buffer of audio data
        self._buff = queue.Queue()
        self.closed = True

    def __enter__(self):
        self._audio_interface = pyaudio.PyAudio()
        self._audio_stream = self._audio_interface.open(
            format=pyaudio.paInt16,
            # The API currently only supports 1-channel (mono) audio
            # https://goo.gl/z757pE
            channels=1,
            rate=self._rate,
            input=True,
            frames_per_buffer=self._chunk,
            # Run the audio stream asynchronously to fill the buffer object.
            # This is necessary so that the input device's buffer doesn't
            # overflow while the calling thread makes network requests, etc.
            stream_callback=self._fill_buffer,
        )

        self.closed = False

        return self

    def __exit__(self, type, value, traceback):
        self._audio_stream.stop_stream()
        self._audio_stream.close()
        self.closed = True
        # Signal the generator to terminate so that the client's
        # streaming_recognize method will not block the process termination.
        self._buff.put(None)
        self._audio_interface.terminate()

    def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
        """Continuously collect data from the audio stream, into the buffer."""
        self._buff.put(in_data)
        return None, pyaudio.paContinue

    def generator(self):
        while not self.closed:
            # Use a blocking get() to ensure there's at least one chunk of
            # data, and stop iteration if the chunk is None, indicating the
            # end of the audio stream.
            chunk = self._buff.get()
            if chunk is None:
                return
            data = [chunk]

            # Now consume whatever other data's still buffered.
            while True:
                try:
                    chunk = self._buff.get(block=False)
                    if chunk is None:
                        return
                    data.append(chunk)
                except queue.Empty:
                    break

            yield b"".join(data)


def listen_print_loop(responses):
    """Iterates through server responses and prints them.

    The responses passed is a generator that will block until a response
    is provided by the server.

    Each response may contain multiple results, and each result may contain
    multiple alternatives; for details, see https://goo.gl/tjCPAU.  Here we
    print only the transcription for the top alternative of the top result.

    In this case, responses are provided for interim results as well. If the
    response is an interim one, print a line feed at the end of it, to allow
    the next result to overwrite it, until the response is a final one. For the
    final one, print a newline to preserve the finalized transcription.
    """
    global current_text
    global finality
    num_chars_printed = 0
    print("initiated listening loop")
    # current_text = "Listening..."
    for response in responses:
        if not response.results:
            continue

        result = response.results[0]
        # The `results` list is consecutive. For streaming, we only care about
        # the first result being considered, since once it's `is_final`, it
        # moves on to considering the next utterance.
        if not result.alternatives:
            continue

        # Display the transcription of the top alternative.
        transcript = result.alternatives[0].transcript

        # Display interim results, but with a carriage return at the end of the
        # line, so subsequent lines will overwrite them.
        #
        # If the previous result was longer than this one, we need to print
        # some extra spaces to overwrite the previous result
        overwrite_chars = " " * (num_chars_printed - len(transcript))

        if not result.is_final:
            current_text = transcript + overwrite_chars
            sys.stdout.write(transcript + overwrite_chars + "\r")
            sys.stdout.flush()

            num_chars_printed = len(transcript)

        else:
            final_result = transcript + overwrite_chars
            finality = True
            num_chars_printed = 0
            alternative = result.alternatives[0]
            for i, result in enumerate(response.results):
                print(alternative.words[0].confidence)
            print(final_result)
            print(pronounce_task_internal)
            final_result_internal = re.sub(r'[^\w\s]','',final_result)
            if final_result_internal == pronounce_task_internal:
                print(final_result)
                print("对")
                current_text = final_result + " - 对!  测量精度:" + str(
                    round(alternative.words[0].confidence * 100, 2)) + "%"
                break
            else:
                print("你的回复: " + final_result + " - 对: " + pronounce_task)
                print("不对")
                current_text = "你的回复: " + final_result + " 对: " + pronounce_task + "- 再试一次!"
                break


def main():
    global current_text
    print("main ran")
    # See http://g.co/cloud/speech/docs/languages
    # for a list of supported languages.
    language_code = "zh"  # a BCP-47 language tag
    print('fwm')
    client = speech.SpeechClient()
    config = speech.RecognitionConfig(
        encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,
        sample_rate_hertz=RATE,
        language_code=language_code,
        enable_word_confidence=True,
        enable_automatic_punctuation=True,
    )

    streaming_config = speech.StreamingRecognitionConfig(
        config=config, interim_results=True
    )

    with MicrophoneStream(RATE, CHUNK) as stream:
        audio_generator = stream.generator()
        print("generated")
        requests = (
            speech.StreamingRecognizeRequest(audio_content=content)
            for content in audio_generator
        )

        print("Waiting for speech...")
        current_text = "Recognizing..."
        responses = client.from_service_account_json("C:\\Users\\nasty\\PycharmProjects\\chinatr\\smiling-pact-337618-0803c1d1e8fa.json").streaming_recognize(streaming_config, requests)
        print("responded")

        # Now, put the transcription responses to use.
        listen_print_loop(responses)


if __name__ == "__main__":
    print("is not module")

from PyQt6.QtGui import QFont
from PyQt6.QtCore import QSize, QTimer
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QListWidget, QComboBox

# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("China Trainer Demo")

        self.button = QPushButton("Start")
        self.button.clicked.connect(self.the_button_was_clicked)

        self.labelTask = QLabel(pronounce_task)
        self.taskFont = QFont()
        self.taskFont.setPixelSize(30)
        self.labelAnswer = QLabel("answer")

        self.labelTask.setFont(self.taskFont)
        self.labelTask.setWordWrap(True)

        self.timer = QTimer()

        self.selectLesson = QComboBox()
        self.selectLesson.currentIndexChanged.connect(self.the_lesson_was_changed)

        self.setFixedSize(QSize(600, 300))

        # Set the central widget of the Window.
        layout = QVBoxLayout()
        layout.addWidget(self.labelTask)
        layout.addWidget(self.labelAnswer)
        layout.addWidget(self.button)
        layout.addWidget(self.selectLesson)
        for i in range(len(tasks_table_by_lesson)):
            self.selectLesson.addItem(str(i+1))

        container = QWidget()
        container.setLayout(layout)

        # Set the central widget of the Window.
        self.setCentralWidget(container)
        # self.the_button_was_clicked()

        self.x = threading.Thread(target=main)

    def the_button_was_clicked(self):
        if self.x.is_alive() is False:
            global current_text
            global finality
            print("button clicked, initiating and running thread...")
            finality = False
            current_text = "Initiating..."
            self.button.setText("Running...")

            self.x = threading.Thread(target=main)
            self.x.start()
            self.timer = QTimer()
            self.timer.timeout.connect(self.update_ans)
            self.timer.start(300)
            # testy()
            # main()

    def the_lesson_was_changed(self):
        global current_lesson
        current_lesson = self.selectLesson.currentIndex() + 1
        print(current_lesson)
        if not self.timer.isActive():
            GetRandomTask()
            self.labelTask.setText(pronounce_task)


    def update_ans(self):
        global pronounce_task
        global pronounce_task_internal
        # print(current_text)
        self.labelAnswer.setText(current_text)

        if finality is True:  # the thread may not be dead at this point
            self.button.setText("Start")
            self.timer.stop()
            GetRandomTask()
            self.labelTask.setText(pronounce_task)


app = QApplication(sys.argv)
loop = qasync.QEventLoop(app)
asyncio.set_event_loop(loop)

with loop:
    w = MainWindow()
    w.show()
    loop.run_forever()

# app.exec()
from __future__ import division

import asyncio
import sys
import threading
import string
import random

import pyaudio
import qasync
from google.cloud import speech_v1p1beta1 as speech
from six.moves import queue

import re
import codecs

import os

#get google to auth
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] =  'path here'

# Audio recording parameters
RATE = 16000
CHUNK = int(RATE / 10)  # 100ms

# String that the user is supposed to pronounce
# pronounce_task = "我要去大学学汉语"
# pronounce_task_internal = "我要去大学学汉语"
file = codecs.open("chinese_db.txt", "r", "utf-8")
tasks_table = file.read().splitlines()
file.close()

#probably not the best way to do that? its 2am i went to stackoverflow
from itertools import groupby
tasks_table_by_lesson = list((list(g) for k,g in groupby(tasks_table, key=lambda x: x.isnumeric() != True) if k))

#for debugging purposes also looks cool
for chunk in tasks_table_by_lesson:
    print(chunk)

#tasks_table = [
#    "我要去大学学汉语。",
#    "我知道汉语很好。",
#    "他叫什么名字？",
#    "我要一杯啤#酒。",
#    "我有一支电话。",
#    "我很好！",
#]

final_result_internal = ""
# globaly accessible transcription string
current_text = ""
# globally accessible transcription state
finality = False
# yet another global to see the current lesson. idk what im doing!
current_lesson = 1

pronounce_task = ""
pronounce_task_internal = ""

def GetRandomTask():
    global pronounce_task
    global pronounce_task_internal
    pronounce_task = random.choice(tasks_table_by_lesson[current_lesson-1])
    pronounce_task_internal = re.sub(r'[^\w\s]', '', pronounce_task)
    print(pronounce_task_internal)
    print(pronounce_task)

GetRandomTask()

class MicrophoneStream(object):
    """Opens a recording stream as a generator yielding the audio chunks."""

    def __init__(self, rate, chunk):
        self._rate = rate
        self._chunk = chunk

        # Create a thread-safe buffer of audio data
        self._buff = queue.Queue()
        self.closed = True

    def __enter__(self):
        self._audio_interface = pyaudio.PyAudio()
        self._audio_stream = self._audio_interface.open(
            format=pyaudio.paInt16,
            # The API currently only supports 1-channel (mono) audio
            # https://goo.gl/z757pE
            channels=1,
            rate=self._rate,
            input=True,
            frames_per_buffer=self._chunk,
            # Run the audio stream asynchronously to fill the buffer object.
            # This is necessary so that the input device's buffer doesn't
            # overflow while the calling thread makes network requests, etc.
            stream_callback=self._fill_buffer,
        )

        self.closed = False

        return self

    def __exit__(self, type, value, traceback):
        self._audio_stream.stop_stream()
        self._audio_stream.close()
        self.closed = True
        # Signal the generator to terminate so that the client's
        # streaming_recognize method will not block the process termination.
        self._buff.put(None)
        self._audio_interface.terminate()

    def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
        """Continuously collect data from the audio stream, into the buffer."""
        self._buff.put(in_data)
        return None, pyaudio.paContinue

    def generator(self):
        while not self.closed:
            # Use a blocking get() to ensure there's at least one chunk of
            # data, and stop iteration if the chunk is None, indicating the
            # end of the audio stream.
            chunk = self._buff.get()
            if chunk is None:
                return
            data = [chunk]

            # Now consume whatever other data's still buffered.
            while True:
                try:
                    chunk = self._buff.get(block=False)
                    if chunk is None:
                        return
                    data.append(chunk)
                except queue.Empty:
                    break

            yield b"".join(data)


def listen_print_loop(responses):
    """Iterates through server responses and prints them.

    The responses passed is a generator that will block until a response
    is provided by the server.

    Each response may contain multiple results, and each result may contain
    multiple alternatives; for details, see https://goo.gl/tjCPAU.  Here we
    print only the transcription for the top alternative of the top result.

    In this case, responses are provided for interim results as well. If the
    response is an interim one, print a line feed at the end of it, to allow
    the next result to overwrite it, until the response is a final one. For the
    final one, print a newline to preserve the finalized transcription.
    """
    global current_text
    global finality
    num_chars_printed = 0
    print("initiated listening loop")
    # current_text = "Listening..."
    for response in responses:
        if not response.results:
            continue

        result = response.results[0]
        # The `results` list is consecutive. For streaming, we only care about
        # the first result being considered, since once it's `is_final`, it
        # moves on to considering the next utterance.
        if not result.alternatives:
            continue

        # Display the transcription of the top alternative.
        transcript = result.alternatives[0].transcript

        # Display interim results, but with a carriage return at the end of the
        # line, so subsequent lines will overwrite them.
        #
        # If the previous result was longer than this one, we need to print
        # some extra spaces to overwrite the previous result
        overwrite_chars = " " * (num_chars_printed - len(transcript))

        if not result.is_final:
            current_text = transcript + overwrite_chars
            sys.stdout.write(transcript + overwrite_chars + "\r")
            sys.stdout.flush()

            num_chars_printed = len(transcript)

        else:
            final_result = transcript + overwrite_chars
            finality = True
            num_chars_printed = 0
            alternative = result.alternatives[0]
            for i, result in enumerate(response.results):
                print(alternative.words[0].confidence)
            print(final_result)
            print(pronounce_task_internal)
            final_result_internal = re.sub(r'[^\w\s]','',final_result)
            if final_result_internal == pronounce_task_internal:
                print(final_result)
                print("对")
                current_text = final_result + " - 对!  测量精度:" + str(
                    round(alternative.words[0].confidence * 100, 2)) + "%"
                break
            else:
                print("你的回复: " + final_result + " - 对: " + pronounce_task)
                print("不对")
                current_text = "你的回复: " + final_result + " 对: " + pronounce_task + "- 再试一次!"
                break


def main():
    global current_text
    print("main ran")
    # See http://g.co/cloud/speech/docs/languages
    # for a list of supported languages.
    language_code = "zh"  # a BCP-47 language tag
    print('fwm')
    client = speech.SpeechClient()
    config = speech.RecognitionConfig(
        encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,
        sample_rate_hertz=RATE,
        language_code=language_code,
        enable_word_confidence=True,
        enable_automatic_punctuation=True,
    )

    streaming_config = speech.StreamingRecognitionConfig(
        config=config, interim_results=True
    )

    with MicrophoneStream(RATE, CHUNK) as stream:
        audio_generator = stream.generator()
        print("generated")
        requests = (
            speech.StreamingRecognizeRequest(audio_content=content)
            for content in audio_generator
        )

        print("Waiting for speech...")
        current_text = "Recognizing..."
        responses = client.from_service_account_json("C:\\Users\\nasty\\PycharmProjects\\chinatr\\smiling-pact-337618-0803c1d1e8fa.json").streaming_recognize(streaming_config, requests)
        print("responded")

        # Now, put the transcription responses to use.
        listen_print_loop(responses)


if __name__ == "__main__":
    print("is not module")

from PyQt6.QtGui import QFont
from PyQt6.QtCore import QSize, QTimer
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QListWidget, QComboBox

# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("China Trainer Demo")

        self.button = QPushButton("Start")
        self.button.clicked.connect(self.the_button_was_clicked)

        self.labelTask = QLabel(pronounce_task)
        self.taskFont = QFont()
        self.taskFont.setPixelSize(30)
        self.labelAnswer = QLabel("answer")

        self.labelTask.setFont(self.taskFont)
        self.labelTask.setWordWrap(True)

        self.timer = QTimer()

        self.selectLesson = QComboBox()
        self.selectLesson.currentIndexChanged.connect(self.the_lesson_was_changed)

        self.setFixedSize(QSize(600, 300))

        # Set the central widget of the Window.
        layout = QVBoxLayout()
        layout.addWidget(self.labelTask)
        layout.addWidget(self.labelAnswer)
        layout.addWidget(self.button)
        layout.addWidget(self.selectLesson)
        for i in range(len(tasks_table_by_lesson)):
            self.selectLesson.addItem(str(i+1))

        container = QWidget()
        container.setLayout(layout)

        # Set the central widget of the Window.
        self.setCentralWidget(container)
        # self.the_button_was_clicked()

        self.x = threading.Thread(target=main)

    def the_button_was_clicked(self):
        if self.x.is_alive() is False:
            global current_text
            global finality
            print("button clicked, initiating and running thread...")
            finality = False
            current_text = "Initiating..."
            self.button.setText("Running...")

            self.x = threading.Thread(target=main)
            self.x.start()
            self.timer = QTimer()
            self.timer.timeout.connect(self.update_ans)
            self.timer.start(300)
            # testy()
            # main()

    def the_lesson_was_changed(self):
        global current_lesson
        current_lesson = self.selectLesson.currentIndex() + 1
        print(current_lesson)
        if not self.timer.isActive():
            GetRandomTask()
            self.labelTask.setText(pronounce_task)


    def update_ans(self):
        global pronounce_task
        global pronounce_task_internal
        # print(current_text)
        self.labelAnswer.setText(current_text)

        if finality is True:  # the thread may not be dead at this point
            self.button.setText("Start")
            self.timer.stop()
            GetRandomTask()
            self.labelTask.setText(pronounce_task)


app = QApplication(sys.argv)
loop = qasync.QEventLoop(app)
asyncio.set_event_loop(loop)

with loop:
    w = MainWindow()
    w.show()
    loop.run_forever()

# app.exec()
#get google to auth # Audio recording parameters # 100ms # String that the user is supposed to pronounce # pronounce_task = "我要去大学学汉语" # pronounce_task_internal = "我要去大学学汉语" #probably not the best way to do that? its 2am i went to stackoverflow #for debugging purposes also looks cool #tasks_table = [ #    "我要去大学学汉语。", #    "我知道汉语很好。", #    "他叫什么名字？", #    "我要一杯啤#酒。", #    "我有一支电话。", #    "我很好！", #] # globaly accessible transcription string # globally accessible transcription state # yet another global to see the current lesson. idk what im doing! Opens a recording stream as a generator yielding the audio chunks. # Create a thread-safe buffer of audio data # The API currently only supports 1-channel (mono) audio # https://goo.gl/z757pE # Run the audio stream asynchronously to fill the buffer object. # This is necessary so that the input device's buffer doesn't # overflow while the calling thread makes network requests, etc. # Signal the generator to terminate so that the client's # streaming_recognize method will not block the process termination. Continuously collect data from the audio stream, into the buffer. # Use a blocking get() to ensure there's at least one chunk of # data, and stop iteration if the chunk is None, indicating the # end of the audio stream. # Now consume whatever other data's still buffered. Iterates through server responses and prints them.      The responses passed is a generator that will block until a response     is provided by the server.      Each response may contain multiple results, and each result may contain     multiple alternatives; for details, see https://goo.gl/tjCPAU.  Here we     print only the transcription for the top alternative of the top result.      In this case, responses are provided for interim results as well. If the     response is an interim one, print a line feed at the end of it, to allow     the next result to overwrite it, until the response is a final one. For the     final one, print a newline to preserve the finalized transcription. # current_text = "Listening..." # The `results` list is consecutive. For streaming, we only care about # the first result being considered, since once it's `is_final`, it # moves on to considering the next utterance. # Display the transcription of the top alternative. # Display interim results, but with a carriage return at the end of the # line, so subsequent lines will overwrite them. # # If the previous result was longer than this one, we need to print # some extra spaces to overwrite the previous result # See http://g.co/cloud/speech/docs/languages # for a list of supported languages. # a BCP-47 language tag # Now, put the transcription responses to use. # Subclass QMainWindow to customize your application's main window # Set the central widget of the Window. # Set the central widget of the Window. # self.the_button_was_clicked() # testy() # main() # print(current_text) # the thread may not be dead at this point # app.exec()