Merge branch 'working' into 'main'

Working again

See merge request JanDickmann/masterproject!4
This commit is contained in:
Jan Dickmann 2024-08-20 14:37:14 +00:00
commit 56a20f4465
6 changed files with 749 additions and 87 deletions

View File

@ -11,7 +11,7 @@ import uuid
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import select, join
from sqlalchemy.orm import DeclarativeBase
from flask_wtf.csrf import CSRFProtect
#from flask_wtf.csrf import CSRFProtect
import os
import csv
from zipfile import ZipFile
@ -33,6 +33,7 @@ app = Flask(__name__)
# configure the database, give it a path (it will be in the instances folder)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database.db"
app.config["PERMANENT_SESSION_LIFETIME"] = 10800 #3 Stunden, 10800 sekunden
app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000 # try and fix video upload not working
db.init_app(app)
#set the secret key (TODO change this for final deployment)
@ -41,6 +42,9 @@ app.secret_key = b"29fe9e8edd407c5491d4f1c05632d9fa33e26ed8734a3f5e080ebac3772a5
UPLOAD_FOLDER = 'uploads'
EXPORT_FOLDER = 'exports'
PASSWORD = '#1ACGmsjd'
# CONFIGFILE = 'userstudy1.json'
CONFIGFILE = 'test.json'
# CONFIGFILE = 'default.json'
#csrf = CSRFProtect(app) #enable CSRF protection globally
@ -70,7 +74,7 @@ except SQLAlchemyError as e:
#open, parse and execute json file
#open the json file with the config
configfile = open("default.json", encoding='utf-8') #todo replace with other name
configfile = open(CONFIGFILE, encoding='utf-8') #todo replace with other name
#convert it to dict
config = json.load(configfile)
configfile.close()
@ -374,16 +378,6 @@ def sendpage():
print("Error occurred: {e}".format(e=str(e)))
return "There was a problem while adding the response to the Database"
# handle possible Video that was send
if 'recordedVideo' in request.files:
video = request.files['recordedVideo']
formatted_date = date.strftime("%Y.%m.%d %H-%M-%S")
print("date: ", date)
video_name = str(session_user_id) + "_" + session["current_block_name"] + "_" + session["current_stimulus_name"] + "_" + str(formatted_date) + ".webm"
path = os.path.join(UPLOAD_FOLDER, video_name)
print("path: ",path)
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
video.save(path)
if (session["current_block_index"] == session["number_of_blocks"]-1) and (session["current_stimulus_index"] >= session["number_of_stimuli"]-1):
#update the database entry, the form is completed

View File

@ -1,64 +1,73 @@
const buttonCamera = document.getElementById('buttonCamera');
const buttonRecord = document.getElementById('buttonRecord');
const buttonDelete = document.getElementById('buttonDelete');
const videoDisplay = document.getElementById('videoDisplay');
const buttonCameraIcon = document.getElementById('buttonCameraIcon');
const buttonRecordIcon = document.getElementById('buttonRecordIcon');
const buttonDeleteIcon = document.getElementById('buttonDeleteIcon');
const videoContainer = document.getElementById('videoContainer');
const videoContainerCss = document.querySelector(".video-container ") //might be unnecessary
var mediaRecorder = null;
var stream = null;
let recordedVideoBlob = null;
let isRecording = false;
let videoAccess = false;
let videoHeigt = 720;
const videoDisplay = document.getElementById('videoDisplay');
const videoContainer = document.getElementById('videoContainer'); // div that contains the videodisplay
var mediaRecorder = null; // interface of the Media Stream Recording API to record the video stream
var stream = null; // webcam video input stream
let recordedVideoBlob = null; // recorded videodata
let isRecording = false; // false to display record button, true to display stop button
let videoAccess = false; // true if user has given permission to use the webcam
// default video dimensions
let videoHeight = 720;
let videoWidth = 1280;
// Handle form submission
// handle form submission
//the Video is beeing send together with the form data
document.getElementById("question_form").addEventListener("submit", function (event) {
event.preventDefault(); // Prevent the default form submission
console.log("submit button pressed");
// Create a FormData object
// create a FormData object
const formData = new FormData(event.target);
console.log("form data: ",formData);
// Append the recorded video Blob to the FormData object
// append the recorded video blob to the FormData object
if (recordedVideoBlob) {
console.log("video is available: ", recordedVideoBlob);
formData.append("recordedVideo", recordedVideoBlob, "recordedVideo.webm");
}
console.log("Data to be submitted: ",formData);
// Use fetch to send the form data and video to the backend
console.log("try to send the form and video");
// send the form data and video to the backend
fetch("/send", {
method: "POST",
body: formData
}).then(response => {
// code to handle proper redirection after submit
console.log('Response:', response);
// Check if response is a redirect (HTTP 3xx status)
// check if response is a redirect
/*
if (response.redirected) {
console.log("Redirecting to:", response.url);
window.location.href = response.url; // Redirect to the new page
} else {
console.log("Non-redirect response received.");
// Handle other responses if needed
console.log("No redirect response received.");
}
*/
})
.catch(error => {
console.error('Error:', error);
// Handle errors if fetch fails
});
});
// enable/disable video recording feature
async function cameraButton() {
if (!videoAccess) {
console.log("cameraButton case videoAccess = false");
try {
// ask the user for permission to use the webcam
// if given, assign it to "stream"
stream = await navigator.mediaDevices.getUserMedia({
video: true,
});
@ -67,39 +76,61 @@ async function cameraButton() {
return;
}
console.log("stream is active");
videoAccess = true;
videoHeigt = stream.getVideoTracks()[0].getSettings().height
// set the dimensions of the webcam stream to the video display
videoHeight = stream.getVideoTracks()[0].getSettings().height
videoWidth = stream.getVideoTracks()[0].getSettings().width
let aspectratio = (videoHeigt / videoWidth) *100
console.log("videoHeigt: ",videoHeigt);
console.log("videoWidth: ",videoWidth);
console.log("aspect ratio: ",aspectratio);
console.log("device: ",stream.getVideoTracks()[0].getSettings().deviceId);
videoContainer.style.setProperty("padding-bottom", "min("+videoHeigt+"px,"+aspectratio+"%)");
// calculate the aspec ratio
let aspectratio = (videoHeight / videoWidth) *100;
//console.log("videoHeight: ",videoHeight);
//console.log("videoWidth: ",videoWidth);
//console.log("aspect ratio: ",aspectratio);
//console.log("device: ",stream.getVideoTracks()[0].getSettings().deviceId);
if (videoHeigt > videoWidth){ //hochkant video
videoContainer.style.setProperty("max-width", "min(80%,576");
}else{ //Normal, horizontal
// adjust CSS to make the video fit properly
// this makes sure that there is no buggy "jumping" when the video display source changes
videoContainer.style.setProperty("padding-bottom", "min("+videoHeight+"px,"+aspectratio+"%), 100vh");
//TODO: Solution for this part:
// If the video is vertical, I need to set the width to 0, the max-height to 100% and do the padding on the width, so turn the code around
//This should always make the video fitt
// adjust the max width for horizontal and vertical video input
if (videoHeight > videoWidth){ //hochkant video
// I did this originally to display vertical video on a horizontal screen properly (video should not be higher than the screem)
// but now I do this by adjusting the paddint to be at most 100vh, so this whole part should be useless now
// But a new problem could be if I do too little padding and the ratio is lost because of it, so actually I also need to adjust the width
videoContainer.style.setProperty("max-width", "min(80%,576)"); // maybe actually use the screen height here: instead of 80% maybe 80vh
}else{ //normal, horizontal
videoContainer.style.setProperty("max-width", "100%");
}
// show the webcam input stream on the video display
videoDisplay.srcObject = stream;
// change the icon to indicate the disable option
buttonCameraIcon.src = ICON_PATHS.cameraofficon;
buttonCameraIcon.alt = "Camera-off Icon";
// display the elements for the video recording
buttonRecord.style.display = 'inline-block';
buttonDelete.style.display = 'inline-block';
videoDisplay.style.display = 'block';
videoContainer.style.display = 'block';
videoDisplay.classList.add("videomirror");
// initialize MediaRecorder, give it the webcam stream as input to record
mediaRecorder = new MediaRecorder(stream, {
mimeType: "video/webm", // could use different video format
// videoBitsPerSecond: 5000000, // Standard bitrate for video is 2,5 mbps
});
// when data is available at the mediaRecorder (this means the recording has ended, since I have not specified time intervalls)
// save the data in "recordedVideoBlob"
mediaRecorder.addEventListener("dataavailable", (event) => {
console.log("Data available Event triggered");
if (event.data.size > 0) {
@ -110,28 +141,37 @@ async function cameraButton() {
}
});
mediaRecorder.addEventListener("stop", () => {
// when recording is stopped, display the recorded video
// TODO possibly replace this and just add it to the dataavailable event
// TODO this would ensure proper order in a concurrent scenario (the stop code here can only be executed after the dataavailable code happened)
// TODO part of it could also go to the record button function
mediaRecorder.addEventListener("stop", () => {
if (recordedVideoBlob) {
videoDisplay.srcObject = null;
videoDisplay.src = URL.createObjectURL(recordedVideoBlob);
videoDisplay.controls = true;
videoDisplay.pause();
videoDisplay.srcObject = null; //remove the stream as input
videoDisplay.src = URL.createObjectURL(recordedVideoBlob); // create a url for the recorded video and set it as input
videoDisplay.controls = true; // display video controls
videoDisplay.pause(); // pause, so that it doesn't immediately play, TODO maybe disable autoplay?
buttonRecordIcon.src = ICON_PATHS.recordicon;
// TODO maybe move this to the record button function
buttonRecordIcon.src = ICON_PATHS.recordicon; //change the icon of the record button back
buttonRecordIcon.alt = 'Record Icon';
isRecording = false;
console.log('Recording stopped');
console.log("Src path:", videoDisplay.src);
}
});
} else {
// -> the user disabled the videorecording feature
console.log("cameraButton case videoAccess = true");
stream.getTracks().forEach(track => track.stop()); // Stop all tracks to release the camera
stream.getTracks().forEach(track => track.stop()); // stop all tracks to release the camera
stream = null;
videoAccess = false;
// change the icon and hide all the elements again
buttonCameraIcon.src = ICON_PATHS.cameraicon;
buttonCameraIcon.alt = "Camera Icon";
buttonRecord.style.display = 'none';
@ -142,41 +182,57 @@ async function cameraButton() {
console.log("camera button function ends");
}
function recordButton() {
console.log("recordButton pressed");
if (!isRecording) {
// a new recording starts
console.log("recordButton pressed case isRecording = false");
deleteButton();
videoDisplay.classList.add("videomirror");
buttonDelete.setAttribute("disabled", "");
buttonDeleteIcon.classList.add("buttondisable");
videoDisplay.srcObject = stream;
videoDisplay.src = null;
videoDisplay.controls = false;
mediaRecorder.start();
deleteButton(); //delete previous video
videoDisplay.classList.add("videomirror"); // mirror the video while recording, for a more natural experience
buttonDelete.setAttribute("disabled", ""); // can't delete during recording
buttonDeleteIcon.classList.add("buttondisable"); // delete button icon indicates that it is disabled
videoDisplay.src = null; // get rid of the previous video on the display
videoDisplay.srcObject = stream; // set webcam stream as input for the video display
videoDisplay.controls = false; // hide the video controls durin recording, because they are confusing
mediaRecorder.start(); // start recording
console.log("video bitrate = ",mediaRecorder.videoBitsPerSecond);
// change icon to indicate "stop"
buttonRecordIcon.src = ICON_PATHS.stopicon;
buttonRecordIcon.alt = 'Stop Icon';
isRecording = true;
console.log('Recording started');
} else {
// recording got stopped
console.log("recordButton pressed case isRecording = true");
mediaRecorder.stop();
videoDisplay.classList.remove("videomirror");
mediaRecorder.stop(); // stop recording
videoDisplay.classList.remove("videomirror"); // don't mirror the videodisplay anymore
console.log("recording stops");
// enable the deletebutton again
buttonDelete.removeAttribute("disabled");
buttonDeleteIcon.classList.remove("buttondisable");
}
}
function deleteButton() {
// TODO delete data
// delete the recorded video
videoDisplay.controls = false;
videoDisplay.srcObject = stream;
videoDisplay.srcObject = stream; // set webcam stream as source for the video display again
recordedVideoBlob = null
videoDisplay.classList.add("videomirror");
videoDisplay.classList.add("videomirror"); // mirror the video display during live feed again
// disable the deletebutton again
buttonDelete.setAttribute("disabled", "");
buttonDeleteIcon.classList.add("buttondisable");
}

View File

@ -225,7 +225,6 @@ step={{question["step"]}}
</div>
<script src="{{ url_for('static', filename='videoscript.js')}}">
</script>
{% else %}
<p>Error: Block {{config["question 1"]["blocks"][block]["type"]}} could not be loaded!</p>

View File

@ -1,37 +1,325 @@
{
"Block 1":{
"type": "SinglePage",
"template": "startpage.html"
},
"Block 2":{
"Block 2": {
"type": "TaskTemplate",
"tempalte": "tempaltetest1.html",
"name" : "Block2Responses",
"databasetable": {
"question_title" : {
"type":"likert"
"tempalte": "standard_template.html",
"stimuli": {
"type": "single_video",
"order": "random",
"list": {
"video_1": "https://www.youtube-nocookie.com/embed/iI2bjpgLgu0?si=pWWwitq8Tl9zAs04",
"video_2": "https://www.youtube-nocookie.com/embed/R_LNEJiShRM?si=vm5mj-xs04nfijkf",
"video_3": "https://www.youtube-nocookie.com/embed/DJnHVnT2YEk?si=e6qe7nrHaRYJ3NQe",
"video_4": "https://www.youtube-nocookie.com/embed/6BTZn7tqSzk?si=jQH8RHGMIP9ARsT5",
"video_5": "https://www.youtube-nocookie.com/embed/bCRqmhWjuCk?si=iM2dwOSTosLq08Pr",
"video_6": "https://www.youtube-nocookie.com/embed/hgE2k8y9-qc?si=kR2rshmVcb9P70r0"
},
"configuration": {
"embed": "yt"
}
},
"questions": {
"question1": {
"type": "likert",
"name": "likertscale",
"text": "Wie würden sie dieses Video bewerten?",
"required": "true",
"points": {
"p1": {
"value": "1",
"text": "Ich finde es gar nicht gut 🙁👎"
},
"p2": {
"value": "2",
"text": "Ich finde es nicht gut 👎"
},
"p3": {
"value": "3",
"text": "Ich finde es weder gut noch schlecht"
},
"p4": {
"value": "4",
"text": "Ich finde es gut 👍"
},
"p5": {
"value": "5",
"text": "Ich finde es sehr gut 😊👍"
}
}
},
"question2": {
"type": "textinput",
"name": "text_feedback",
"text": "Hier können sie uns Feedback geben",
"required": "false",
"size": "250"
},
"question3": {
"type": "videoinput",
"text": "Hier können sie per Video Feedback geben",
"name": "video_feedback",
"required": "false"
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden.\\n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt.\\n Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "single_video_responses",
"fields": {
"likertscale": {
"type": "integer",
"nullable": "false"
},
"text_feedback": {
"type": "string",
"size": "250",
"nullable": "true"
},
"video_upload": {
"type": "string",
"size": "100",
"nullable": "true"
}
}
}
},
"question 3":{
"type": "single",
"video1": "https://www.youtube-nocookie.com/embed/XTMIomsXxKM?si=r2zB6OKERH6Jdpi6",
"scales": {
"block1":{
"type": "likert",
"numberofpoints": "3",
"points":{
"point1": "left",
"point2": "none",
"point3": "right"
"Block 1": {
"type": "TaskTemplate",
"tempalte": "standard_template.html",
"stimuli": {
"type": "empty",
"list": {
"empty_stimulus": ""
}
},
"questions": {
"question1_alter": {
"type": "numberinput",
"name": "alter",
"text": "Alter:",
"required": "true",
"min": "1",
"max": "120"
},
"question2_geschlecht": {
"type": "dropdowninput",
"name": "geschlecht",
"text": "Geschlecht:",
"required": "true",
"defaulttext": "",
"points": {
"männlich": {
"value": "Männlich",
"text": "Männlich"
},
"weiblich": {
"value": "Weiblich",
"text": "Weiblich"
},
"divers": {
"value": "Divers",
"text": "Divers"
},
"keine_angabe": {
"value": "keine_angabe",
"text": "Keine Angabe"
}
}
},
"block2":{
"type": "textinput",
"length": "200"
"question3_hoerstatus": {
"type": "dropdowninput",
"name": "hoerstatus",
"text": "Hörstatus:",
"required": "true",
"defaulttext": "",
"points": {
"hörend": {
"value": "Hörend",
"text": "Hörend"
},
"schwerhörig": {
"value": "Schwerhörig",
"text": "Schwerhörig"
},
"gehörlos": {
"value": "Gehörlos",
"text": "Gehörlos"
}
}
},
"block3":{
"type": "video"
"question4_bevorzugte_kommunikation": {
"type": "dropdowninput",
"name": "bevorzugte_kommunikation",
"text": "Bevorzugte Kommunikationsform:",
"required": "true",
"defaulttext": "",
"points": {
"gesprochen": {
"value": "Gesprochene Sprache",
"text": "Gesprochene Sprache"
},
"text": {
"value": "Text",
"text": "Text"
},
"gebärdensprache": {
"value": "Gebärdensprache",
"text": "Gebärdensprache"
}
}
},
"question5_gebeardenzeitraum": {
"type": "numberinput",
"name": "gebärdenzeitraum",
"text": "Wie viele Jahre verwenden sie schon Gebärdensprache:",
"required": "true",
"min": "0",
"max": "100",
"step": "0.5"
},
"question6_sprachkompetenz": {
"type": "numberinput",
"name": "gebärdensprachkompetenz",
"text": "Wie schätzen sie ihre Gebärdensprachkompetenz ein (1-10):",
"required": "true",
"min": "1",
"max": "10"
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. \n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "demographic_data",
"fields": {
"alter": {
"type": "integer",
"nullable": "false"
},
"geschlecht": {
"type": "string",
"size": "14",
"nullable": "false"
},
"hoerstatus": {
"type": "string",
"size": "14",
"nullable": "false"
},
"bevorzugte_kommunikation": {
"type": "string",
"size": "22",
"nullable": "false"
},
"gebärdenzeitraum": {
"type": "float",
"nullable": "false"
},
"gebärdensprachkompetenz": {
"type": "integer",
"nullable": "false"
}
}
}
},
"Block 3": {
"type": "TaskTemplate",
"tempalte": "standard_template.html",
"stimuli": {
"type": "double_video",
"list_1": {
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522",
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-"
},
"list_2": {
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-",
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522"
},
"configuration": {
"embed": "yt"
}
},
"questions": {
"question1": {
"type": "likert",
"name": "likertscale",
"text": "Welches Video gefällt ihnen besser?",
"required": "true",
"points": {
"p1": {
"value": "1",
"text": "Ich finde das linke Video besser"
},
"p2": {
"value": "2",
"text": "Ich finde beide Videos gleich gut"
},
"p3": {
"value": "3",
"text": "Ich finde das rechte Video besser"
}
}
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "double_video_responses",
"fields": {
"likertscale": {
"type": "integer",
"nullable": "false"
}
}
}
},
"Block 4": {
"type": "TaskTemplate",
"tempalte": "standard_template.html",
"stimuli": {
"type": "empty",
"list": {
"empty_stimulus": ""
}
},
"questions": {
"question1": {
"type": "textinput",
"name": "formfeedback",
"text": "Das war der Prototyp für dieses Studientool. Über Feedback würde ich mich freuen. Entweder hier oder per Email unter: jan.dickmann@web.de",
"required": "false",
"size": "1000"
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "feedback_responses",
"fields": {
"formfeedback": {
"type": "string",
"size": "1000",
"nullable": "true"
}
}
}
}

325
slaeforms/userstudy1.json Normal file
View File

@ -0,0 +1,325 @@
{
"Block 1": {
"type": "TaskTemplate",
"tempalte": "standard_template.html",
"stimuli": {
"type": "empty",
"list": {
"empty_stimulus": ""
}
},
"questions": {
"question1_alter": {
"type": "numberinput",
"name": "alter",
"text": "Alter:",
"required": "true",
"min": "1",
"max": "120"
},
"question2_geschlecht": {
"type": "dropdowninput",
"name": "geschlecht",
"text": "Geschlecht:",
"required": "true",
"defaulttext": "",
"points": {
"männlich": {
"value": "Männlich",
"text": "Männlich"
},
"weiblich": {
"value": "Weiblich",
"text": "Weiblich"
},
"divers": {
"value": "Divers",
"text": "Divers"
},
"keine_angabe": {
"value": "keine_angabe",
"text": "Keine Angabe"
}
}
},
"question3_hoerstatus": {
"type": "dropdowninput",
"name": "hoerstatus",
"text": "Hörstatus:",
"required": "true",
"defaulttext": "",
"points": {
"hörend": {
"value": "Hörend",
"text": "Hörend"
},
"schwerhörig": {
"value": "Schwerhörig",
"text": "Schwerhörig"
},
"gehörlos": {
"value": "Gehörlos",
"text": "Gehörlos"
}
}
},
"question4_bevorzugte_kommunikation": {
"type": "dropdowninput",
"name": "bevorzugte_kommunikation",
"text": "Bevorzugte Kommunikationsform:",
"required": "true",
"defaulttext": "",
"points": {
"gesprochen": {
"value": "Gesprochene Sprache",
"text": "Gesprochene Sprache"
},
"text": {
"value": "Text",
"text": "Text"
},
"gebärdensprache": {
"value": "Gebärdensprache",
"text": "Gebärdensprache"
}
}
},
"question5_gebeardenzeitraum": {
"type": "numberinput",
"name": "gebärdenzeitraum",
"text": "Wie viele Jahre verwenden sie schon Gebärdensprache:",
"required": "true",
"min": "0",
"max": "100",
"step": "0.5"
},
"question6_sprachkompetenz": {
"type": "numberinput",
"name": "gebärdensprachkompetenz",
"text": "Wie schätzen sie ihre Gebärdensprachkompetenz ein (1-10):",
"required": "true",
"min": "1",
"max": "10"
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. \n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "demographic_data",
"fields": {
"alter": {
"type": "integer",
"nullable": "false"
},
"geschlecht": {
"type": "string",
"size": "14",
"nullable": "false"
},
"hoerstatus": {
"type": "string",
"size": "14",
"nullable": "false"
},
"bevorzugte_kommunikation": {
"type": "string",
"size": "22",
"nullable": "false"
},
"gebärdenzeitraum": {
"type": "float",
"nullable": "false"
},
"gebärdensprachkompetenz": {
"type": "integer",
"nullable": "false"
}
}
}
},
"Block 2": {
"type": "TaskTemplate",
"tempalte": "standard_template.html",
"stimuli": {
"type": "single_video",
"order": "random",
"list": {
"video_1": "https://www.youtube-nocookie.com/embed/iI2bjpgLgu0?si=pWWwitq8Tl9zAs04",
"video_2": "https://www.youtube-nocookie.com/embed/R_LNEJiShRM?si=vm5mj-xs04nfijkf",
"video_3": "https://www.youtube-nocookie.com/embed/DJnHVnT2YEk?si=e6qe7nrHaRYJ3NQe",
"video_4": "https://www.youtube-nocookie.com/embed/6BTZn7tqSzk?si=jQH8RHGMIP9ARsT5",
"video_5": "https://www.youtube-nocookie.com/embed/bCRqmhWjuCk?si=iM2dwOSTosLq08Pr",
"video_6": "https://www.youtube-nocookie.com/embed/hgE2k8y9-qc?si=kR2rshmVcb9P70r0"
},
"configuration": {
"embed": "yt"
}
},
"questions": {
"question1": {
"type": "likert",
"name": "likertscale",
"text": "Wie würden sie dieses Video bewerten?",
"required": "true",
"points": {
"p1": {
"value": "1",
"text": "Ich finde es gar nicht gut 🙁👎"
},
"p2": {
"value": "2",
"text": "Ich finde es nicht gut 👎"
},
"p3": {
"value": "3",
"text": "Ich finde es weder gut noch schlecht"
},
"p4": {
"value": "4",
"text": "Ich finde es gut 👍"
},
"p5": {
"value": "5",
"text": "Ich finde es sehr gut 😊👍"
}
}
},
"question2": {
"type": "textinput",
"name": "text_feedback",
"text": "Hier können sie uns Feedback geben",
"required": "false",
"size": "250"
},
"question3": {
"type": "videoinput",
"text": "Hier können sie per Video Feedback geben",
"name": "video_feedback",
"required": "false"
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden.\\n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt.\\n Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "single_video_responses",
"fields": {
"likertscale": {
"type": "integer",
"nullable": "false"
},
"text_feedback": {
"type": "string",
"size": "250",
"nullable": "true"
},
"video_upload": {
"type": "string",
"size": "100",
"nullable": "true"
}
}
}
},
"Block 3": {
"type": "TaskTemplate",
"tempalte": "standard_template.html",
"stimuli": {
"type": "double_video",
"list_1": {
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522",
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-"
},
"list_2": {
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-",
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522"
},
"configuration": {
"embed": "yt"
}
},
"questions": {
"question1": {
"type": "likert",
"name": "likertscale",
"text": "Welches Video gefällt ihnen besser?",
"required": "true",
"points": {
"p1": {
"value": "1",
"text": "Ich finde das linke Video besser"
},
"p2": {
"value": "2",
"text": "Ich finde beide Videos gleich gut"
},
"p3": {
"value": "3",
"text": "Ich finde das rechte Video besser"
}
}
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "double_video_responses",
"fields": {
"likertscale": {
"type": "integer",
"nullable": "false"
}
}
}
},
"Block 4": {
"type": "TaskTemplate",
"tempalte": "standard_template.html",
"stimuli": {
"type": "empty",
"list": {
"empty_stimulus": ""
}
},
"questions": {
"question1": {
"type": "textinput",
"name": "formfeedback",
"text": "Das war der Prototyp für dieses Studientool. Über Feedback würde ich mich freuen. Entweder hier oder per Email unter: jan.dickmann@web.de",
"required": "false",
"size": "1000"
}
},
"infovideo": {
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
"configuration": {
"embed": "yt"
}
},
"database_table": {
"table_name": "feedback_responses",
"fields": {
"formfeedback": {
"type": "string",
"size": "1000",
"nullable": "true"
}
}
}
}
}

Binary file not shown.