|
@@ -0,0 +1,337 @@
|
|
|
|
+import sys
|
|
|
|
+from PyQt5.QtWidgets import (
|
|
|
|
+ QApplication, QWidget, QTabWidget, QVBoxLayout,
|
|
|
|
+ QPushButton, QTextEdit, QHBoxLayout, QFileDialog,
|
|
|
|
+ QTextBrowser, QGroupBox, QButtonGroup, QSlider,
|
|
|
|
+ QComboBox,
|
|
|
|
+)
|
|
|
|
+from PyQt5 import QtCore, QtWidgets
|
|
|
|
+from PyQt5.QtGui import QFont, QTextCursor
|
|
|
|
+from PyQt5.QtMultimedia import QMediaPlaylist
|
|
|
|
+
|
|
|
|
+from record import Record
|
|
|
|
+from component.player import Player
|
|
|
|
+from summary.infer import summary, summary_with_model
|
|
|
|
+
|
|
|
|
+from time import time, sleep
|
|
|
|
+import soundfile as sf
|
|
|
|
+
|
|
|
|
+class Tab1Widget(QWidget):
|
|
|
|
+ def __init__(self, add_signal):
|
|
|
|
+ super().__init__()
|
|
|
|
+ self.text = ''
|
|
|
|
+ self.add_signal = add_signal
|
|
|
|
+
|
|
|
|
+ ## for player
|
|
|
|
+ self.player = Player(self)
|
|
|
|
+ self.playlist = ['/Users/user/Documents/HDC/RnD/Project/qt/resource/1. KsponSpeech_sample.wav']
|
|
|
|
+ self.selectedList = [0]
|
|
|
|
+ self.playOption = QMediaPlaylist.Sequential
|
|
|
|
+
|
|
|
|
+ wav, sr = sf.read(self.playlist[0])
|
|
|
|
+ self.playlist_data = [[wav, sr]]
|
|
|
|
+
|
|
|
|
+ self.sound_prev = 0
|
|
|
|
+
|
|
|
|
+ self.initUI()
|
|
|
|
+
|
|
|
|
+ self.record_thread = RecordWorker(self.add_signal)
|
|
|
|
+ self.record_file_thread = FileRecordWorker(self.add_signal, self.playlist_data)
|
|
|
|
+
|
|
|
|
+ self.btn_run.clicked.connect(self.clicked_run_btn)
|
|
|
|
+ self.btn_stop.clicked.connect(self.clicked_stop_btn)
|
|
|
|
+ self.btn_clear.clicked.connect(self.clicked_clear_btn)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def initUI(self):
|
|
|
|
+ self.btn_run = QPushButton('Run', self)
|
|
|
|
+ self.btn_stop = QPushButton('Stop', self)
|
|
|
|
+ self.btn_clear = QPushButton('Clear', self)
|
|
|
|
+
|
|
|
|
+ self.tb = QTextEdit()
|
|
|
|
+ self.tb.setReadOnly(True)
|
|
|
|
+ self.tb.setAcceptRichText(True)
|
|
|
|
+ font = QFont()
|
|
|
|
+ font.setPointSize(80)
|
|
|
|
+ self.tb.setFont(font)
|
|
|
|
+ self.tb.setText(self.text)
|
|
|
|
+
|
|
|
|
+ # Play Control
|
|
|
|
+ self.gb = QGroupBox('Play Control')
|
|
|
|
+
|
|
|
|
+ grp = QButtonGroup(self)
|
|
|
|
+ play_button_layout = QHBoxLayout()
|
|
|
|
+ play_button_text = ['Change', '▶','■'] # ['◀◀', '▶', '⏸', '▶▶', '■']
|
|
|
|
+ for i in range(len(play_button_text)):
|
|
|
|
+ btn = QPushButton(play_button_text[i], self)
|
|
|
|
+ grp.addButton(btn, i)
|
|
|
|
+ play_button_layout.addWidget(btn)
|
|
|
|
+ grp.buttonClicked[int].connect(self.clicked_play_btn)
|
|
|
|
+
|
|
|
|
+ # Volume
|
|
|
|
+ self.slider = QSlider(QtCore.Qt.Horizontal, self)
|
|
|
|
+ self.slider.setRange(0,100)
|
|
|
|
+ self.slider.setValue(50)
|
|
|
|
+ self.slider.valueChanged[int].connect(self.volumeChanged)
|
|
|
|
+ play_button_layout.addWidget(self.slider)
|
|
|
|
+ self.gb.setLayout(play_button_layout)
|
|
|
|
+
|
|
|
|
+ self.vbox = QVBoxLayout()
|
|
|
|
+ self.vbox.addWidget(self.gb)
|
|
|
|
+ self.vbox.addWidget(self.btn_run)
|
|
|
|
+ self.vbox.addWidget(self.btn_stop)
|
|
|
|
+ self.vbox.addWidget(self.btn_clear)
|
|
|
|
+ self.vbox.addWidget(self.tb)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ self.setLayout(self.vbox)
|
|
|
|
+
|
|
|
|
+ def clicked_run_btn(self):
|
|
|
|
+ self.record_thread.start()
|
|
|
|
+ # self.text += '\nrun!!\n'
|
|
|
|
+ # self.tb.setText(self.text)
|
|
|
|
+
|
|
|
|
+ # self.addText.emit(self.text)
|
|
|
|
+
|
|
|
|
+ def clicked_play_btn(self, id):
|
|
|
|
+ if id==0: #change
|
|
|
|
+ self.changeList()
|
|
|
|
+ elif id==1: #▶
|
|
|
|
+ self.player.play(self.playlist, self.selectedList[0], self.playOption)
|
|
|
|
+ self.record_file_thread.start()
|
|
|
|
+ elif id==2: #■
|
|
|
|
+ self.player.stop()
|
|
|
|
+ self.record_file_thread.stop()
|
|
|
|
+
|
|
|
|
+ def clicked_stop_btn(self):
|
|
|
|
+ self.record_thread.stop()
|
|
|
|
+
|
|
|
|
+ def clicked_clear_btn(self):
|
|
|
|
+ # self.record_thread = RecordWorker(self.add_signal)
|
|
|
|
+ self.record_thread.clear()
|
|
|
|
+ self.add_signal.emit('<cls>')
|
|
|
|
+
|
|
|
|
+ def volumeChanged(self):
|
|
|
|
+ self.player.upateVolume(self.slider.value())
|
|
|
|
+
|
|
|
|
+ def clear_text_browser(self):
|
|
|
|
+ self.text = ''
|
|
|
|
+ # self.tb.setText(self.text)
|
|
|
|
+ self.add_signal.emit('<cls>')
|
|
|
|
+
|
|
|
|
+ def changeList(self):
|
|
|
|
+ fname = QFileDialog.getOpenFileName(self, 'Select one file to open', './resource')
|
|
|
|
+ if fname[0]:
|
|
|
|
+ self.clear_text_browser()
|
|
|
|
+ wav, sr = sf.read(fname[0])
|
|
|
|
+ self.playlist = [fname[0]]
|
|
|
|
+ self.playlist_data = [[wav, sr]]
|
|
|
|
+ self.record_file_thread = FileRecordWorker(self.add_signal, self.playlist_data)
|
|
|
|
+
|
|
|
|
+ def updateMediaChanged(self, index):
|
|
|
|
+ print('index:',index)
|
|
|
|
+ pass
|
|
|
|
+ # if index>=0:
|
|
|
|
+ # self.table.selectRow(index)
|
|
|
|
+
|
|
|
|
+ def updateDurationChanged(self, index, msec):
|
|
|
|
+ print('index:',index, 'duration:', msec)
|
|
|
|
+ # self.pbar = self.table.cellWidget(index, 1)
|
|
|
|
+ # if self.pbar:
|
|
|
|
+ # self.pbar.setRange(0, msec)
|
|
|
|
+
|
|
|
|
+ def updatePositionChanged(self, index, msec):
|
|
|
|
+ print('index:',index, 'position:', msec)
|
|
|
|
+
|
|
|
|
+ # self.pbar = self.table.cellWidget(index, 1)
|
|
|
|
+ # if self.pbar:
|
|
|
|
+ # self.pbar.setValue(msec)
|
|
|
|
+
|
|
|
|
+class Tab2Widget(QWidget):
|
|
|
|
+ def __init__(self):
|
|
|
|
+ super().__init__()
|
|
|
|
+
|
|
|
|
+ self.summary_model_idx = 0
|
|
|
|
+
|
|
|
|
+ self.initUI()
|
|
|
|
+ self.btn_convert.clicked.connect(self.clicked_convert_btn)
|
|
|
|
+ self.btn_open_file.clicked.connect(self.clicked_open_file_btn)
|
|
|
|
+ self.btn_clear.clicked.connect(self.clicked_clear_btn)
|
|
|
|
+
|
|
|
|
+ def initUI(self):
|
|
|
|
+
|
|
|
|
+ self.grid = QHBoxLayout()
|
|
|
|
+ self.btn_open_file = QPushButton('Open File')
|
|
|
|
+ self.btn_clear = QPushButton('Clear')
|
|
|
|
+ self.grid.addWidget(self.btn_open_file)
|
|
|
|
+ self.grid.addWidget(self.btn_clear)
|
|
|
|
+
|
|
|
|
+ self.combo = QComboBox(self)
|
|
|
|
+ self.combo.addItems(["General", "Estate"])
|
|
|
|
+ self.combo.currentTextChanged.connect(self.on_combobox_func)
|
|
|
|
+ self.grid.addWidget(self.combo)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ self.tb_source = QTextEdit()
|
|
|
|
+ self.tb_source.setAcceptRichText(True)
|
|
|
|
+
|
|
|
|
+ self.btn_convert = QPushButton('Convert', self)
|
|
|
|
+
|
|
|
|
+ self.tb_convert = QTextBrowser()
|
|
|
|
+ # self.tb_convert.setReadOnly(True)
|
|
|
|
+ self.tb_convert.setAcceptRichText(True)
|
|
|
|
+ font = QFont()
|
|
|
|
+ font.setPointSize(80)
|
|
|
|
+ self.tb_convert.setFont(font)
|
|
|
|
+ # self.tb_convert.setSource(QtCore.QUrl.fromLocalFile("test2.html"))
|
|
|
|
+
|
|
|
|
+ self.vbox = QVBoxLayout()
|
|
|
|
+ self.vbox.addLayout(self.grid, 0)
|
|
|
|
+ self.vbox.addWidget(self.tb_source, 1)
|
|
|
|
+ self.vbox.addWidget(self.btn_convert, 2)
|
|
|
|
+ self.vbox.addWidget(self.tb_convert, 3)
|
|
|
|
+
|
|
|
|
+ self.setLayout(self.vbox)
|
|
|
|
+
|
|
|
|
+ def on_combobox_func(self, text):
|
|
|
|
+ if text == 'General':
|
|
|
|
+ self.summary_model_idx = 0
|
|
|
|
+ else:
|
|
|
|
+ self.summary_model_idx = 1
|
|
|
|
+
|
|
|
|
+ @QtCore.pyqtSlot(str)
|
|
|
|
+ def update_source_text(self, content):
|
|
|
|
+ self.tb_source.setText(content)
|
|
|
|
+
|
|
|
|
+ def clicked_convert_btn(self):
|
|
|
|
+ text = self.tb_source.toPlainText()
|
|
|
|
+ # text = summary(text)
|
|
|
|
+ text = summary_with_model(text, self.summary_model_idx)
|
|
|
|
+ self.tb_convert.setText(text)
|
|
|
|
+
|
|
|
|
+ def clicked_open_file_btn(self):
|
|
|
|
+ fname = QFileDialog.getOpenFileName(self, 'Open file', './script')
|
|
|
|
+ if fname[0]:
|
|
|
|
+ f = open(fname[0], 'r')
|
|
|
|
+
|
|
|
|
+ with f:
|
|
|
|
+ data = f.read()
|
|
|
|
+ self.tb_source.setText(data)
|
|
|
|
+
|
|
|
|
+ def clicked_clear_btn(self):
|
|
|
|
+ self.tb_source.setText("")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class MyApp(QtWidgets.QMainWindow):
|
|
|
|
+ addText = QtCore.pyqtSignal(str)
|
|
|
|
+
|
|
|
|
+ def __init__(self, parent=None):
|
|
|
|
+ super(MyApp, self).__init__(parent)
|
|
|
|
+ self.text = ''
|
|
|
|
+ self.blank_cnt = 0
|
|
|
|
+ self.blank_max = 2
|
|
|
|
+
|
|
|
|
+ self.initUI()
|
|
|
|
+
|
|
|
|
+ def initUI(self):
|
|
|
|
+ self.tab1 = Tab1Widget(self.addText)
|
|
|
|
+ self.tab2 = Tab2Widget()
|
|
|
|
+
|
|
|
|
+ # tab1.addText.connect(tab2.update_source_text)
|
|
|
|
+ # tab1.addText.connect(tab2.update_source_text)
|
|
|
|
+ # self.addText.connect(tab2.update_source_text)
|
|
|
|
+ self.addText.connect(self.update_text)
|
|
|
|
+
|
|
|
|
+ tabs = QTabWidget()
|
|
|
|
+ tabs.addTab(self.tab1, '음성 인식')
|
|
|
|
+ tabs.addTab(self.tab2, '요약')
|
|
|
|
+
|
|
|
|
+ self.setCentralWidget(tabs)
|
|
|
|
+
|
|
|
|
+ # vbox = QVBoxLayout()
|
|
|
|
+ # vbox.addWidget(tabs)
|
|
|
|
+
|
|
|
|
+ # self.setLayout(vbox)
|
|
|
|
+
|
|
|
|
+ self.setWindowTitle('BTS')
|
|
|
|
+ self.setGeometry(300, 300, 900, 500)
|
|
|
|
+ self.show()
|
|
|
|
+
|
|
|
|
+ @QtCore.pyqtSlot(str)
|
|
|
|
+ def update_text(self, content):
|
|
|
|
+ if content == '<cls>':
|
|
|
|
+ self.text = ''
|
|
|
|
+ elif len(content) == 0 and len(self.text) and self.text[-1] != "\n":
|
|
|
|
+ self.blank_cnt += 1
|
|
|
|
+ if self.blank_cnt >= self.blank_max:
|
|
|
|
+ self.blank_cnt = 0
|
|
|
|
+ self.text += '\n'
|
|
|
|
+ else:
|
|
|
|
+ self.text += content
|
|
|
|
+
|
|
|
|
+ self.tab1.tb.setText(self.text)
|
|
|
|
+ self.tab1.tb.moveCursor(QTextCursor.End)
|
|
|
|
+
|
|
|
|
+ self.tab2.tb_source.setText(self.text)
|
|
|
|
+ self.tab2.tb_source.moveCursor(QTextCursor.End)
|
|
|
|
+
|
|
|
|
+def list_chunk(lst, n):
|
|
|
|
+ return [lst[i:i+n] for i in range(0, len(lst), n)]
|
|
|
|
+
|
|
|
|
+class RecordWorker(QtCore.QThread):
|
|
|
|
+
|
|
|
|
+ def __init__(self, add_signal):
|
|
|
|
+ super().__init__()
|
|
|
|
+ self.power = False
|
|
|
|
+ self.record = Record()
|
|
|
|
+ self.add_signal = add_signal
|
|
|
|
+
|
|
|
|
+ def run(self):
|
|
|
|
+ self.power = True
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ while self.power == True:
|
|
|
|
+ self.record.record_unit(self.add_signal.emit)
|
|
|
|
+
|
|
|
|
+ # self.record.record_unit(self.add_signal.emit)
|
|
|
|
+
|
|
|
|
+ def stop(self):
|
|
|
|
+ self.power = False
|
|
|
|
+
|
|
|
|
+ def clear(self):
|
|
|
|
+ self.record.clear()
|
|
|
|
+
|
|
|
|
+class FileRecordWorker(QtCore.QThread):
|
|
|
|
+ def __init__(self, add_signal, audio_data):
|
|
|
|
+ super().__init__()
|
|
|
|
+ self.power = False
|
|
|
|
+ self.record = Record()
|
|
|
|
+ self.add_signal = add_signal
|
|
|
|
+ self.audio_data = audio_data
|
|
|
|
+
|
|
|
|
+ def run(self):
|
|
|
|
+ self.power = True
|
|
|
|
+ sec = 1
|
|
|
|
+
|
|
|
|
+ audio, sr = self.audio_data[0]
|
|
|
|
+ sample_list = list_chunk(audio, 16000 * sec)
|
|
|
|
+
|
|
|
|
+ start_time = time()
|
|
|
|
+ for idx, sample in enumerate(sample_list):
|
|
|
|
+ if self.power:
|
|
|
|
+ now = time()
|
|
|
|
+ length = len(sample)/sr
|
|
|
|
+
|
|
|
|
+ print('time = ', start_time + length + (idx+1), 'now = ', now, 'diff = ', (start_time + length + (idx+1)) - now)
|
|
|
|
+ pivot = (start_time + length + (idx+1)) - now
|
|
|
|
+ if pivot > 0:
|
|
|
|
+ sleep(pivot)
|
|
|
|
+ self.record.record_file(sample, self.add_signal.emit)
|
|
|
|
+
|
|
|
|
+ def stop(self):
|
|
|
|
+ self.power = False
|
|
|
|
+
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
+ app = QApplication(sys.argv)
|
|
|
|
+ ex = MyApp()
|
|
|
|
+ sys.exit(app.exec_())
|