Skip to content
This repository was archived by the owner on Nov 5, 2023. It is now read-only.

Commit 83cdb0c

Browse files
committed
Add start of typing mode. Tweak webhook request format.
1 parent 1b992a6 commit 83cdb0c

File tree

9 files changed

+122
-8
lines changed

9 files changed

+122
-8
lines changed

app/assets/scss/app.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ a.nav-link.active {
350350
position:absolute;
351351
bottom:0; // make transcription start from the bottom
352352
max-height:100%;
353+
min-width:5px;
353354
}
354355

355356
.final:focus {

app/components/Navbar.vue

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
<div v-if="waitingForInitialTranscript" class="navbar-text small text-primary mr-3">
2626
Listening<span v-if="microphoneName"> to "{{microphoneName}}"</span>
2727
</div>
28+
<b-btn v-show="false && !typingModeOn" variant="info" class="mr-3" v-b-tooltip.top title="Typing Mode" @click="startTypingMode">
29+
<fa icon="keyboard"/>
30+
</b-btn>
31+
<b-btn v-show="false && typingModeOn" variant="secondary" class="mr-3" v-b-tooltip.top title="Turn Off" @click="stopTypingMode">
32+
<fa icon="keyboard"/> Typing Mode
33+
</b-btn>
2834
<transition name="fade">
2935
<cast-button v-if="experiments.includes('chromecast')"></cast-button>
3036
</transition>
@@ -131,6 +137,9 @@ export default {
131137
captioningOn: function() {
132138
return this.$store.state.captioner.shouldBeOn;
133139
},
140+
typingModeOn: function() {
141+
return this.$store.state.captioner.typingModeOn;
142+
},
134143
microphoneName: function() {
135144
return this.$store.state.captioner.microphoneName;
136145
},
@@ -186,11 +195,11 @@ export default {
186195
stopCaptioning: function() {
187196
this.$store.dispatch('captioner/stopManual');
188197
},
189-
startTyping: function() {
190-
this.$store.dispatch('captioner/startTyping');
198+
startTypingMode: function() {
199+
this.$store.dispatch('captioner/startTypingMode');
191200
},
192-
stopTyping: function() {
193-
this.$store.dispatch('captioner/stopTyping');
201+
stopTypingMode: function() {
202+
this.$store.dispatch('captioner/stopTypingMode');
194203
},
195204
startSaveToFileModal: function() {
196205
this.$router.push('/captioner/save-to-file');

app/components/Transcript.vue

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
<div
33
class="transcript d-flex"
44
v-bind:class="[wrapTextPositionClass, (chromeless ? 'chromeless' : '')]"
5-
v-bind:style="{height, color, backgroundColor, fontFamily, fontSize, lineHeight, letterSpacing, textTransform, padding, textShadow}">
5+
v-bind:style="{height, color, backgroundColor, fontFamily, fontSize, lineHeight, letterSpacing, textTransform, padding, textShadow, cursor}"
6+
@click="focusIfInTypingMode()">
67
<link type="text/css" rel="stylesheet" :href="'https://fonts.googleapis.com/css?family=' + fontFamily" />
78
<span
89
v-bind:class="textPositionClass"
910
class="transcript-scroller"
1011
ref="scroller">
11-
<span class="transcript-scroller-child">{{finalTranscript}} <span v-if="interimTranscript" v-bind:style="{color: interimColor}">{{interimTranscript}}</span></span>
12+
<span class="transcript-scroller-child">{{finalTranscript}} <span v-if="interimTranscript" v-bind:style="{color: interimColor}">{{interimTranscript}}</span> <span v-show="typingModeOn" contenteditable v-text="transcriptTypedForDisplay" @input="typedTranscriptDidChange()" ref="typedTranscript" class="transcriptTyped">Hello world</span></span>
1213
</span>
1314
</div>
1415
</template>
@@ -27,6 +28,7 @@ export default {
2728
data: function() {
2829
return {
2930
height: '100vh',
31+
transcriptTypedForDisplay: '',
3032
}
3133
},
3234
methods: {
@@ -37,6 +39,14 @@ export default {
3739
}
3840
});
3941
},
42+
typedTranscriptDidChange: function() {
43+
this.$store.commit('captioner/SET_TRANSCRIPT_TYPED', {transcriptTyped: this.$refs.typedTranscript.innerText})
44+
},
45+
focusIfInTypingMode: function() {
46+
if (this.typingModeOn) {
47+
this.$refs.typedTranscript.focus();
48+
}
49+
},
4050
},
4151
mounted: function() {
4252
this.scrollToBottom();
@@ -54,6 +64,37 @@ export default {
5464
this.height = this.adjustAppHeight();
5565
});
5666
},
67+
watch: {
68+
typingModeOn: function (on) {
69+
if (on) {
70+
// Turned on. Copy the transcript over once.
71+
this.transcriptTypedForDisplay = this.typedTranscript;
72+
this.$nextTick(() => {
73+
this.$refs.typedTranscript.focus();
74+
75+
// Put caret at end
76+
if (typeof window.getSelection != "undefined"
77+
&& typeof document.createRange != "undefined") {
78+
var range = document.createRange();
79+
range.selectNodeContents(this.$refs.typedTranscript);
80+
range.collapse(false);
81+
var sel = window.getSelection();
82+
sel.removeAllRanges();
83+
sel.addRange(range);
84+
} else if (typeof document.body.createTextRange != "undefined") {
85+
var textRange = document.body.createTextRange();
86+
textRange.moveToElementText(this.$refs.typedTranscript);
87+
textRange.collapse(false);
88+
textRange.select();
89+
}
90+
});
91+
}
92+
else {
93+
// Turned off.
94+
this.transcriptTypedForDisplay = '';
95+
}
96+
},
97+
},
5798
computed: {
5899
// Appearance
59100
color () {
@@ -107,6 +148,12 @@ export default {
107148
return (this.$store.state.captioner.transcript.interim && this.$store.state.captioner.transcript.interim.length ? ' ' : '')
108149
+ this.$store.state.captioner.transcript.interim;
109150
},
151+
typingModeOn () {
152+
return this.$store.state.captioner.typingModeOn;
153+
},
154+
typedTranscript () {
155+
return this.$store.state.captioner.transcript.typed;
156+
},
110157
111158
textPositionClass: function () {
112159
return {
@@ -130,6 +177,9 @@ export default {
130177
'align-items-end': ['bottom','lowerThird'].includes(this.$store.state.settings.appearance.text.alignment.vertical),
131178
}
132179
},
180+
cursor: function() {
181+
return this.typingModeOn ? 'text' : 'default';
182+
},
133183
largerLayout: function() {
134184
return this.$store.state.settings.controls.layout.larger;
135185
},
@@ -138,4 +188,10 @@ export default {
138188
</script>
139189

140190
<style lang="css">
191+
.transcriptTyped {
192+
outline:none;
193+
min-width:5px;
194+
display:inline-block;
195+
min-height:100px;
196+
}
141197
</style>

app/nuxt.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module.exports = {
3232
imports: [
3333
{
3434
set: '@fortawesome/free-solid-svg-icons',
35-
icons: ['faFileAlt', 'faFileWord', 'faExclamationTriangle', 'faTimes', 'faMicrophone', 'faDesktop', 'faExternalLinkAlt', 'faSave', 'faTrashAlt', 'faCog', 'faCheckCircle', 'faSpinner', 'faChevronRight', 'faMinusCircle', 'faPlusCircle', 'faArrowLeft', 'faFlask', 'faCaretRight', 'faCaretDown', ],
35+
icons: ['faFileAlt', 'faFileWord', 'faExclamationTriangle', 'faTimes', 'faMicrophone', 'faDesktop', 'faExternalLinkAlt', 'faSave', 'faTrashAlt', 'faCog', 'faCheckCircle', 'faSpinner', 'faChevronRight', 'faMinusCircle', 'faPlusCircle', 'faArrowLeft', 'faFlask', 'faCaretRight', 'faCaretDown', 'faKeyboard', ],
3636
},
3737
{
3838
set: '@fortawesome/free-regular-svg-icons',
@@ -45,6 +45,9 @@ module.exports = {
4545
]
4646
}],
4747
],
48+
plugins: [
49+
'~/node_modules/vue-contenteditable-directive',
50+
],
4851
css: [
4952
'@/assets/scss/app.scss',
5053
],

app/package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"sass-loader": "^7.1.0",
5555
"screenfull": "^3.3.2",
5656
"semver-compare": "^1.0.0",
57+
"vue-contenteditable-directive": "^1.2.0",
5758
"whatwg-fetch": "^2.0.4"
5859
}
5960
}

app/pages/captioner.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ export default {
217217
mode: 'cors',
218218
headers: {
219219
'Accept': 'application/json',
220-
'Content-Type': 'application/json',
221220
},
222221
body,
223222
})

app/store/modules/captioner/index.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ let speechRecognizer,
1313
const state = {
1414
on: false,
1515
shouldBeOn: false,
16+
typingModeOn: false,
1617
microphonePermission: {
1718
needed: false,
1819
denied: false,
@@ -22,6 +23,7 @@ const state = {
2223
transcript: {
2324
interim: '',
2425
final: '',
26+
typed: '',
2527
lastStart: null,
2628
lastUpdate: null,
2729
waitingForInitial: false,
@@ -198,6 +200,21 @@ const actions = {
198200
});
199201
}
200202
},
203+
204+
startTypingMode: ({state, commit, dispatch}) => {
205+
dispatch('stopManual');
206+
setTimeout(() => {
207+
commit('SET_TRANSCRIPT_TYPED', {transcriptTyped: state.transcript.final});
208+
commit('CLEAR_TRANSCRIPT_FINAL');
209+
commit('SET_TYPING_MODE_ON');
210+
},500);
211+
},
212+
213+
stopTypingMode: ({state, commit, dispatch}) => {
214+
commit('APPEND_TRANSCRIPT_FINAL', {transcriptFinal: state.transcript.typed });
215+
commit('CLEAR_TRANSCRIPT_TYPED');
216+
commit('SET_TYPING_MODE_OFF');
217+
},
201218
}
202219

203220
const mutations = {
@@ -227,13 +244,23 @@ const mutations = {
227244
state.transcript.interim = transcriptInterim;
228245
state.transcript.lastUpdate = Date.now();
229246
},
247+
SET_TRANSCRIPT_TYPED (state, { transcriptTyped }) {
248+
state.transcript.typed = transcriptTyped;
249+
},
230250
CLEAR_TRANSCRIPT (state) {
231251
state.transcript.interim = '';
232252
state.transcript.final = '';
253+
state.transcript.typed = '';
233254
},
234255
CLEAR_TRANSCRIPT_INTERIM (state) {
235256
state.transcript.interim = '';
236257
},
258+
CLEAR_TRANSCRIPT_FINAL (state) {
259+
state.transcript.final = '';
260+
},
261+
CLEAR_TRANSCRIPT_TYPED (state) {
262+
state.transcript.typed = '';
263+
},
237264
APPEND_TRANSCRIPT_FINAL (state, { transcriptFinal }) {
238265
if (state.transcript.final.length && state.transcript.final.charAt(state.transcript.final.length - 1) != ' ') {
239266
// Current final string is not empty and doesn't end in a
@@ -258,6 +285,14 @@ const mutations = {
258285
SET_WAITING_FOR_INITIAL_TRANSCRIPT (state, { waitingForInitial }) {
259286
state.transcript.waitingForInitial = waitingForInitial;
260287
},
288+
289+
SET_TYPING_MODE_ON (state) {
290+
state.typingModeOn = true;
291+
},
292+
293+
SET_TYPING_MODE_OFF (state) {
294+
state.typingModeOn = false;
295+
},
261296
}
262297

263298
const getters = {

app/store/mutations.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ export default {
136136
state.detached = false;
137137
},
138138

139+
SET_DETACHED_MODE_OFF: (state) => {
140+
state.detached = false;
141+
},
142+
139143
SET_LAST_WHATS_NEW_VERSION_SEEN: (state, { version }) => {
140144
state.settings.lastWhatsNewVersionSeen = version;
141145
},

0 commit comments

Comments
 (0)