Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions src/components/CallView/shared/LiveTranscriptionRenderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

<script lang="ts">
import type { PropType } from 'vue'
import type { Chunk } from './TranscriptBlock.vue'

import TranscriptBlock from './TranscriptBlock.vue'
import { useLiveTranscriptionStore } from '../../../stores/liveTranscription.ts'
Expand Down Expand Up @@ -49,11 +50,6 @@ interface CallParticipantModel {
off: (event: string, handler: (model: CallParticipantModel, ...args: any[]) => void) => void
}

interface Chunk {
message: string
languageId: string
}

interface TranscriptBlockData {
id: number
model: CallParticipantModel
Expand Down Expand Up @@ -175,7 +171,7 @@ export default {
}

for (let i = 0; i < this.$refs.transcriptBlocks.length; i++) {
this.$refs.transcriptBlocks[i].resetLines()
this.$refs.transcriptBlocks[i].reset()
}

this.$refs.transcript.scrollTo({
Expand Down Expand Up @@ -217,8 +213,10 @@ export default {
* @param message the transcribed message.
* @param languageId the ID of the language of the transcribed
* message.
* @param final true if the transcript will not be updated afterwards,
* false otherwise.
*/
handleTranscript(model: CallParticipantModel, message: string, languageId: string) {
handleTranscript(model: CallParticipantModel, message: string, languageId: string, final: boolean) {
let lastTranscriptBlock = this.transcriptBlocks.at(-1)

const messageIsRightToLeft = this.liveTranscriptionLanguages[languageId]?.metadata.rtl || false
Expand All @@ -237,10 +235,18 @@ export default {
lastTranscriptBlock = transcriptBlock
}

lastTranscriptBlock.chunks.push({
const newTranscriptChunk = {
message,
languageId,
})
final,
}

const lastTranscriptChunk = lastTranscriptBlock.chunks.at(-1)
if (!lastTranscriptChunk || lastTranscriptChunk.final) {
lastTranscriptBlock.chunks.push(newTranscriptChunk)
} else {
lastTranscriptBlock.chunks.splice(-1, 1, newTranscriptChunk)
}

this.$nextTick(() => {
this.scrollToBottomLineByLine()
Expand Down Expand Up @@ -285,6 +291,13 @@ export default {
}

const lastScrolledToBlockLineBoundaries = this.$refs.transcriptBlocks![this.lastScrolledToBlockAndLine.block].getLineBoundaries()

// Fix line number if last chunk was replaced with a shorter text
// that uses less lines.
if (this.lastScrolledToBlockAndLine.line >= lastScrolledToBlockLineBoundaries.length) {
this.lastScrolledToBlockAndLine.line = lastScrolledToBlockLineBoundaries.length - 1
}

if (this.lastScrolledToBlockAndLine.line < lastScrolledToBlockLineBoundaries.length - 1) {
this.scrollToBlockAndLine(this.lastScrolledToBlockAndLine.block, this.lastScrolledToBlockAndLine.line + 1)

Expand Down
194 changes: 194 additions & 0 deletions src/components/CallView/shared/TranscriptBlock.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { shallowMount } from '@vue/test-utils'
import { beforeEach, describe, expect, test } from 'vitest'
import TranscriptBlock from './TranscriptBlock.vue'

describe('TranscriptBlock.vue', () => {
describe('remove last chunk from lines', () => {
let wrapper
let lines

beforeEach(() => {
wrapper = shallowMount(TranscriptBlock, {
props: {
token: 'theToken',
model: {
attributes: {
peerId: 'thePeerId',
actorId: 'theActorId',
actorType: 'theActorType',
userId: 'theUserId',
name: 'The user name',
},
},
chunks: [],
rightToLeft: false,
},
})

lines = wrapper.vm.$data.lines
})

test('no lines', () => {
wrapper.vm.removeLastChunkFromLines()

expect(lines.length).toBe(0)
})

test('single line with single chunk', () => {
lines.push({
firstChunkIndex: 42,
lastChunkIndex: 42,
})

wrapper.vm.removeLastChunkFromLines()

expect(lines.length).toBe(0)
})

test('single line with several chunks', () => {
lines.push({
firstChunkIndex: 42,
lastChunkIndex: 108,
})

wrapper.vm.removeLastChunkFromLines()

expect(lines).toEqual([
{
firstChunkIndex: 42,
lastChunkIndex: 107,
},
])
})

test('several lines with single chunk', () => {
lines.push({
firstChunkIndex: 42,
lastChunkIndex: 42,
})
lines.push({
firstChunkIndex: 42,
lastChunkIndex: 42,
})
lines.push({
firstChunkIndex: 42,
lastChunkIndex: 42,
})

wrapper.vm.removeLastChunkFromLines()

expect(lines.length).toBe(0)
})

describe('several lines with several chunks', () => {
test('last chunk filling last line', () => {
lines.push({
firstChunkIndex: 23,
lastChunkIndex: 42,
})
lines.push({
firstChunkIndex: 108,
lastChunkIndex: 108,
})

wrapper.vm.removeLastChunkFromLines()

expect(lines).toEqual([
{
firstChunkIndex: 23,
lastChunkIndex: 42,
},
])
})

test('last chunk filling several lines', () => {
lines.push({
firstChunkIndex: 23,
lastChunkIndex: 42,
})
lines.push({
firstChunkIndex: 108,
lastChunkIndex: 108,
})
lines.push({
firstChunkIndex: 108,
lastChunkIndex: 108,
})
lines.push({
firstChunkIndex: 108,
lastChunkIndex: 108,
})

wrapper.vm.removeLastChunkFromLines()

expect(lines).toEqual([
{
firstChunkIndex: 23,
lastChunkIndex: 42,
},
])
})

test('last chunk partially in last line', () => {
lines.push({
firstChunkIndex: 23,
lastChunkIndex: 42,
})
lines.push({
firstChunkIndex: 42,
lastChunkIndex: 108,
})

wrapper.vm.removeLastChunkFromLines()

expect(lines).toEqual([
{
firstChunkIndex: 23,
lastChunkIndex: 42,
},
{
firstChunkIndex: 42,
lastChunkIndex: 107,
},
])
})

test('last chunk partially in several lines', () => {
lines.push({
firstChunkIndex: 23,
lastChunkIndex: 42,
})
lines.push({
firstChunkIndex: 42,
lastChunkIndex: 108,
})
lines.push({
firstChunkIndex: 108,
lastChunkIndex: 108,
})
lines.push({
firstChunkIndex: 108,
lastChunkIndex: 108,
})

wrapper.vm.removeLastChunkFromLines()

expect(lines).toEqual([
{
firstChunkIndex: 23,
lastChunkIndex: 42,
},
{
firstChunkIndex: 42,
lastChunkIndex: 107,
},
])
})
})
})
})
Loading