Skip to content

Commit

Permalink
[MM-56089] Multi language support for captions (#586)
Browse files Browse the repository at this point in the history
* Multi language support for captions

* Update e2e test
  • Loading branch information
streamer45 authored Dec 11, 2023
1 parent 3957bea commit f5dc9c4
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 49 deletions.
3 changes: 2 additions & 1 deletion e2e/tests/recordings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ test.describe('call recordings and transcriptions', () => {
await expect(page.locator('.file-preview-modal__content')).toBeVisible();

// verify transcription track exists
await expect(page.getByTestId('calls-recording-transcription')).toHaveAttribute('label', 'Transcription');
await expect(page.getByTestId('calls-recording-transcription')).toHaveAttribute('label', 'en');
await expect(page.getByTestId('calls-recording-transcription')).toHaveAttribute('srclang', 'en');

// fetch transcription file and verify it has the expected content
const src = await page.getByTestId('calls-recording-transcription').getAttribute('src');
Expand Down
8 changes: 4 additions & 4 deletions server/bot_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ func (p *Plugin) handleBotPostTranscriptions(w http.ResponseWriter, r *http.Requ
// Updating the file to point to the existing call post solves this problem
// without requiring us to expose a dedicated API nor attach the file which
// we don't want to show.
if err := p.updateFileInfoPostID(info.FileIDs[0], info.PostID); err != nil {
if err := p.updateFileInfoPostID(info.Transcriptions[0].FileIDs[0], info.PostID); err != nil {
res.Err = "failed to update fileinfo post id: " + err.Error()
res.Code = http.StatusInternalServerError
}
Expand All @@ -343,7 +343,7 @@ func (p *Plugin) handleBotPostTranscriptions(w http.ResponseWriter, r *http.Requ
Message: postMsg,
Type: "custom_calls_transcription",
RootId: threadID,
FileIds: []string{info.FileIDs[1]},
FileIds: []string{info.Transcriptions[0].FileIDs[1]},
}
transcriptionPost.AddProp("call_post_id", info.PostID)
transcriptionPost.AddProp("transcription_id", info.JobID)
Expand All @@ -365,7 +365,7 @@ func (p *Plugin) handleBotPostTranscriptions(w http.ResponseWriter, r *http.Requ

var tm jobMetadata
tm.fromMap(transcriptions[info.JobID])
tm.FileID = info.FileIDs[0]
tm.FileID = info.Transcriptions[0].FileIDs[0]
tm.PostID = trPost.Id
transcriptions[info.JobID] = tm.toMap()
post.AddProp("transcriptions", transcriptions)
Expand All @@ -390,7 +390,7 @@ func (p *Plugin) handleBotPostTranscriptions(w http.ResponseWriter, r *http.Requ
p.LogError(res.Err, "trID", info.JobID)
return
}
recPost.AddProp("captions_file_id", tm.FileID)
recPost.AddProp("captions", info.Transcriptions.ToClientCaptions())
if _, appErr := p.API.UpdatePost(recPost); appErr != nil {
res.Err = "failed to update recording post: " + appErr.Error()
res.Code = http.StatusInternalServerError
Expand Down
71 changes: 63 additions & 8 deletions server/public/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,32 @@ type JobStatus struct {
Error string `json:"omitempty"`
}

type JobInfo struct {
PostID string
// We need aliases so that we can have different validation rules.
type RecordingJobInfo struct {
// Recording job ID
JobID string
// Call post ID
PostID string
// Recording files IDs
FileIDs []string
JobID string
}

// We need aliases so that we can have different validation rules.
type RecordingJobInfo JobInfo
type TranscribingJobInfo JobInfo
type Transcription struct {
Title string
Language string
FileIDs []string
}

type Transcriptions []Transcription

type TranscribingJobInfo struct {
// Transcribing job ID
JobID string
// Call post ID
PostID string
// Transcription metadata
Transcriptions Transcriptions
}

func (i RecordingJobInfo) IsValid() error {
if i.PostID == "" {
Expand All @@ -55,8 +72,14 @@ func (i TranscribingJobInfo) IsValid() error {
return fmt.Errorf("PostID should not be empty")
}

if len(i.FileIDs) != 2 {
return fmt.Errorf("invalid FileIDs length")
if len(i.Transcriptions) == 0 {
return fmt.Errorf("invalid Transcriptions length")
}

for _, t := range i.Transcriptions {
if err := t.IsValid(); err != nil {
return err
}
}

if i.JobID == "" {
Expand All @@ -65,3 +88,35 @@ func (i TranscribingJobInfo) IsValid() error {

return nil
}

func (t Transcription) IsValid() error {
if t.Language == "" {
return fmt.Errorf("Language should not be empty")
}

if len(t.FileIDs) < 2 {
return fmt.Errorf("invalid FileIDs length")
}

return nil
}

// We need to do some magic in order to go through the RCP layer without errors.
func (t Transcription) ToClientMap() map[string]any {
if t.Title == "" {
t.Title = t.Language
}
return map[string]any{
"title": t.Title,
"language": t.Language,
"file_id": t.FileIDs[0],
}
}

func (t Transcriptions) ToClientCaptions() []any {
captions := make([]any, len(t))
for i := range t {
captions[i] = t[i].ToClientMap()
}
return captions
}
162 changes: 150 additions & 12 deletions server/public/job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,42 +67,62 @@ func TestTranscribingJobInfoIsValid(t *testing.T) {
{
name: "missing JobID",
info: TranscribingJobInfo{
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c", "gyzdsttw9jbxfgm9b4otburw7o"},
PostID: "5khxhbp6t3r9tpxy6cxxqyrpge",
Transcriptions: []Transcription{
{
Language: "en",
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c", "gyzdsttw9jbxfgm9b4otburw7o"},
},
},
PostID: "5khxhbp6t3r9tpxy6cxxqyrpge",
},
err: "JobID should not be empty",
},
{
name: "missing FileID",
name: "missing Transcriptions",
info: TranscribingJobInfo{
JobID: "g719uqqnrjry5jof9cjqe5zhcy",
PostID: "5khxhbp6t3r9tpxy6cxxqyrpge",
},
err: "invalid FileIDs length",
err: "invalid Transcriptions length",
},
{
name: "not enough file ids",
info: TranscribingJobInfo{
JobID: "g719uqqnrjry5jof9cjqe5zhcy",
PostID: "5khxhbp6t3r9tpxy6cxxqyrpge",
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c"},
JobID: "g719uqqnrjry5jof9cjqe5zhcy",
PostID: "5khxhbp6t3r9tpxy6cxxqyrpge",
Transcriptions: []Transcription{
{
Language: "en",
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c"},
},
},
},
err: "invalid FileIDs length",
},
{
name: "missing PostID",
info: TranscribingJobInfo{
JobID: "g719uqqnrjry5jof9cjqe5zhcy",
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c", "gyzdsttw9jbxfgm9b4otburw7o"},
JobID: "g719uqqnrjry5jof9cjqe5zhcy",
Transcriptions: []Transcription{
{
Language: "en",
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c", "gyzdsttw9jbxfgm9b4otburw7o"},
},
},
},
err: "PostID should not be empty",
},
{
name: "valid",
info: TranscribingJobInfo{
JobID: "g719uqqnrjry5jof9cjqe5zhcy",
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c", "gyzdsttw9jbxfgm9b4otburw7o"},
PostID: "5khxhbp6t3r9tpxy6cxxqyrpge",
JobID: "g719uqqnrjry5jof9cjqe5zhcy",
PostID: "5khxhbp6t3r9tpxy6cxxqyrpge",
Transcriptions: []Transcription{
{
Language: "en",
FileIDs: []string{"srn9te5wnifg98ekrurcr7ty8c", "gyzdsttw9jbxfgm9b4otburw7o"},
},
},
},
},
}
Expand All @@ -118,3 +138,121 @@ func TestTranscribingJobInfoIsValid(t *testing.T) {
})
}
}

func TestTranscriptionIsValid(t *testing.T) {
tcs := []struct {
name string
tr Transcription
err string
}{
{
name: "missing language",
err: "Language should not be empty",
tr: Transcription{
Title: "title",
FileIDs: []string{
"fileA",
"fileB",
},
},
},
{
name: "invalid file ids",
err: "invalid FileIDs length",
tr: Transcription{
Title: "title",
Language: "it",
FileIDs: []string{
"fileA",
},
},
},
{
name: "valid",
tr: Transcription{
Title: "title",
Language: "it",
FileIDs: []string{
"fileA",
"fileB",
},
},
},
}

for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
err := tc.tr.IsValid()
if tc.err == "" {
require.NoError(t, err)
} else {
require.EqualError(t, err, tc.err)
}
})
}
}

func TestTranscriptionToClientMap(t *testing.T) {
t.Run("empty title", func(t *testing.T) {
tr := Transcription{
Language: "it",
FileIDs: []string{
"fileA",
"fileB",
},
}
require.Equal(t, map[string]any{
"title": "it",
"language": "it",
"file_id": "fileA",
}, tr.ToClientMap())
})

t.Run("with title", func(t *testing.T) {
tr := Transcription{
Title: "title",
Language: "it",
FileIDs: []string{
"fileA",
"fileB",
},
}
require.Equal(t, map[string]any{
"title": "title",
"language": "it",
"file_id": "fileA",
}, tr.ToClientMap())
})
}

func TestTranscriptionsToClientCaptions(t *testing.T) {
t.Run("empty", func(t *testing.T) {
var trs Transcriptions
require.Empty(t, trs.ToClientCaptions())
})

t.Run("not empty", func(t *testing.T) {
trs := Transcriptions{
Transcription{
Title: "title",
Language: "it",
FileIDs: []string{
"fileA",
"fileB",
},
},
Transcription{
Title: "title",
Language: "en",
FileIDs: []string{
"fileC",
"fileD",
},
},
}
require.Equal(t, []any{
trs[0].ToClientMap(),
trs[1].ToClientMap(),
}, trs.ToClientCaptions())
})
}
12 changes: 6 additions & 6 deletions standalone/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion standalone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"webpack-cli": "4.10.0"
},
"dependencies": {
"@calls/common": "github:mattermost/calls-common#4bca3651b2eb5d46fab9a29af000d21d9f56727c",
"@calls/common": "github:mattermost/calls-common#4a45138c02e3ce45d9e26f81c0f421a136ae0e59",
"@mattermost/compass-icons": "0.1.31",
"@msgpack/msgpack": "2.7.1",
"bootstrap": "3.4.1",
Expand Down
Loading

0 comments on commit f5dc9c4

Please sign in to comment.