Refactored routing and socket logic. Implementing eeg train/test
This commit is contained in:
@@ -10,3 +10,5 @@ server = Flask(__name__)
|
|||||||
server.config["SEND_FILE_MAX_AGE_DEFAULT"] = 1 # disable caching
|
server.config["SEND_FILE_MAX_AGE_DEFAULT"] = 1 # disable caching
|
||||||
socketio = SocketIO(async_mode='threading')
|
socketio = SocketIO(async_mode='threading')
|
||||||
socketio.init_app(server)
|
socketio.init_app(server)
|
||||||
|
|
||||||
|
participants = {}
|
||||||
|
|||||||
@@ -180,6 +180,8 @@ class MatTestThread(Thread):
|
|||||||
copy2(self.backupFilepath, backup_path)
|
copy2(self.backupFilepath, backup_path)
|
||||||
else:
|
else:
|
||||||
copy2(self.backupFilepath, './finalised_backup.pkl')
|
copy2(self.backupFilepath, './finalised_backup.pkl')
|
||||||
|
with open('./Matrix_test_results.pkl', 'wb') as f:
|
||||||
|
dill.dump(saveDict, f)
|
||||||
self.finalised = True
|
self.finalised = True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+44
-1
@@ -1,6 +1,45 @@
|
|||||||
from pathops import dir_must_exist
|
from pathops import dir_must_exist
|
||||||
import os
|
import os
|
||||||
import dill
|
import dill
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from config import server, socketio, participants
|
||||||
|
|
||||||
|
def find_participants(folder='./participant_data/'):
|
||||||
|
'''
|
||||||
|
Returns a tuple of (participant number, participant filepath) for every
|
||||||
|
participant folder found in directory provided
|
||||||
|
'''
|
||||||
|
part_folder = [os.path.join(folder, o) for o in os.listdir(folder)
|
||||||
|
if os.path.isdir(os.path.join(folder,o))]
|
||||||
|
for path in part_folder:
|
||||||
|
part_key = os.path.basename(path)
|
||||||
|
participants[part_key] = Participant(participant_dir=path)
|
||||||
|
participants[part_key].load('info')
|
||||||
|
return participants
|
||||||
|
|
||||||
|
def gen_participant_num(participants, N = 100):
|
||||||
|
# generate array of numbers that haven't been taken between 0-100
|
||||||
|
# if list is empty increment until list isnt empty
|
||||||
|
# Choose a number
|
||||||
|
taken_nums = []
|
||||||
|
for part_key in participants.keys():
|
||||||
|
participant = participants[part_key]
|
||||||
|
taken_nums.append(participant['info']['number'])
|
||||||
|
n = 0
|
||||||
|
num_found = False
|
||||||
|
while not num_found:
|
||||||
|
potential_nums = np.arange(N)+n+1
|
||||||
|
try:
|
||||||
|
valid_nums = np.setdiff1d(potential_nums, taken_nums)
|
||||||
|
except:
|
||||||
|
set_trace()
|
||||||
|
if valid_nums.size:
|
||||||
|
num_found = True
|
||||||
|
else:
|
||||||
|
n += N
|
||||||
|
return np.random.choice(valid_nums)
|
||||||
|
|
||||||
|
|
||||||
class Participant:
|
class Participant:
|
||||||
def __init__(self, participant_dir=None, number=None, age=None, gender=None, handedness=None, general_notes=None):
|
def __init__(self, participant_dir=None, number=None, age=None, gender=None, handedness=None, general_notes=None):
|
||||||
@@ -24,7 +63,11 @@ class Participant:
|
|||||||
"notes": ''
|
"notes": ''
|
||||||
},
|
},
|
||||||
|
|
||||||
"set_matrix_data": {
|
"eeg_train_data": {
|
||||||
|
"notes": ''
|
||||||
|
},
|
||||||
|
|
||||||
|
"eeg_test": {
|
||||||
"notes": ''
|
"notes": ''
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import os
|
||||||
|
from flask import Flask, url_for, render_template, jsonify, request, make_response, g
|
||||||
|
from flask_socketio import emit
|
||||||
|
import pdb
|
||||||
|
import csv
|
||||||
|
import io
|
||||||
|
import re
|
||||||
|
import base64
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import webview
|
||||||
|
import webbrowser
|
||||||
|
import app
|
||||||
|
import time
|
||||||
|
from threading import Thread, Event
|
||||||
|
import numpy as np
|
||||||
|
import random
|
||||||
|
from pysndfile import sndio
|
||||||
|
from scipy.optimize import minimize
|
||||||
|
|
||||||
|
from app import generate_matrix_stimulus
|
||||||
|
from matrix_test.filesystem import globDir, organiseWavs, prepareOutDir
|
||||||
|
from matrix_test_thread import MatTestThread
|
||||||
|
from pathops import dir_must_exist
|
||||||
|
from participant import Participant, find_participants, gen_participant_num
|
||||||
|
|
||||||
|
from config import server, socketio, participants
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
General routing
|
||||||
|
'''
|
||||||
|
@server.route("/")
|
||||||
|
def landing():
|
||||||
|
"""
|
||||||
|
Render index.html
|
||||||
|
"""
|
||||||
|
return render_template("index.html")
|
||||||
|
|
||||||
|
@server.route('/participant_home')
|
||||||
|
def participant_homepage():
|
||||||
|
title = "Welcome"
|
||||||
|
paragraph = [
|
||||||
|
"Please wait while the experimenter sets up the test..."
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
return render_template("participant_home.html", title = title, paragraph=paragraph)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
|
||||||
|
@server.route('/home')
|
||||||
|
def homepage():
|
||||||
|
title = "Welcome"
|
||||||
|
paragraph = [
|
||||||
|
"This is the clinician view. Use the dropdown menus to access controls "
|
||||||
|
"and feedback for the various tests available.",
|
||||||
|
"This web app was developed for the generation of stimulus and "
|
||||||
|
"running of experiments for the PhD project \"Predicting speech "
|
||||||
|
"in noise performance using evoked responses\"."
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
return render_template("home.html", title = title, paragraph=paragraph)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
|
||||||
|
@server.route("/choose/path")
|
||||||
|
def choose_path():
|
||||||
|
"""
|
||||||
|
Invokes a folder selection dialog
|
||||||
|
"""
|
||||||
|
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
|
||||||
|
if dirs and len(dirs) > 0:
|
||||||
|
directory = dirs[0]
|
||||||
|
if isinstance(directory, bytes):
|
||||||
|
directory = directory.decode("utf-8")
|
||||||
|
|
||||||
|
response = {"status": "ok", "directory": directory}
|
||||||
|
else:
|
||||||
|
response = {"status": "cancel"}
|
||||||
|
|
||||||
|
return jsonify(response)
|
||||||
|
|
||||||
|
|
||||||
|
@server.route("/fullscreen")
|
||||||
|
def fullscreen():
|
||||||
|
webview.toggle_fullscreen()
|
||||||
|
return jsonify({})
|
||||||
|
|
||||||
|
'''
|
||||||
|
Participant routing
|
||||||
|
'''
|
||||||
|
@server.route('/participant/manage')
|
||||||
|
def manage_participant_page():
|
||||||
|
# Find all pre-existing participants
|
||||||
|
participants = find_participants()
|
||||||
|
return render_template("manage_participants.html", part_keys=participants.keys())
|
||||||
|
|
||||||
|
@server.route('/participant/create')
|
||||||
|
def create_participant_page():
|
||||||
|
# Find all pre-existing participants
|
||||||
|
participants = find_participants()
|
||||||
|
part_num = gen_participant_num(participants)
|
||||||
|
return render_template("create_participant.html", num=part_num)
|
||||||
|
|
||||||
|
@server.route('/participant/create/submit', methods=["POST"])
|
||||||
|
def create_participant_submit():
|
||||||
|
data = request.form
|
||||||
|
key = "participant_{}".format(data['number'])
|
||||||
|
participants[key] = Participant(participant_dir="./participant_data/{}".format(key), **data)
|
||||||
|
participants[key].save("info")
|
||||||
|
return render_template("manage_participants.html", part_keys = participants.keys())
|
||||||
|
|
||||||
|
'''
|
||||||
|
EEG routing
|
||||||
|
'''
|
||||||
|
@server.route('/eeg')
|
||||||
|
def eeg_setup():
|
||||||
|
participants = find_participants()
|
||||||
|
return render_template("eeg_setup.html", part_keys=participants.keys())
|
||||||
|
|
||||||
|
'''
|
||||||
|
Matrix behavioral test routing
|
||||||
|
'''
|
||||||
|
@server.route('/matrix_test')
|
||||||
|
def matrix_test_setup():
|
||||||
|
participants = find_participants()
|
||||||
|
return render_template("matrix_test_setup.html", part_keys=participants.keys())
|
||||||
|
|
||||||
|
@server.route('/matrix_test/run')
|
||||||
|
def run_matrix_test():
|
||||||
|
return render_template("mat_test_run.html")
|
||||||
|
|
||||||
|
@server.route('/matrix_test/complete')
|
||||||
|
def mat_end():
|
||||||
|
return render_template("mat_test_end.html")
|
||||||
|
|
||||||
|
@server.route('/matrix_test/clinician/control')
|
||||||
|
def clinician_control_mat():
|
||||||
|
return render_template("mat_test_clinician_view.html")
|
||||||
|
|
||||||
|
@server.route('/matrix_test/clinician/complete')
|
||||||
|
def clinician_mat_end():
|
||||||
|
return render_template("mat_test_clinician_end.html")
|
||||||
|
|
||||||
|
@server.route('/matrix_test/stimulus_generation')
|
||||||
|
def matDecStim():
|
||||||
|
return render_template("matrix_decode_stim.html")
|
||||||
|
|
||||||
|
'''
|
||||||
|
Click stimulus routing
|
||||||
|
'''
|
||||||
|
@server.route('/click_stim')
|
||||||
|
def clickStim():
|
||||||
|
return render_template("click_stim.html")
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
/da/ stimulus routing
|
||||||
|
'''
|
||||||
|
@server.route('/da_stim')
|
||||||
|
def daStim():
|
||||||
|
return render_template("da_stim.html")
|
||||||
|
|
||||||
|
|
||||||
@@ -32,13 +32,8 @@ from matrix_test_thread import MatTestThread
|
|||||||
from pathops import dir_must_exist
|
from pathops import dir_must_exist
|
||||||
from participant import Participant
|
from participant import Participant
|
||||||
|
|
||||||
import config
|
from config import server, socketio, participants
|
||||||
|
from route import *
|
||||||
server = config.server
|
|
||||||
socketio = config.socketio
|
|
||||||
|
|
||||||
participants = {}
|
|
||||||
|
|
||||||
|
|
||||||
class StimGenThread(Thread):
|
class StimGenThread(Thread):
|
||||||
'''
|
'''
|
||||||
@@ -78,6 +73,26 @@ def run_matrix_thread(listN=None, sessionFilepath=None, participant=None):
|
|||||||
participant=participant)
|
participant=participant)
|
||||||
matThread.start()
|
matThread.start()
|
||||||
|
|
||||||
|
def run_eeg_train(sessionFilepath=None, participant=None):
|
||||||
|
global eegTrainThread
|
||||||
|
if 'matThread' in globals():
|
||||||
|
if matThread.isAlive() and isinstance(matThread, MatTestThread):
|
||||||
|
matThread.join()
|
||||||
|
matThread = MatTestThread(socketio=socketio, listN=listN,
|
||||||
|
sessionFilepath=sessionFilepath,
|
||||||
|
participant=participant)
|
||||||
|
matThread.start()
|
||||||
|
|
||||||
|
def run_eeg_test(sessionFilepath=None, participant=None):
|
||||||
|
global eegTestThread
|
||||||
|
if 'eegTestThread' in globals():
|
||||||
|
if eegTestThread.isAlive() and isinstance(eegTestThread, EEGTestThread):
|
||||||
|
eegTestThread.join()
|
||||||
|
eegTestThread = EEGTestThread(socketio=socketio, listN=listN,
|
||||||
|
sessionFilepath=sessionFilepath,
|
||||||
|
participant=participant)
|
||||||
|
eegTestThread.start()
|
||||||
|
|
||||||
|
|
||||||
@server.after_request
|
@server.after_request
|
||||||
def add_header(response):
|
def add_header(response):
|
||||||
@@ -86,315 +101,6 @@ def add_header(response):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@server.route("/")
|
|
||||||
def landing():
|
|
||||||
"""
|
|
||||||
Render index.html
|
|
||||||
"""
|
|
||||||
return render_template("index.html")
|
|
||||||
|
|
||||||
|
|
||||||
@server.route("/choose/path")
|
|
||||||
def choose_path():
|
|
||||||
"""
|
|
||||||
Invokes a folder selection dialog
|
|
||||||
"""
|
|
||||||
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
|
|
||||||
if dirs and len(dirs) > 0:
|
|
||||||
directory = dirs[0]
|
|
||||||
if isinstance(directory, bytes):
|
|
||||||
directory = directory.decode("utf-8")
|
|
||||||
|
|
||||||
response = {"status": "ok", "directory": directory}
|
|
||||||
else:
|
|
||||||
response = {"status": "cancel"}
|
|
||||||
|
|
||||||
return jsonify(response)
|
|
||||||
|
|
||||||
|
|
||||||
@server.route("/fullscreen")
|
|
||||||
def fullscreen():
|
|
||||||
webview.toggle_fullscreen()
|
|
||||||
return jsonify({})
|
|
||||||
|
|
||||||
@server.route('/participant/manage')
|
|
||||||
def manage_participant_page():
|
|
||||||
# Find all pre-existing participants
|
|
||||||
participants = find_participants()
|
|
||||||
return render_template("manage_participants.html", part_keys=participants.keys())
|
|
||||||
|
|
||||||
@socketio.on('delete_participant', namespace='/main')
|
|
||||||
def manage_participant_delete(participant_str):
|
|
||||||
shutil.rmtree(participants[participant_str].participant_dir)
|
|
||||||
del participants[participant_str]
|
|
||||||
return render_template("manage_participants.html", part_keys=participants.keys())
|
|
||||||
|
|
||||||
@socketio.on('update_participant_info', namespace='/main')
|
|
||||||
def manage_participant_save(data):
|
|
||||||
key = "participant_{}".format(data['number'])
|
|
||||||
participants[key].set_info(data)
|
|
||||||
participants[key].save("info")
|
|
||||||
|
|
||||||
@socketio.on('get_part_info', namespace='/main')
|
|
||||||
def get_participant_info(key):
|
|
||||||
socketio.emit('part_info', participants[key]['info'], namespace='/main')
|
|
||||||
|
|
||||||
@server.route('/participant/create')
|
|
||||||
def create_participant_page():
|
|
||||||
# Find all pre-existing participants
|
|
||||||
participants = find_participants()
|
|
||||||
part_num = gen_participant_num(participants)
|
|
||||||
return render_template("create_participant.html", num=part_num)
|
|
||||||
|
|
||||||
def find_participants(folder='./participant_data/'):
|
|
||||||
'''
|
|
||||||
Returns a tuple of (participant number, participant filepath) for every
|
|
||||||
participant folder found in directory provided
|
|
||||||
'''
|
|
||||||
part_folder = [os.path.join(folder, o) for o in os.listdir(folder)
|
|
||||||
if os.path.isdir(os.path.join(folder,o))]
|
|
||||||
for path in part_folder:
|
|
||||||
part_key = os.path.basename(path)
|
|
||||||
participants[part_key] = Participant(participant_dir=path)
|
|
||||||
participants[part_key].load('info')
|
|
||||||
return participants
|
|
||||||
|
|
||||||
def gen_participant_num(participants, N = 100):
|
|
||||||
# generate array of numbers that haven't been taken between 0-100
|
|
||||||
# if list is empty increment until list isnt empty
|
|
||||||
# Choose a number
|
|
||||||
taken_nums = []
|
|
||||||
for part_key in participants.keys():
|
|
||||||
participant = participants[part_key]
|
|
||||||
taken_nums.append(participant['info']['number'])
|
|
||||||
n = 0
|
|
||||||
num_found = False
|
|
||||||
while not num_found:
|
|
||||||
potential_nums = np.arange(N)+n+1
|
|
||||||
try:
|
|
||||||
valid_nums = np.setdiff1d(potential_nums, taken_nums)
|
|
||||||
except:
|
|
||||||
set_trace()
|
|
||||||
if valid_nums.size:
|
|
||||||
num_found = True
|
|
||||||
else:
|
|
||||||
n += N
|
|
||||||
return np.random.choice(valid_nums)
|
|
||||||
|
|
||||||
@server.route('/participant/create/submit', methods=["POST"])
|
|
||||||
def create_participant_submit():
|
|
||||||
data = request.form
|
|
||||||
key = "participant_{}".format(data['number'])
|
|
||||||
participants[key] = Participant(participant_dir="./participant_data/{}".format(key), **data)
|
|
||||||
participants[key].save("info")
|
|
||||||
return render_template("manage_participants.html", part_keys = participants.keys())
|
|
||||||
|
|
||||||
@server.route('/participant_home')
|
|
||||||
def participant_homepage():
|
|
||||||
title = "Welcome"
|
|
||||||
paragraph = [
|
|
||||||
"Please wait while the experimenter sets up the test..."
|
|
||||||
]
|
|
||||||
|
|
||||||
try:
|
|
||||||
return render_template("participant_home.html", title = title, paragraph=paragraph)
|
|
||||||
except Exception as e:
|
|
||||||
return str(e)
|
|
||||||
|
|
||||||
|
|
||||||
@server.route('/home')
|
|
||||||
def homepage():
|
|
||||||
title = "Welcome"
|
|
||||||
paragraph = [
|
|
||||||
"This is the clinician view. Use the dropdown menus to access controls "
|
|
||||||
"and feedback for the various tests available.",
|
|
||||||
"This web app was developed for the generation of stimulus and "
|
|
||||||
"running of experiments for the PhD project \"Predicting speech "
|
|
||||||
"in noise performance using evoked responses\"."
|
|
||||||
]
|
|
||||||
|
|
||||||
try:
|
|
||||||
return render_template("home.html", title = title, paragraph=paragraph)
|
|
||||||
except Exception as e:
|
|
||||||
return str(e)
|
|
||||||
|
|
||||||
|
|
||||||
@server.route('/matrix_test')
|
|
||||||
def matrix_test_setup():
|
|
||||||
participants = find_participants()
|
|
||||||
return render_template("matrix_test_setup.html", part_keys=participants.keys())
|
|
||||||
|
|
||||||
@server.route('/matrix_test/run')
|
|
||||||
def run_matrix_test():
|
|
||||||
return render_template("mat_test_run.html")
|
|
||||||
|
|
||||||
@server.route('/matrix_test/complete')
|
|
||||||
def mat_end():
|
|
||||||
return render_template("mat_test_end.html")
|
|
||||||
|
|
||||||
@server.route('/matrix_test/clinician/control')
|
|
||||||
def clinician_control_mat():
|
|
||||||
return render_template("mat_test_clinician_view.html")
|
|
||||||
|
|
||||||
@server.route('/matrix_test/clinician/complete')
|
|
||||||
def clinician_mat_end():
|
|
||||||
return render_template("mat_test_clinician_end.html")
|
|
||||||
|
|
||||||
@server.route('/matrix_test/stimulus_generation')
|
|
||||||
def matDecStim():
|
|
||||||
return render_template("matrix_decode_stim.html")
|
|
||||||
|
|
||||||
@socketio.on('start_mat_test', namespace='/main')
|
|
||||||
def start_mat_test(msg):
|
|
||||||
'''
|
|
||||||
Relay test start message to participant view
|
|
||||||
'''
|
|
||||||
socketio.emit('participant_start_mat', {'data': ''}, namespace='/main', broadcast=True)
|
|
||||||
listN = int(msg['listN'])
|
|
||||||
part_key = msg['part_key']
|
|
||||||
|
|
||||||
if part_key != "--":
|
|
||||||
participant = participants[part_key]
|
|
||||||
else:
|
|
||||||
participant = None
|
|
||||||
|
|
||||||
run_matrix_thread(listN=listN, participant=participant)
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('load_mat_backup', namespace='/main')
|
|
||||||
def start_backup_mat_test(msg):
|
|
||||||
'''
|
|
||||||
Relay test start message to participant view
|
|
||||||
'''
|
|
||||||
socketio.emit('participant_start_mat', {'data': ''}, namespace='/main', broadcast=True)
|
|
||||||
part_key = msg['part_key']
|
|
||||||
if part_key != "--":
|
|
||||||
participant = participants[part_key]
|
|
||||||
folder = participant.data_paths["adaptive_matrix_data"]
|
|
||||||
backupPath = os.path.join(folder, "mat_state.pkl")
|
|
||||||
else:
|
|
||||||
participant = None
|
|
||||||
backupPath = './mat_state.pkl'
|
|
||||||
|
|
||||||
run_matrix_thread(sessionFilepath=backupPath, participant=participant)
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('load_mat_session', namespace='/main')
|
|
||||||
def start_saved_mat_test(msg):
|
|
||||||
'''
|
|
||||||
Relay test start message to participant view
|
|
||||||
'''
|
|
||||||
filepath = webview.create_file_dialog(dialog_type=webview.OPEN_DIALOG, file_types=("Python Pickle (*.pkl)",))
|
|
||||||
if filepath and len(filepath) > 0:
|
|
||||||
filepath = filepath[0]
|
|
||||||
if isinstance(filepath, bytes):
|
|
||||||
filepath = filepath.decode("utf-8")
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
part_key = msg['part_key']
|
|
||||||
if part_key != "--":
|
|
||||||
participant = participants[part_key]
|
|
||||||
else:
|
|
||||||
participant = None
|
|
||||||
socketio.emit('participant_start_mat', {'data': ''}, namespace='/main', broadcast=True)
|
|
||||||
run_matrix_thread(sessionFilepath=filepath, participant=participant)
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('run_mat_stim_gen', namespace='/main')
|
|
||||||
def generateStim(msg):
|
|
||||||
'''
|
|
||||||
When process buton is clicked in GUI, start an asynchronous thread to run
|
|
||||||
process
|
|
||||||
'''
|
|
||||||
global thread
|
|
||||||
n_part = int(msg['n_part'])
|
|
||||||
snr_len = float(msg['snr_len'])
|
|
||||||
snr_num = int(msg['snr_num'])
|
|
||||||
mat_dir = msg['mat_dir']
|
|
||||||
save_dir = msg['save_dir']
|
|
||||||
thread = StimGenThread(n_part, snr_len, snr_num, mat_dir, save_dir, socketio=socketio)
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('check-mat-processing-status', namespace='/main')
|
|
||||||
def checkMatProcessingStatus():
|
|
||||||
global thread
|
|
||||||
if thread.is_alive():
|
|
||||||
socketio.emit('mat-processing-status', {'data': True}, namespace='/main')
|
|
||||||
else:
|
|
||||||
socketio.emit('mat-processing-status', {'data': False}, namespace='/main')
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('open_save_file_dialog', namespace='/main')
|
|
||||||
def openSaveFileDialog():
|
|
||||||
# Open a file dialog interface for selecting a directory
|
|
||||||
filepath = webview.create_file_dialog(dialog_type=webview.SAVE_DIALOG,
|
|
||||||
file_types=("Python Pickle (*.pkl)",),
|
|
||||||
save_filename="test_session.pkl")
|
|
||||||
if filepath and len(filepath) > 0:
|
|
||||||
filepath = filepath[0]
|
|
||||||
if isinstance(filepath, bytes):
|
|
||||||
filepath = filepath.decode("utf-8")
|
|
||||||
# Make sure file ends with pickle file extension
|
|
||||||
head, tail = os.path.splitext(filepath)
|
|
||||||
filepath = head + ".pkl"
|
|
||||||
# Send message with selected directory to the GUI
|
|
||||||
socketio.emit('save_file_dialog_resp', {'data': filepath}, namespace='/main', broadcast=True, include_self=True)
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('open_load_file_dialog', namespace='/main')
|
|
||||||
def openLoadFileDialog():
|
|
||||||
# Open a file dialog interface for selecting a directory
|
|
||||||
filepath = webview.create_file_dialog(dialog_type=webview.OPEN_DIALOG, file_types=("Python Pickle (*.pkl)",))
|
|
||||||
if filepath and len(filepath) > 0:
|
|
||||||
filepath = filepath[0]
|
|
||||||
if isinstance(filepath, bytes):
|
|
||||||
filepath = filepath.decode("utf-8")
|
|
||||||
if not os.path.isfile(filepath):
|
|
||||||
socketio.emit('main-notification', {'data': "\'{}\' is not a valid file".format(directory)}, namespace='/main')
|
|
||||||
# Send message with selected directory to the GUI
|
|
||||||
socketio.emit('load_file_dialog_resp', {'data': filepath}, namespace='/main', broadcast=True, include_self=True)
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('open_save_dialog', namespace='/main')
|
|
||||||
def openSaveDirDialog():
|
|
||||||
# Open a file dialog interface for selecting a directory
|
|
||||||
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
|
|
||||||
if dirs and len(dirs) > 0:
|
|
||||||
directory = dirs[0]
|
|
||||||
if isinstance(directory, bytes):
|
|
||||||
directory = directory.decode("utf-8")
|
|
||||||
if not os.path.isdir(directory):
|
|
||||||
socketio.emit('main-notification', {'data': "\'{}\' is not a valid directory".format(directory)}, namespace='/main')
|
|
||||||
return None
|
|
||||||
# Send message with selected directory to the GUI
|
|
||||||
socketio.emit('save-file-dialog-resp', {'data': directory}, namespace='/main')
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('open_mat_dialog', namespace='/main')
|
|
||||||
def openMatDialog():
|
|
||||||
# Open a file dialog interface for selecting a directory
|
|
||||||
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
|
|
||||||
if dirs and len(dirs) > 0:
|
|
||||||
directory = dirs[0]
|
|
||||||
if isinstance(directory, bytes):
|
|
||||||
directory = directory.decode("utf-8")
|
|
||||||
# TODO: Add filepath checking here...
|
|
||||||
# Send message with selected directory to the GUI
|
|
||||||
socketio.emit('mat-dialog-resp', {'data': directory}, namespace='/main')
|
|
||||||
|
|
||||||
|
|
||||||
@server.route('/click_stim')
|
|
||||||
def clickStim():
|
|
||||||
return render_template("click_stim.html")
|
|
||||||
|
|
||||||
|
|
||||||
@server.route('/da_stim')
|
|
||||||
def daStim():
|
|
||||||
return render_template("da_stim.html")
|
|
||||||
|
|
||||||
|
|
||||||
def set_trace():
|
def set_trace():
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger('werkzeug')
|
log = logging.getLogger('werkzeug')
|
||||||
|
|||||||
@@ -0,0 +1,314 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
from flask import Flask, url_for, render_template, jsonify, request, make_response, g
|
||||||
|
from flask_socketio import emit
|
||||||
|
import pdb
|
||||||
|
import csv
|
||||||
|
import io
|
||||||
|
import re
|
||||||
|
import base64
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import webview
|
||||||
|
import webbrowser
|
||||||
|
import app
|
||||||
|
import time
|
||||||
|
from threading import Thread, Event
|
||||||
|
import numpy as np
|
||||||
|
import random
|
||||||
|
from pysndfile import sndio
|
||||||
|
from scipy.optimize import minimize
|
||||||
|
|
||||||
|
from app import generate_matrix_stimulus
|
||||||
|
from matrix_test.filesystem import globDir, organiseWavs, prepareOutDir
|
||||||
|
from matrix_test_thread import MatTestThread
|
||||||
|
from pathops import dir_must_exist
|
||||||
|
from participant import Participant
|
||||||
|
|
||||||
|
from config import server, socketio, participants
|
||||||
|
|
||||||
|
'''
|
||||||
|
Generic socket handlers
|
||||||
|
'''
|
||||||
|
@socketio.on('open_save_file_dialog', namespace='/main')
|
||||||
|
def openSaveFileDialog():
|
||||||
|
# Open a file dialog interface for selecting a directory
|
||||||
|
filepath = webview.create_file_dialog(dialog_type=webview.SAVE_DIALOG,
|
||||||
|
file_types=("Python Pickle (*.pkl)",),
|
||||||
|
save_filename="test_session.pkl")
|
||||||
|
if filepath and len(filepath) > 0:
|
||||||
|
filepath = filepath[0]
|
||||||
|
if isinstance(filepath, bytes):
|
||||||
|
filepath = filepath.decode("utf-8")
|
||||||
|
# Make sure file ends with pickle file extension
|
||||||
|
head, tail = os.path.splitext(filepath)
|
||||||
|
filepath = head + ".pkl"
|
||||||
|
# Send message with selected directory to the GUI
|
||||||
|
socketio.emit('save_file_dialog_resp', {'data': filepath}, namespace='/main', broadcast=True, include_self=True)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('open_load_file_dialog', namespace='/main')
|
||||||
|
def openLoadFileDialog():
|
||||||
|
# Open a file dialog interface for selecting a directory
|
||||||
|
filepath = webview.create_file_dialog(dialog_type=webview.OPEN_DIALOG, file_types=("Python Pickle (*.pkl)",))
|
||||||
|
if filepath and len(filepath) > 0:
|
||||||
|
filepath = filepath[0]
|
||||||
|
if isinstance(filepath, bytes):
|
||||||
|
filepath = filepath.decode("utf-8")
|
||||||
|
if not os.path.isfile(filepath):
|
||||||
|
socketio.emit('main-notification', {'data': "\'{}\' is not a valid file".format(directory)}, namespace='/main')
|
||||||
|
# Send message with selected directory to the GUI
|
||||||
|
socketio.emit('load_file_dialog_resp', {'data': filepath}, namespace='/main', broadcast=True, include_self=True)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('open_save_dialog', namespace='/main')
|
||||||
|
def openSaveDirDialog():
|
||||||
|
# Open a file dialog interface for selecting a directory
|
||||||
|
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
|
||||||
|
if dirs and len(dirs) > 0:
|
||||||
|
directory = dirs[0]
|
||||||
|
if isinstance(directory, bytes):
|
||||||
|
directory = directory.decode("utf-8")
|
||||||
|
if not os.path.isdir(directory):
|
||||||
|
socketio.emit('main-notification', {'data': "\'{}\' is not a valid directory".format(directory)}, namespace='/main')
|
||||||
|
return None
|
||||||
|
# Send message with selected directory to the GUI
|
||||||
|
socketio.emit('save-file-dialog-resp', {'data': directory}, namespace='/main')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
Participant socket handlers
|
||||||
|
'''
|
||||||
|
@socketio.on('delete_participant', namespace='/main')
|
||||||
|
def manage_participant_delete(participant_str):
|
||||||
|
shutil.rmtree(participants[participant_str].participant_dir)
|
||||||
|
del participants[participant_str]
|
||||||
|
return render_template("manage_participants.html", part_keys=participants.keys())
|
||||||
|
|
||||||
|
@socketio.on('update_participant_info', namespace='/main')
|
||||||
|
def manage_participant_save(data):
|
||||||
|
key = "participant_{}".format(data['number'])
|
||||||
|
participants[key].set_info(data)
|
||||||
|
participants[key].save("info")
|
||||||
|
|
||||||
|
@socketio.on('get_part_info', namespace='/main')
|
||||||
|
def get_participant_info(key):
|
||||||
|
socketio.emit('part_info', participants[key]['info'], namespace='/main')
|
||||||
|
|
||||||
|
'''
|
||||||
|
EEG training socket handlers
|
||||||
|
'''
|
||||||
|
@socketio.on('start_eeg_train', namespace='/main')
|
||||||
|
def start_eeg_train(msg):
|
||||||
|
'''
|
||||||
|
Relay train start message to participant view
|
||||||
|
'''
|
||||||
|
socketio.emit('participant_start_eeg', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
part_key = msg['part_key']
|
||||||
|
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
|
||||||
|
run_eeg_train_thread(listN=listN, participant=participant)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('load_eeg_train_backup', namespace='/main')
|
||||||
|
def start_backup_eeg_train(msg):
|
||||||
|
'''
|
||||||
|
Relay train start message to participant view
|
||||||
|
'''
|
||||||
|
socketio.emit('participant_start_eeg_train', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
part_key = msg['part_key']
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
folder = participant.data_paths["eeg_train_data"]
|
||||||
|
backupPath = os.path.join(folder, "eeg_train_state.pkl")
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
backupPath = './eeg_train_state.pkl'
|
||||||
|
|
||||||
|
run_eeg_train_thread(sessionFilepath=backupPath, participant=participant)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('load_eeg_train_session', namespace='/main')
|
||||||
|
def start_saved_eeg_train(msg):
|
||||||
|
'''
|
||||||
|
Relay train start message to participant view
|
||||||
|
'''
|
||||||
|
filepath = webview.create_file_dialog(dialog_type=webview.OPEN_DIALOG, file_types=("Python Pickle (*.pkl)",))
|
||||||
|
if filepath and len(filepath) > 0:
|
||||||
|
filepath = filepath[0]
|
||||||
|
if isinstance(filepath, bytes):
|
||||||
|
filepath = filepath.decode("utf-8")
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
part_key = msg['part_key']
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
socketio.emit('participant_start_eeg_train', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
run_eeg_train_thread(sessionFilepath=filepath, participant=participant)
|
||||||
|
|
||||||
|
'''
|
||||||
|
EEG test socket handlers
|
||||||
|
'''
|
||||||
|
@socketio.on('start_eeg_test', namespace='/main')
|
||||||
|
def start_eeg_test(msg):
|
||||||
|
'''
|
||||||
|
Relay test start message to participant view
|
||||||
|
'''
|
||||||
|
socketio.emit('participant_start_eeg', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
part_key = msg['part_key']
|
||||||
|
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
|
||||||
|
run_eeg_test_thread(listN=listN, participant=participant)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('load_eeg_test_backup', namespace='/main')
|
||||||
|
def start_backup_eeg_test(msg):
|
||||||
|
'''
|
||||||
|
Relay test start message to participant view
|
||||||
|
'''
|
||||||
|
socketio.emit('participant_start_eeg_test', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
part_key = msg['part_key']
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
folder = participant.data_paths["eeg_test_data"]
|
||||||
|
backupPath = os.path.join(folder, "eeg_test_state.pkl")
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
backupPath = './eeg_test_state.pkl'
|
||||||
|
|
||||||
|
run_eeg_test_thread(sessionFilepath=backupPath, participant=participant)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('load_eeg_test_session', namespace='/main')
|
||||||
|
def start_saved_eeg_test(msg):
|
||||||
|
'''
|
||||||
|
Relay test start message to participant view
|
||||||
|
'''
|
||||||
|
filepath = webview.create_file_dialog(dialog_type=webview.OPEN_DIALOG, file_types=("Python Pickle (*.pkl)",))
|
||||||
|
if filepath and len(filepath) > 0:
|
||||||
|
filepath = filepath[0]
|
||||||
|
if isinstance(filepath, bytes):
|
||||||
|
filepath = filepath.decode("utf-8")
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
part_key = msg['part_key']
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
socketio.emit('participant_start_eeg_test', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
run_eeg_test_thread(sessionFilepath=filepath, participant=participant)
|
||||||
|
|
||||||
|
'''
|
||||||
|
Behavioral matrix test socket handlers
|
||||||
|
'''
|
||||||
|
@socketio.on('start_mat_test', namespace='/main')
|
||||||
|
def start_mat_test(msg):
|
||||||
|
'''
|
||||||
|
Relay test start message to participant view
|
||||||
|
'''
|
||||||
|
socketio.emit('participant_start_mat', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
listN = int(msg['listN'])
|
||||||
|
part_key = msg['part_key']
|
||||||
|
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
|
||||||
|
run_matrix_thread(listN=listN, participant=participant)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('load_mat_backup', namespace='/main')
|
||||||
|
def start_backup_mat_test(msg):
|
||||||
|
'''
|
||||||
|
Relay test start message to participant view
|
||||||
|
'''
|
||||||
|
socketio.emit('participant_start_mat', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
part_key = msg['part_key']
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
folder = participant.data_paths["adaptive_matrix_data"]
|
||||||
|
backupPath = os.path.join(folder, "mat_state.pkl")
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
backupPath = './mat_state.pkl'
|
||||||
|
|
||||||
|
run_matrix_thread(sessionFilepath=backupPath, participant=participant)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('load_mat_session', namespace='/main')
|
||||||
|
def start_saved_mat_test(msg):
|
||||||
|
'''
|
||||||
|
Relay test start message to participant view
|
||||||
|
'''
|
||||||
|
filepath = webview.create_file_dialog(dialog_type=webview.OPEN_DIALOG, file_types=("Python Pickle (*.pkl)",))
|
||||||
|
if filepath and len(filepath) > 0:
|
||||||
|
filepath = filepath[0]
|
||||||
|
if isinstance(filepath, bytes):
|
||||||
|
filepath = filepath.decode("utf-8")
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
part_key = msg['part_key']
|
||||||
|
if part_key != "--":
|
||||||
|
participant = participants[part_key]
|
||||||
|
else:
|
||||||
|
participant = None
|
||||||
|
socketio.emit('participant_start_mat', {'data': ''}, namespace='/main', broadcast=True)
|
||||||
|
run_matrix_thread(sessionFilepath=filepath, participant=participant)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('open_mat_dialog', namespace='/main')
|
||||||
|
def openMatDialog():
|
||||||
|
# Open a file dialog interface for selecting a directory
|
||||||
|
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
|
||||||
|
if dirs and len(dirs) > 0:
|
||||||
|
directory = dirs[0]
|
||||||
|
if isinstance(directory, bytes):
|
||||||
|
directory = directory.decode("utf-8")
|
||||||
|
# TODO: Add filepath checking here...
|
||||||
|
# Send message with selected directory to the GUI
|
||||||
|
socketio.emit('mat-dialog-resp', {'data': directory}, namespace='/main')
|
||||||
|
|
||||||
|
'''
|
||||||
|
Matrix test stimulus generation socket handlers
|
||||||
|
'''
|
||||||
|
@socketio.on('run_mat_stim_gen', namespace='/main')
|
||||||
|
def generateStim(msg):
|
||||||
|
'''
|
||||||
|
When process buton is clicked in GUI, start an asynchronous thread to run
|
||||||
|
process
|
||||||
|
'''
|
||||||
|
global thread
|
||||||
|
n_part = int(msg['n_part'])
|
||||||
|
snr_len = float(msg['snr_len'])
|
||||||
|
snr_num = int(msg['snr_num'])
|
||||||
|
mat_dir = msg['mat_dir']
|
||||||
|
save_dir = msg['save_dir']
|
||||||
|
thread = StimGenThread(n_part, snr_len, snr_num, mat_dir, save_dir, socketio=socketio)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('check-mat-processing-status', namespace='/main')
|
||||||
|
def checkMatProcessingStatus():
|
||||||
|
global thread
|
||||||
|
if thread.is_alive():
|
||||||
|
socketio.emit('mat-processing-status', {'data': True}, namespace='/main')
|
||||||
|
else:
|
||||||
|
socketio.emit('mat-processing-status', {'data': False}, namespace='/main')
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{% extends 'index.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="card">
|
||||||
|
<div id="main-div" class="card-body">
|
||||||
|
<form action="{{ url_for('matDecStim') }}" method="POST">
|
||||||
|
<div class="form-group">
|
||||||
|
<select class="form-control" name="participant" id="participant">
|
||||||
|
<option>--</option>
|
||||||
|
{% for p in part_keys %}
|
||||||
|
<option>{{ p }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="open-mat-folder-container">Behavioral test data:</label>
|
||||||
|
<br>
|
||||||
|
<input type="text" id="behav_res" name='behav_res' value="./Matrix_test_results.pkl" style="width:85%"></input>
|
||||||
|
<button type="button" id="behav_res_button" class="btn btn-primary">Browse...</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group d-flex justify-content-center">
|
||||||
|
<button type="button" id="start_eeg_train" class="btn btn-primary mx-3">Start training data collection</button>
|
||||||
|
<button type="button" id="start_eeg_test" class="btn btn-primary mx-3">Start test data collection</button>
|
||||||
|
<button type="button" id="load-saved" class="btn btn-primary mx-3">Load saved session</button>
|
||||||
|
<button type="button" id="load-backup" class="btn btn-primary mx-3">Load previous automatic backup</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
// Initialise socketio with a namespace called "main"
|
||||||
|
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||||
|
|
||||||
|
$('#load-backup').click(function(event) {
|
||||||
|
// Send message to call stimulus generation function in Python
|
||||||
|
socket.emit('load_eeg_backup', {part_key: $("#participant").val()});
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
$('#load-saved').click(function(event) {
|
||||||
|
// Send message to call stimulus generation function in Python
|
||||||
|
socket.emit('load_eeg_session', {part_key: $("#participant").val()});
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
$('#start_eeg_train').click(function(event) {
|
||||||
|
// Send message to call stimulus generation function in Python
|
||||||
|
socket.emit('start_eeg_train', {part_key: $("#participant").val()});
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
$('#start_eeg_test').click(function(event) {
|
||||||
|
// Send message to call stimulus generation function in Python
|
||||||
|
socket.emit('start_eeg_test', {part_key: $("#participant").val()});
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on('participant_start_mat', function(msg) {
|
||||||
|
window.location.href = '/eeg/clinician/control';
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
socket.on('save-dialog-resp', function(msg) {
|
||||||
|
// Set form test to filepath returned by dialog
|
||||||
|
document.getElementById("save-dir").value = msg.data
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#mat-dir-button').click(function(event) {
|
||||||
|
// Send message to call stimulus generation function in Python
|
||||||
|
socket.emit('open_eeg_dialog');
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on('eeg-dialog-resp', function(msg) {
|
||||||
|
// Set form test to filepath returned by dialog
|
||||||
|
document.getElementById("eeg-dir").value = msg.data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -83,8 +83,8 @@
|
|||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<a class="dropdown-item" href="#">PTA</a>
|
<a class="dropdown-item" href="#">PTA</a>
|
||||||
<a class="dropdown-item" href="#">Tympanometry</a>
|
<a class="dropdown-item" href="#">Tympanometry</a>
|
||||||
<a class="dropdown-item" href="/matrix_test">Matrix Test</a>
|
<a class="dropdown-item" href="/matrix_test">Behavioral Matrix Test</a>
|
||||||
<a class="dropdown-item" href="#">EEG recording</a>
|
<a class="dropdown-item" href="/eeg">EEG recording</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -36,17 +36,14 @@
|
|||||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||||
|
|
||||||
$('#load-backup').click(function(event) {
|
$('#load-backup').click(function(event) {
|
||||||
// Send message to call stimulus generation function in Python
|
|
||||||
socket.emit('load_mat_backup', {part_key: $("#participant").val()});
|
socket.emit('load_mat_backup', {part_key: $("#participant").val()});
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
$('#load-saved').click(function(event) {
|
$('#load-saved').click(function(event) {
|
||||||
// Send message to call stimulus generation function in Python
|
|
||||||
socket.emit('load_mat_session', {part_key: $("#participant").val()});
|
socket.emit('load_mat_session', {part_key: $("#participant").val()});
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
$('#submit').click(function(event) {
|
$('#submit').click(function(event) {
|
||||||
// Send message to call stimulus generation function in Python
|
|
||||||
socket.emit('start_mat_test', {listN: $("#listN").val(), part_key: $("#participant").val()});
|
socket.emit('start_mat_test', {listN: $("#listN").val(), part_key: $("#participant").val()});
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user