Merge pull request #334 from Monadical-SAS/feat-api-speaker-reassignment

API to reassign speakers, and get topics with words
This commit is contained in:
2023-12-15 18:15:02 +01:00
committed by GitHub
29 changed files with 2648 additions and 13 deletions

View File

@@ -0,0 +1,29 @@
"""reviewed
Revision ID: b9348748bbbc
Revises: 125031f7cb78
Create Date: 2023-12-13 15:37:51.303970
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'b9348748bbbc'
down_revision: Union[str, None] = '125031f7cb78'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('transcript', sa.Column('reviewed', sa.Boolean(), server_default=sa.text('0'), nullable=False))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('transcript', 'reviewed')
# ### end Alembic commands ###

View File

@@ -17,6 +17,7 @@ from reflector.views.transcripts_audio import router as transcripts_audio_router
from reflector.views.transcripts_participants import (
router as transcripts_participants_router,
)
from reflector.views.transcripts_speaker import router as transcripts_speaker_router
from reflector.views.transcripts_upload import router as transcripts_upload_router
from reflector.views.transcripts_webrtc import router as transcripts_webrtc_router
from reflector.views.transcripts_websocket import router as transcripts_websocket_router
@@ -69,6 +70,7 @@ app.include_router(rtc_offer_router)
app.include_router(transcripts_router, prefix="/v1")
app.include_router(transcripts_audio_router, prefix="/v1")
app.include_router(transcripts_participants_router, prefix="/v1")
app.include_router(transcripts_speaker_router, prefix="/v1")
app.include_router(transcripts_upload_router, prefix="/v1")
app.include_router(transcripts_websocket_router, prefix="/v1")
app.include_router(transcripts_webrtc_router, prefix="/v1")

View File

@@ -12,6 +12,7 @@ from reflector.db import database, metadata
from reflector.processors.types import Word as ProcessorWord
from reflector.settings import settings
from reflector.storage import Storage
from sqlalchemy.sql import false
transcripts = sqlalchemy.Table(
"transcript",
@@ -30,6 +31,9 @@ transcripts = sqlalchemy.Table(
sqlalchemy.Column("participants", sqlalchemy.JSON),
sqlalchemy.Column("source_language", sqlalchemy.String, nullable=True),
sqlalchemy.Column("target_language", sqlalchemy.String, nullable=True),
sqlalchemy.Column(
"reviewed", sqlalchemy.Boolean, nullable=False, server_default=false()
),
sqlalchemy.Column(
"audio_location",
sqlalchemy.String,
@@ -138,6 +142,7 @@ class Transcript(BaseModel):
target_language: str = "en"
share_mode: Literal["private", "semi-private", "public"] = "private"
audio_location: str = "local"
reviewed: bool = False
def add_event(self, event: str, data: BaseModel) -> TranscriptEvent:
ev = TranscriptEvent(event=event, data=data.model_dump())
@@ -248,6 +253,23 @@ class Transcript(BaseModel):
url += f"?token={token}"
return url
def find_empty_speaker(self) -> int:
"""
Find an empty speaker seat
"""
speakers = set(
word.speaker
for topic in self.topics
for word in topic.words
if word.speaker is not None
)
i = 0
while True:
if i not in speakers:
return i
i += 1
raise Exception("No empty speaker found")
class TranscriptController:
async def get_all(
@@ -362,7 +384,7 @@ class TranscriptController:
await database.execute(query)
return transcript
async def update(self, transcript: Transcript, values: dict):
async def update(self, transcript: Transcript, values: dict, mutate=True):
"""
Update a transcript fields with key/values in values
"""
@@ -372,6 +394,7 @@ class TranscriptController:
.values(**values)
)
await database.execute(query)
if mutate:
for key, value in values.items():
setattr(transcript, key, value)
@@ -410,7 +433,11 @@ class TranscriptController:
Append an event to a transcript
"""
resp = transcript.add_event(event=event, data=data)
await self.update(transcript, {"events": transcript.events_dump()})
await self.update(
transcript,
{"events": transcript.events_dump()},
mutate=False,
)
return resp
async def upsert_topic(
@@ -422,7 +449,11 @@ class TranscriptController:
Append an event to a transcript
"""
transcript.upsert_topic(topic)
await self.update(transcript, {"topics": transcript.topics_dump()})
await self.update(
transcript,
{"topics": transcript.topics_dump()},
mutate=False,
)
async def move_mp3_to_storage(self, transcript: Transcript):
"""
@@ -450,7 +481,11 @@ class TranscriptController:
Add/update a participant to a transcript
"""
result = transcript.upsert_participant(participant)
await self.update(transcript, {"participants": transcript.participants_dump()})
await self.update(
transcript,
{"participants": transcript.participants_dump()},
mutate=False,
)
return result
async def delete_participant(
@@ -462,7 +497,11 @@ class TranscriptController:
Delete a participant from a transcript
"""
transcript.delete_participant(participant_id)
await self.update(transcript, {"participants": transcript.participants_dump()})
await self.update(
transcript,
{"participants": transcript.participants_dump()},
mutate=False,
)
transcripts_controller = TranscriptController()

View File

@@ -57,6 +57,7 @@ class Word(BaseModel):
class TranscriptSegment(BaseModel):
text: str
start: float
end: float
speaker: int = 0
@@ -127,6 +128,7 @@ class Transcript(BaseModel):
current_segment = TranscriptSegment(
text=word.text,
start=word.start,
end=word.end,
speaker=word.speaker,
)
continue
@@ -138,6 +140,7 @@ class Transcript(BaseModel):
current_segment = TranscriptSegment(
text=word.text,
start=word.start,
end=word.end,
speaker=word.speaker,
)
continue
@@ -145,6 +148,7 @@ class Transcript(BaseModel):
# if the word is the end of a sentence, and we have enough content,
# add the word to the current segment and push it
current_segment.text += word.text
current_segment.end = word.end
have_punc = PUNC_RE.search(word.text)
if have_punc and (len(current_segment.text) > MAX_SEGMENT_LENGTH):

View File

@@ -13,6 +13,7 @@ from reflector.db.transcripts import (
transcripts_controller,
)
from reflector.processors.types import Transcript as ProcessorTranscript
from reflector.processors.types import Word
from reflector.settings import settings
router = APIRouter()
@@ -49,6 +50,7 @@ class GetTranscript(BaseModel):
source_language: str | None
target_language: str | None
participants: list[TranscriptParticipant] | None
reviewed: bool
class CreateTranscript(BaseModel):
@@ -65,6 +67,7 @@ class UpdateTranscript(BaseModel):
long_summary: Optional[str] = Field(None)
share_mode: Optional[Literal["public", "semi-private", "private"]] = Field(None)
participants: Optional[list[TranscriptParticipant]] = Field(None)
reviewed: Optional[bool] = Field(None)
class DeletionStatus(BaseModel):
@@ -121,6 +124,7 @@ class GetTranscriptTopic(BaseModel):
title: str
summary: str
timestamp: float
duration: float | None
transcript: str
segments: list[GetTranscriptSegmentTopic] = []
@@ -130,6 +134,7 @@ class GetTranscriptTopic(BaseModel):
# In previous version, words were missing
# Just output a segment with speaker 0
text = topic.transcript
duration = None
segments = [
GetTranscriptSegmentTopic(
text=topic.transcript,
@@ -141,6 +146,7 @@ class GetTranscriptTopic(BaseModel):
# New versions include words
transcript = ProcessorTranscript(words=topic.words)
text = transcript.text
duration = transcript.duration
segments = [
GetTranscriptSegmentTopic(
text=segment.text,
@@ -156,9 +162,59 @@ class GetTranscriptTopic(BaseModel):
timestamp=topic.timestamp,
transcript=text,
segments=segments,
duration=duration,
)
class GetTranscriptTopicWithWords(GetTranscriptTopic):
words: list[Word] = []
@classmethod
def from_transcript_topic(cls, topic: TranscriptTopic):
instance = super().from_transcript_topic(topic)
if topic.words:
instance.words = topic.words
return instance
class SpeakerWords(BaseModel):
speaker: int
words: list[Word]
class GetTranscriptTopicWithWordsPerSpeaker(GetTranscriptTopic):
words_per_speaker: list[SpeakerWords] = []
@classmethod
def from_transcript_topic(cls, topic: TranscriptTopic):
instance = super().from_transcript_topic(topic)
if topic.words:
words_per_speakers = []
# group words by speaker
words = []
for word in topic.words:
if words and words[-1].speaker != word.speaker:
words_per_speakers.append(
SpeakerWords(
speaker=words[-1].speaker,
words=words,
)
)
words = []
words.append(word)
if words:
words_per_speakers.append(
SpeakerWords(
speaker=words[-1].speaker,
words=words,
)
)
instance.words_per_speaker = words_per_speakers
return instance
@router.get("/transcripts/{transcript_id}", response_model=GetTranscript)
async def transcript_get(
transcript_id: str,
@@ -215,3 +271,46 @@ async def transcript_get_topics(
return [
GetTranscriptTopic.from_transcript_topic(topic) for topic in transcript.topics
]
@router.get(
"/transcripts/{transcript_id}/topics/with-words",
response_model=list[GetTranscriptTopicWithWords],
)
async def transcript_get_topics_with_words(
transcript_id: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
transcript = await transcripts_controller.get_by_id_for_http(
transcript_id, user_id=user_id
)
# convert to GetTranscriptTopicWithWords
return [
GetTranscriptTopicWithWords.from_transcript_topic(topic)
for topic in transcript.topics
]
@router.get(
"/transcripts/{transcript_id}/topics/{topic_id}/words-per-speaker",
response_model=GetTranscriptTopicWithWordsPerSpeaker,
)
async def transcript_get_topics_with_words_per_speaker(
transcript_id: str,
topic_id: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
transcript = await transcripts_controller.get_by_id_for_http(
transcript_id, user_id=user_id
)
# get the topic from the transcript
topic = next((t for t in transcript.topics if t.id == topic_id), None)
if not topic:
raise HTTPException(status_code=404, detail="Topic not found")
# convert to GetTranscriptTopicWithWordsPerSpeaker
return GetTranscriptTopicWithWordsPerSpeaker.from_transcript_topic(topic)

View File

@@ -59,6 +59,7 @@ async def transcript_add_participant(
)
# ensure the speaker is unique
if participant.speaker is not None:
for p in transcript.participants:
if p.speaker == participant.speaker:
raise HTTPException(

View File

@@ -0,0 +1,170 @@
"""
Reassign speakers in a transcript
=================================
"""
from typing import Annotated, Optional
import reflector.auth as auth
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from reflector.db.transcripts import transcripts_controller
router = APIRouter()
class SpeakerAssignment(BaseModel):
speaker: Optional[int] = Field(None, ge=0)
participant: Optional[str] = Field(None)
timestamp_from: float
timestamp_to: float
class SpeakerAssignmentStatus(BaseModel):
status: str
class SpeakerMerge(BaseModel):
speaker_from: int
speaker_to: int
@router.patch("/transcripts/{transcript_id}/speaker/assign")
async def transcript_assign_speaker(
transcript_id: str,
assignment: SpeakerAssignment,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
) -> SpeakerAssignmentStatus:
user_id = user["sub"] if user else None
transcript = await transcripts_controller.get_by_id_for_http(
transcript_id, user_id=user_id
)
if not transcript:
raise HTTPException(status_code=404, detail="Transcript not found")
if assignment.speaker is None and assignment.participant is None:
raise HTTPException(
status_code=400,
detail="Either speaker or participant must be provided",
)
if assignment.speaker is not None and assignment.participant is not None:
raise HTTPException(
status_code=400,
detail="Only one of speaker or participant must be provided",
)
# if it's a participant, search for it
if assignment.speaker is not None:
speaker = assignment.speaker
elif assignment.participant is not None:
participant = next(
(
participant
for participant in transcript.participants
if participant.id == assignment.participant
),
None,
)
if not participant:
raise HTTPException(
status_code=404,
detail="Participant not found",
)
# if the participant does not have a speaker, create one
if participant.speaker is None:
participant.speaker = transcript.find_empty_speaker()
await transcripts_controller.upsert_participant(transcript, participant)
speaker = participant.speaker
# reassign speakers from words in the transcript
ts_from = assignment.timestamp_from
ts_to = assignment.timestamp_to
changed_topics = []
for topic in transcript.topics:
changed = False
for word in topic.words:
if ts_from <= word.start <= ts_to:
word.speaker = speaker
changed = True
if changed:
changed_topics.append(topic)
# batch changes
for topic in changed_topics:
transcript.upsert_topic(topic)
await transcripts_controller.update(
transcript,
{
"topics": transcript.topics_dump(),
},
)
return SpeakerAssignmentStatus(status="ok")
@router.patch("/transcripts/{transcript_id}/speaker/merge")
async def transcript_merge_speaker(
transcript_id: str,
merge: SpeakerMerge,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
) -> SpeakerAssignmentStatus:
user_id = user["sub"] if user else None
transcript = await transcripts_controller.get_by_id_for_http(
transcript_id, user_id=user_id
)
if not transcript:
raise HTTPException(status_code=404, detail="Transcript not found")
# ensure both speaker are not assigned to the 2 differents participants
participant_from = next(
(
participant
for participant in transcript.participants
if participant.speaker == merge.speaker_from
),
None,
)
participant_to = next(
(
participant
for participant in transcript.participants
if participant.speaker == merge.speaker_to
),
None,
)
if participant_from and participant_to:
raise HTTPException(
status_code=400,
detail="Both speakers are assigned to participants",
)
# reassign speakers from words in the transcript
speaker_from = merge.speaker_from
speaker_to = merge.speaker_to
changed_topics = []
for topic in transcript.topics:
changed = False
for word in topic.words:
if word.speaker == speaker_from:
word.speaker = speaker_to
changed = True
if changed:
changed_topics.append(topic)
# batch changes
for topic in changed_topics:
transcript.upsert_topic(topic)
await transcripts_controller.update(
transcript,
{
"topics": transcript.topics_dump(),
},
)
return SpeakerAssignmentStatus(status="ok")

View File

@@ -177,3 +177,64 @@ def fake_mp3_upload():
) as mock_move:
mock_move.return_value = True
yield
@pytest.fixture
async def fake_transcript_with_topics(tmpdir):
from reflector.settings import settings
from reflector.app import app
from reflector.views.transcripts import transcripts_controller
from reflector.db.transcripts import TranscriptTopic
from reflector.processors.types import Word
from pathlib import Path
from httpx import AsyncClient
import shutil
settings.DATA_DIR = Path(tmpdir)
# create a transcript
ac = AsyncClient(app=app, base_url="http://test/v1")
response = await ac.post("/transcripts", json={"name": "Test audio download"})
assert response.status_code == 200
tid = response.json()["id"]
transcript = await transcripts_controller.get_by_id(tid)
assert transcript is not None
await transcripts_controller.update(transcript, {"status": "finished"})
# manually copy a file at the expected location
audio_filename = transcript.audio_mp3_filename
path = Path(__file__).parent / "records" / "test_mathieu_hello.mp3"
audio_filename.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(path, audio_filename)
# create some topics
await transcripts_controller.upsert_topic(
transcript,
TranscriptTopic(
title="Topic 1",
summary="Topic 1 summary",
timestamp=0,
transcript="Hello world",
words=[
Word(text="Hello", start=0, end=1, speaker=0),
Word(text="world", start=1, end=2, speaker=0),
],
),
)
await transcripts_controller.upsert_topic(
transcript,
TranscriptTopic(
title="Topic 2",
summary="Topic 2 summary",
timestamp=2,
transcript="Hello world",
words=[
Word(text="Hello", start=2, end=3, speaker=0),
Word(text="world", start=3, end=4, speaker=0),
],
),
)
yield transcript

View File

@@ -196,3 +196,29 @@ async def test_transcript_delete():
response = await ac.get(f"/transcripts/{tid}")
assert response.status_code == 404
@pytest.mark.asyncio
async def test_transcript_mark_reviewed():
from reflector.app import app
async with AsyncClient(app=app, base_url="http://test/v1") as ac:
response = await ac.post("/transcripts", json={"name": "test"})
assert response.status_code == 200
assert response.json()["name"] == "test"
assert response.json()["reviewed"] is False
tid = response.json()["id"]
response = await ac.get(f"/transcripts/{tid}")
assert response.status_code == 200
assert response.json()["name"] == "test"
assert response.json()["reviewed"] is False
response = await ac.patch(f"/transcripts/{tid}", json={"reviewed": True})
assert response.status_code == 200
assert response.json()["reviewed"] is True
response = await ac.get(f"/transcripts/{tid}")
assert response.status_code == 200
assert response.json()["reviewed"] is True

View File

@@ -0,0 +1,401 @@
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_transcript_reassign_speaker(fake_transcript_with_topics):
from reflector.app import app
transcript_id = fake_transcript_with_topics.id
async with AsyncClient(app=app, base_url="http://test/v1") as ac:
# check the transcript exists
response = await ac.get(f"/transcripts/{transcript_id}")
assert response.status_code == 200
# check initial topics of the transcript
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 0
assert topics[0]["words"][1]["speaker"] == 0
assert topics[1]["words"][0]["speaker"] == 0
assert topics[1]["words"][1]["speaker"] == 0
# check through segments
assert len(topics[0]["segments"]) == 1
assert topics[0]["segments"][0]["speaker"] == 0
assert len(topics[1]["segments"]) == 1
assert topics[1]["segments"][0]["speaker"] == 0
# reassign speaker
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"speaker": 1,
"timestamp_from": 0,
"timestamp_to": 1,
},
)
assert response.status_code == 200
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 1
assert topics[0]["words"][1]["speaker"] == 1
assert topics[1]["words"][0]["speaker"] == 0
assert topics[1]["words"][1]["speaker"] == 0
# check segments
assert len(topics[0]["segments"]) == 1
assert topics[0]["segments"][0]["speaker"] == 1
assert len(topics[1]["segments"]) == 1
assert topics[1]["segments"][0]["speaker"] == 0
# reassign speaker, middle of 2 topics
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"speaker": 2,
"timestamp_from": 1,
"timestamp_to": 2.5,
},
)
assert response.status_code == 200
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 1
assert topics[0]["words"][1]["speaker"] == 2
assert topics[1]["words"][0]["speaker"] == 2
assert topics[1]["words"][1]["speaker"] == 0
# check segments
assert len(topics[0]["segments"]) == 2
assert topics[0]["segments"][0]["speaker"] == 1
assert topics[0]["segments"][1]["speaker"] == 2
assert len(topics[1]["segments"]) == 2
assert topics[1]["segments"][0]["speaker"] == 2
assert topics[1]["segments"][1]["speaker"] == 0
# reassign speaker, everything
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"speaker": 4,
"timestamp_from": 0,
"timestamp_to": 100,
},
)
assert response.status_code == 200
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 4
assert topics[0]["words"][1]["speaker"] == 4
assert topics[1]["words"][0]["speaker"] == 4
assert topics[1]["words"][1]["speaker"] == 4
# check segments
assert len(topics[0]["segments"]) == 1
assert topics[0]["segments"][0]["speaker"] == 4
assert len(topics[1]["segments"]) == 1
assert topics[1]["segments"][0]["speaker"] == 4
@pytest.mark.asyncio
async def test_transcript_merge_speaker(fake_transcript_with_topics):
from reflector.app import app
transcript_id = fake_transcript_with_topics.id
async with AsyncClient(app=app, base_url="http://test/v1") as ac:
# check the transcript exists
response = await ac.get(f"/transcripts/{transcript_id}")
assert response.status_code == 200
# check initial topics of the transcript
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 0
assert topics[0]["words"][1]["speaker"] == 0
assert topics[1]["words"][0]["speaker"] == 0
assert topics[1]["words"][1]["speaker"] == 0
# reassign speaker
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"speaker": 1,
"timestamp_from": 0,
"timestamp_to": 1,
},
)
assert response.status_code == 200
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 1
assert topics[0]["words"][1]["speaker"] == 1
assert topics[1]["words"][0]["speaker"] == 0
assert topics[1]["words"][1]["speaker"] == 0
# merge speakers
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/merge",
json={
"speaker_from": 1,
"speaker_to": 0,
},
)
assert response.status_code == 200
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 0
assert topics[0]["words"][1]["speaker"] == 0
assert topics[1]["words"][0]["speaker"] == 0
assert topics[1]["words"][1]["speaker"] == 0
@pytest.mark.asyncio
async def test_transcript_reassign_with_participant(fake_transcript_with_topics):
from reflector.app import app
transcript_id = fake_transcript_with_topics.id
async with AsyncClient(app=app, base_url="http://test/v1") as ac:
# check the transcript exists
response = await ac.get(f"/transcripts/{transcript_id}")
assert response.status_code == 200
transcript = response.json()
assert len(transcript["participants"]) == 0
# create 2 participants
response = await ac.post(
f"/transcripts/{transcript_id}/participants",
json={
"name": "Participant 1",
},
)
assert response.status_code == 200
participant1_id = response.json()["id"]
response = await ac.post(
f"/transcripts/{transcript_id}/participants",
json={
"name": "Participant 2",
},
)
assert response.status_code == 200
participant2_id = response.json()["id"]
# check participants speakers
response = await ac.get(f"/transcripts/{transcript_id}/participants")
assert response.status_code == 200
participants = response.json()
assert len(participants) == 2
assert participants[0]["name"] == "Participant 1"
assert participants[0]["speaker"] is None
assert participants[1]["name"] == "Participant 2"
assert participants[1]["speaker"] is None
# check initial topics of the transcript
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 0
assert topics[0]["words"][1]["speaker"] == 0
assert topics[1]["words"][0]["speaker"] == 0
assert topics[1]["words"][1]["speaker"] == 0
# check through segments
assert len(topics[0]["segments"]) == 1
assert topics[0]["segments"][0]["speaker"] == 0
assert len(topics[1]["segments"]) == 1
assert topics[1]["segments"][0]["speaker"] == 0
# reassign speaker from a participant
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"participant": participant1_id,
"timestamp_from": 0,
"timestamp_to": 1,
},
)
assert response.status_code == 200
# check participants if speaker has been assigned
# first participant should have 1, because it's not used yet.
response = await ac.get(f"/transcripts/{transcript_id}/participants")
assert response.status_code == 200
participants = response.json()
assert len(participants) == 2
assert participants[0]["name"] == "Participant 1"
assert participants[0]["speaker"] == 1
assert participants[1]["name"] == "Participant 2"
assert participants[1]["speaker"] is None
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 1
assert topics[0]["words"][1]["speaker"] == 1
assert topics[1]["words"][0]["speaker"] == 0
assert topics[1]["words"][1]["speaker"] == 0
# check segments
assert len(topics[0]["segments"]) == 1
assert topics[0]["segments"][0]["speaker"] == 1
assert len(topics[1]["segments"]) == 1
assert topics[1]["segments"][0]["speaker"] == 0
# reassign participant, middle of 2 topics
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"participant": participant2_id,
"timestamp_from": 1,
"timestamp_to": 2.5,
},
)
assert response.status_code == 200
# check participants if speaker has been assigned
# first participant should have 1, because it's not used yet.
response = await ac.get(f"/transcripts/{transcript_id}/participants")
assert response.status_code == 200
participants = response.json()
assert len(participants) == 2
assert participants[0]["name"] == "Participant 1"
assert participants[0]["speaker"] == 1
assert participants[1]["name"] == "Participant 2"
assert participants[1]["speaker"] == 2
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 1
assert topics[0]["words"][1]["speaker"] == 2
assert topics[1]["words"][0]["speaker"] == 2
assert topics[1]["words"][1]["speaker"] == 0
# check segments
assert len(topics[0]["segments"]) == 2
assert topics[0]["segments"][0]["speaker"] == 1
assert topics[0]["segments"][1]["speaker"] == 2
assert len(topics[1]["segments"]) == 2
assert topics[1]["segments"][0]["speaker"] == 2
assert topics[1]["segments"][1]["speaker"] == 0
# reassign speaker, everything
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"participant": participant1_id,
"timestamp_from": 0,
"timestamp_to": 100,
},
)
assert response.status_code == 200
# check topics again
response = await ac.get(f"/transcripts/{transcript_id}/topics/with-words")
assert response.status_code == 200
topics = response.json()
assert len(topics) == 2
# check through words
assert topics[0]["words"][0]["speaker"] == 1
assert topics[0]["words"][1]["speaker"] == 1
assert topics[1]["words"][0]["speaker"] == 1
assert topics[1]["words"][1]["speaker"] == 1
# check segments
assert len(topics[0]["segments"]) == 1
assert topics[0]["segments"][0]["speaker"] == 1
assert len(topics[1]["segments"]) == 1
assert topics[1]["segments"][0]["speaker"] == 1
@pytest.mark.asyncio
async def test_transcript_reassign_edge_cases(fake_transcript_with_topics):
from reflector.app import app
transcript_id = fake_transcript_with_topics.id
async with AsyncClient(app=app, base_url="http://test/v1") as ac:
# check the transcript exists
response = await ac.get(f"/transcripts/{transcript_id}")
assert response.status_code == 200
transcript = response.json()
assert len(transcript["participants"]) == 0
# try reassign without any participant_id or speaker
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"timestamp_from": 0,
"timestamp_to": 1,
},
)
assert response.status_code == 400
# try reassing with both participant_id and speaker
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"participant": "123",
"speaker": 1,
"timestamp_from": 0,
"timestamp_to": 1,
},
)
assert response.status_code == 400
# try reassing with non-existing participant_id
response = await ac.patch(
f"/transcripts/{transcript_id}/speaker/assign",
json={
"participant": "123",
"timestamp_from": 0,
"timestamp_to": 1,
},
)
assert response.status_code == 404

View File

@@ -0,0 +1,26 @@
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_transcript_topics(fake_transcript_with_topics):
from reflector.app import app
transcript_id = fake_transcript_with_topics.id
async with AsyncClient(app=app, base_url="http://test/v1") as ac:
# check the transcript exists
response = await ac.get(f"/transcripts/{transcript_id}/topics")
assert response.status_code == 200
assert len(response.json()) == 2
topic_id = response.json()[0]["id"]
# get words per speakers
response = await ac.get(
f"/transcripts/{transcript_id}/topics/{topic_id}/words-per-speaker"
)
assert response.status_code == 200
data = response.json()
assert len(data["words_per_speaker"]) == 1
assert data["words_per_speaker"][0]["speaker"] == 0
assert len(data["words_per_speaker"][0]["words"]) == 2

View File

@@ -62,6 +62,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "1",
timestamp: 10,
duration: 10,
summary: "This is test topic 1",
title: "Topic 1: Introduction to Quantum Mechanics",
transcript:
@@ -103,6 +104,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "2",
timestamp: 20,
duration: 10,
summary: "This is test topic 2",
title: "Topic 2: Machine Learning Algorithms",
transcript:
@@ -123,6 +125,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "3",
timestamp: 30,
duration: 10,
summary: "This is test topic 3",
title: "Topic 3: Mental Health Awareness",
transcript: "Ways to improve mental health and reduce stigma.",
@@ -142,6 +145,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "4",
timestamp: 40,
duration: 10,
summary: "This is test topic 4",
title: "Topic 4: Basics of Productivity",
transcript: "Tips and tricks to increase daily productivity.",
@@ -161,6 +165,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "5",
timestamp: 50,
duration: 10,
summary: "This is test topic 5",
title: "Topic 5: Future of Aviation",
transcript:
@@ -190,6 +195,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "1",
timestamp: 10,
duration: 10,
summary: "This is test topic 1",
title:
"Topic 1: Introduction to Quantum Mechanics, a brief overview of quantum mechanics and its principles.",
@@ -211,6 +217,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "2",
timestamp: 20,
duration: 10,
summary: "This is test topic 2",
title:
"Topic 2: Machine Learning Algorithms, understanding the different types of machine learning algorithms.",
@@ -232,6 +239,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "3",
timestamp: 30,
duration: 10,
summary: "This is test topic 3",
title:
"Topic 3: Mental Health Awareness, ways to improve mental health and reduce stigma.",
@@ -252,6 +260,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "4",
timestamp: 40,
duration: 10,
summary: "This is test topic 4",
title:
"Topic 4: Basics of Productivity, tips and tricks to increase daily productivity.",
@@ -272,6 +281,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{
id: "5",
timestamp: 50,
duration: 10,
summary: "This is test topic 5",
title:
"Topic 5: Future of Aviation, exploring the advancements and possibilities in aviation.",

View File

@@ -2,16 +2,27 @@ apis/DefaultApi.ts
apis/index.ts
index.ts
models/AudioWaveform.ts
models/CreateParticipant.ts
models/CreateTranscript.ts
models/DeletionStatus.ts
models/GetTranscript.ts
models/GetTranscriptSegmentTopic.ts
models/GetTranscriptTopic.ts
models/GetTranscriptTopicWithWords.ts
models/GetTranscriptTopicWithWordsPerSpeaker.ts
models/HTTPValidationError.ts
models/PageGetTranscript.ts
models/Participant.ts
models/RtcOffer.ts
models/SpeakerAssignment.ts
models/SpeakerAssignmentStatus.ts
models/SpeakerMerge.ts
models/SpeakerWords.ts
models/TranscriptParticipant.ts
models/UpdateParticipant.ts
models/UpdateTranscript.ts
models/UserInfo.ts
models/ValidationError.ts
models/Word.ts
models/index.ts
runtime.ts

View File

@@ -15,37 +15,73 @@
import * as runtime from "../runtime";
import type {
AudioWaveform,
CreateParticipant,
CreateTranscript,
DeletionStatus,
GetTranscript,
GetTranscriptTopicWithWordsPerSpeaker,
HTTPValidationError,
PageGetTranscript,
Participant,
RtcOffer,
SpeakerAssignment,
SpeakerAssignmentStatus,
SpeakerMerge,
UpdateParticipant,
UpdateTranscript,
} from "../models";
import {
AudioWaveformFromJSON,
AudioWaveformToJSON,
CreateParticipantFromJSON,
CreateParticipantToJSON,
CreateTranscriptFromJSON,
CreateTranscriptToJSON,
DeletionStatusFromJSON,
DeletionStatusToJSON,
GetTranscriptFromJSON,
GetTranscriptToJSON,
GetTranscriptTopicWithWordsPerSpeakerFromJSON,
GetTranscriptTopicWithWordsPerSpeakerToJSON,
HTTPValidationErrorFromJSON,
HTTPValidationErrorToJSON,
PageGetTranscriptFromJSON,
PageGetTranscriptToJSON,
ParticipantFromJSON,
ParticipantToJSON,
RtcOfferFromJSON,
RtcOfferToJSON,
SpeakerAssignmentFromJSON,
SpeakerAssignmentToJSON,
SpeakerAssignmentStatusFromJSON,
SpeakerAssignmentStatusToJSON,
SpeakerMergeFromJSON,
SpeakerMergeToJSON,
UpdateParticipantFromJSON,
UpdateParticipantToJSON,
UpdateTranscriptFromJSON,
UpdateTranscriptToJSON,
} from "../models";
export interface V1TranscriptAddParticipantRequest {
transcriptId: any;
createParticipant: CreateParticipant;
}
export interface V1TranscriptAssignSpeakerRequest {
transcriptId: any;
speakerAssignment: SpeakerAssignment;
}
export interface V1TranscriptDeleteRequest {
transcriptId: any;
}
export interface V1TranscriptDeleteParticipantRequest {
transcriptId: any;
participantId: any;
}
export interface V1TranscriptGetRequest {
transcriptId: any;
}
@@ -59,14 +95,37 @@ export interface V1TranscriptGetAudioWaveformRequest {
transcriptId: any;
}
export interface V1TranscriptGetParticipantRequest {
transcriptId: any;
participantId: any;
}
export interface V1TranscriptGetParticipantsRequest {
transcriptId: any;
}
export interface V1TranscriptGetTopicsRequest {
transcriptId: any;
}
export interface V1TranscriptGetTopicsWithWordsRequest {
transcriptId: any;
}
export interface V1TranscriptGetTopicsWithWordsPerSpeakerRequest {
transcriptId: any;
topicId: any;
}
export interface V1TranscriptGetWebsocketEventsRequest {
transcriptId: any;
}
export interface V1TranscriptMergeSpeakerRequest {
transcriptId: any;
speakerMerge: SpeakerMerge;
}
export interface V1TranscriptRecordWebrtcRequest {
transcriptId: any;
rtcOffer: RtcOffer;
@@ -77,6 +136,12 @@ export interface V1TranscriptUpdateRequest {
updateTranscript: UpdateTranscript;
}
export interface V1TranscriptUpdateParticipantRequest {
transcriptId: any;
participantId: any;
updateParticipant: UpdateParticipant;
}
export interface V1TranscriptsCreateRequest {
createTranscript: CreateTranscript;
}
@@ -129,6 +194,154 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value();
}
/**
* Transcript Add Participant
*/
async v1TranscriptAddParticipantRaw(
requestParameters: V1TranscriptAddParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<Participant>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptAddParticipant.",
);
}
if (
requestParameters.createParticipant === null ||
requestParameters.createParticipant === undefined
) {
throw new runtime.RequiredError(
"createParticipant",
"Required parameter requestParameters.createParticipant was null or undefined when calling v1TranscriptAddParticipant.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters["Content-Type"] = "application/json";
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/participants`.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
),
method: "POST",
headers: headerParameters,
query: queryParameters,
body: CreateParticipantToJSON(requestParameters.createParticipant),
},
initOverrides,
);
return new runtime.JSONApiResponse(response, (jsonValue) =>
ParticipantFromJSON(jsonValue),
);
}
/**
* Transcript Add Participant
*/
async v1TranscriptAddParticipant(
requestParameters: V1TranscriptAddParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<Participant> {
const response = await this.v1TranscriptAddParticipantRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Assign Speaker
*/
async v1TranscriptAssignSpeakerRaw(
requestParameters: V1TranscriptAssignSpeakerRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<SpeakerAssignmentStatus>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptAssignSpeaker.",
);
}
if (
requestParameters.speakerAssignment === null ||
requestParameters.speakerAssignment === undefined
) {
throw new runtime.RequiredError(
"speakerAssignment",
"Required parameter requestParameters.speakerAssignment was null or undefined when calling v1TranscriptAssignSpeaker.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters["Content-Type"] = "application/json";
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/speaker/assign`.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
),
method: "PATCH",
headers: headerParameters,
query: queryParameters,
body: SpeakerAssignmentToJSON(requestParameters.speakerAssignment),
},
initOverrides,
);
return new runtime.JSONApiResponse(response, (jsonValue) =>
SpeakerAssignmentStatusFromJSON(jsonValue),
);
}
/**
* Transcript Assign Speaker
*/
async v1TranscriptAssignSpeaker(
requestParameters: V1TranscriptAssignSpeakerRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<SpeakerAssignmentStatus> {
const response = await this.v1TranscriptAssignSpeakerRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Delete
*/
@@ -190,6 +403,82 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value();
}
/**
* Transcript Delete Participant
*/
async v1TranscriptDeleteParticipantRaw(
requestParameters: V1TranscriptDeleteParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<DeletionStatus>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptDeleteParticipant.",
);
}
if (
requestParameters.participantId === null ||
requestParameters.participantId === undefined
) {
throw new runtime.RequiredError(
"participantId",
"Required parameter requestParameters.participantId was null or undefined when calling v1TranscriptDeleteParticipant.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/participants/{participant_id}`
.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
)
.replace(
`{${"participant_id"}}`,
encodeURIComponent(String(requestParameters.participantId)),
),
method: "DELETE",
headers: headerParameters,
query: queryParameters,
},
initOverrides,
);
return new runtime.JSONApiResponse(response, (jsonValue) =>
DeletionStatusFromJSON(jsonValue),
);
}
/**
* Transcript Delete Participant
*/
async v1TranscriptDeleteParticipant(
requestParameters: V1TranscriptDeleteParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<DeletionStatus> {
const response = await this.v1TranscriptDeleteParticipantRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Get
*/
@@ -379,6 +668,145 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value();
}
/**
* Transcript Get Participant
*/
async v1TranscriptGetParticipantRaw(
requestParameters: V1TranscriptGetParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<Participant>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptGetParticipant.",
);
}
if (
requestParameters.participantId === null ||
requestParameters.participantId === undefined
) {
throw new runtime.RequiredError(
"participantId",
"Required parameter requestParameters.participantId was null or undefined when calling v1TranscriptGetParticipant.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/participants/{participant_id}`
.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
)
.replace(
`{${"participant_id"}}`,
encodeURIComponent(String(requestParameters.participantId)),
),
method: "GET",
headers: headerParameters,
query: queryParameters,
},
initOverrides,
);
return new runtime.JSONApiResponse(response, (jsonValue) =>
ParticipantFromJSON(jsonValue),
);
}
/**
* Transcript Get Participant
*/
async v1TranscriptGetParticipant(
requestParameters: V1TranscriptGetParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<Participant> {
const response = await this.v1TranscriptGetParticipantRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Get Participants
*/
async v1TranscriptGetParticipantsRaw(
requestParameters: V1TranscriptGetParticipantsRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<any>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptGetParticipants.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/participants`.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
),
method: "GET",
headers: headerParameters,
query: queryParameters,
},
initOverrides,
);
if (this.isJsonMime(response.headers.get("content-type"))) {
return new runtime.JSONApiResponse<any>(response);
} else {
return new runtime.TextApiResponse(response) as any;
}
}
/**
* Transcript Get Participants
*/
async v1TranscriptGetParticipants(
requestParameters: V1TranscriptGetParticipantsRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<any> {
const response = await this.v1TranscriptGetParticipantsRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Get Topics
*/
@@ -442,6 +870,145 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value();
}
/**
* Transcript Get Topics With Words
*/
async v1TranscriptGetTopicsWithWordsRaw(
requestParameters: V1TranscriptGetTopicsWithWordsRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<any>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptGetTopicsWithWords.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/topics/with-words`.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
),
method: "GET",
headers: headerParameters,
query: queryParameters,
},
initOverrides,
);
if (this.isJsonMime(response.headers.get("content-type"))) {
return new runtime.JSONApiResponse<any>(response);
} else {
return new runtime.TextApiResponse(response) as any;
}
}
/**
* Transcript Get Topics With Words
*/
async v1TranscriptGetTopicsWithWords(
requestParameters: V1TranscriptGetTopicsWithWordsRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<any> {
const response = await this.v1TranscriptGetTopicsWithWordsRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Get Topics With Words Per Speaker
*/
async v1TranscriptGetTopicsWithWordsPerSpeakerRaw(
requestParameters: V1TranscriptGetTopicsWithWordsPerSpeakerRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<GetTranscriptTopicWithWordsPerSpeaker>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptGetTopicsWithWordsPerSpeaker.",
);
}
if (
requestParameters.topicId === null ||
requestParameters.topicId === undefined
) {
throw new runtime.RequiredError(
"topicId",
"Required parameter requestParameters.topicId was null or undefined when calling v1TranscriptGetTopicsWithWordsPerSpeaker.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/topics/{topic_id}/words-per-speaker`
.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
)
.replace(
`{${"topic_id"}}`,
encodeURIComponent(String(requestParameters.topicId)),
),
method: "GET",
headers: headerParameters,
query: queryParameters,
},
initOverrides,
);
return new runtime.JSONApiResponse(response, (jsonValue) =>
GetTranscriptTopicWithWordsPerSpeakerFromJSON(jsonValue),
);
}
/**
* Transcript Get Topics With Words Per Speaker
*/
async v1TranscriptGetTopicsWithWordsPerSpeaker(
requestParameters: V1TranscriptGetTopicsWithWordsPerSpeakerRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<GetTranscriptTopicWithWordsPerSpeaker> {
const response = await this.v1TranscriptGetTopicsWithWordsPerSpeakerRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Get Websocket Events
*/
@@ -497,6 +1064,80 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value();
}
/**
* Transcript Merge Speaker
*/
async v1TranscriptMergeSpeakerRaw(
requestParameters: V1TranscriptMergeSpeakerRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<SpeakerAssignmentStatus>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptMergeSpeaker.",
);
}
if (
requestParameters.speakerMerge === null ||
requestParameters.speakerMerge === undefined
) {
throw new runtime.RequiredError(
"speakerMerge",
"Required parameter requestParameters.speakerMerge was null or undefined when calling v1TranscriptMergeSpeaker.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters["Content-Type"] = "application/json";
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/speaker/merge`.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
),
method: "PATCH",
headers: headerParameters,
query: queryParameters,
body: SpeakerMergeToJSON(requestParameters.speakerMerge),
},
initOverrides,
);
return new runtime.JSONApiResponse(response, (jsonValue) =>
SpeakerAssignmentStatusFromJSON(jsonValue),
);
}
/**
* Transcript Merge Speaker
*/
async v1TranscriptMergeSpeaker(
requestParameters: V1TranscriptMergeSpeakerRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<SpeakerAssignmentStatus> {
const response = await this.v1TranscriptMergeSpeakerRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcript Record Webrtc
*/
@@ -647,6 +1288,95 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value();
}
/**
* Transcript Update Participant
*/
async v1TranscriptUpdateParticipantRaw(
requestParameters: V1TranscriptUpdateParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<runtime.ApiResponse<Participant>> {
if (
requestParameters.transcriptId === null ||
requestParameters.transcriptId === undefined
) {
throw new runtime.RequiredError(
"transcriptId",
"Required parameter requestParameters.transcriptId was null or undefined when calling v1TranscriptUpdateParticipant.",
);
}
if (
requestParameters.participantId === null ||
requestParameters.participantId === undefined
) {
throw new runtime.RequiredError(
"participantId",
"Required parameter requestParameters.participantId was null or undefined when calling v1TranscriptUpdateParticipant.",
);
}
if (
requestParameters.updateParticipant === null ||
requestParameters.updateParticipant === undefined
) {
throw new runtime.RequiredError(
"updateParticipant",
"Required parameter requestParameters.updateParticipant was null or undefined when calling v1TranscriptUpdateParticipant.",
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters["Content-Type"] = "application/json";
if (this.configuration && this.configuration.accessToken) {
// oauth required
headerParameters["Authorization"] = await this.configuration.accessToken(
"OAuth2AuthorizationCodeBearer",
[],
);
}
const response = await this.request(
{
path: `/v1/transcripts/{transcript_id}/participants/{participant_id}`
.replace(
`{${"transcript_id"}}`,
encodeURIComponent(String(requestParameters.transcriptId)),
)
.replace(
`{${"participant_id"}}`,
encodeURIComponent(String(requestParameters.participantId)),
),
method: "PATCH",
headers: headerParameters,
query: queryParameters,
body: UpdateParticipantToJSON(requestParameters.updateParticipant),
},
initOverrides,
);
return new runtime.JSONApiResponse(response, (jsonValue) =>
ParticipantFromJSON(jsonValue),
);
}
/**
* Transcript Update Participant
*/
async v1TranscriptUpdateParticipant(
requestParameters: V1TranscriptUpdateParticipantRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction,
): Promise<Participant> {
const response = await this.v1TranscriptUpdateParticipantRaw(
requestParameters,
initOverrides,
);
return await response.value();
}
/**
* Transcripts Create
*/

View File

@@ -0,0 +1,74 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface CreateParticipant
*/
export interface CreateParticipant {
/**
*
* @type {any}
* @memberof CreateParticipant
*/
speaker?: any | null;
/**
*
* @type {any}
* @memberof CreateParticipant
*/
name: any | null;
}
/**
* Check if a given object implements the CreateParticipant interface.
*/
export function instanceOfCreateParticipant(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "name" in value;
return isInstance;
}
export function CreateParticipantFromJSON(json: any): CreateParticipant {
return CreateParticipantFromJSONTyped(json, false);
}
export function CreateParticipantFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): CreateParticipant {
if (json === undefined || json === null) {
return json;
}
return {
speaker: !exists(json, "speaker") ? undefined : json["speaker"],
name: json["name"],
};
}
export function CreateParticipantToJSON(value?: CreateParticipant | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
speaker: value.speaker,
name: value.name,
};
}

View File

@@ -97,6 +97,12 @@ export interface GetTranscript {
* @memberof GetTranscript
*/
targetLanguage: any | null;
/**
*
* @type {any}
* @memberof GetTranscript
*/
participants: any | null;
}
/**
@@ -116,6 +122,7 @@ export function instanceOfGetTranscript(value: object): boolean {
isInstance = isInstance && "createdAt" in value;
isInstance = isInstance && "sourceLanguage" in value;
isInstance = isInstance && "targetLanguage" in value;
isInstance = isInstance && "participants" in value;
return isInstance;
}
@@ -145,6 +152,7 @@ export function GetTranscriptFromJSONTyped(
shareMode: !exists(json, "share_mode") ? undefined : json["share_mode"],
sourceLanguage: json["source_language"],
targetLanguage: json["target_language"],
participants: json["participants"],
};
}
@@ -169,5 +177,6 @@ export function GetTranscriptToJSON(value?: GetTranscript | null): any {
share_mode: value.shareMode,
source_language: value.sourceLanguage,
target_language: value.targetLanguage,
participants: value.participants,
};
}

View File

@@ -43,6 +43,12 @@ export interface GetTranscriptTopic {
* @memberof GetTranscriptTopic
*/
timestamp: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopic
*/
duration: any | null;
/**
*
* @type {any}
@@ -66,6 +72,7 @@ export function instanceOfGetTranscriptTopic(value: object): boolean {
isInstance = isInstance && "title" in value;
isInstance = isInstance && "summary" in value;
isInstance = isInstance && "timestamp" in value;
isInstance = isInstance && "duration" in value;
isInstance = isInstance && "transcript" in value;
return isInstance;
@@ -87,6 +94,7 @@ export function GetTranscriptTopicFromJSONTyped(
title: json["title"],
summary: json["summary"],
timestamp: json["timestamp"],
duration: json["duration"],
transcript: json["transcript"],
segments: !exists(json, "segments") ? undefined : json["segments"],
};
@@ -106,6 +114,7 @@ export function GetTranscriptTopicToJSON(
title: value.title,
summary: value.summary,
timestamp: value.timestamp,
duration: value.duration,
transcript: value.transcript,
segments: value.segments,
};

View File

@@ -0,0 +1,131 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface GetTranscriptTopicWithWords
*/
export interface GetTranscriptTopicWithWords {
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
id: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
title: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
summary: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
timestamp: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
duration: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
transcript: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
segments?: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWords
*/
words?: any | null;
}
/**
* Check if a given object implements the GetTranscriptTopicWithWords interface.
*/
export function instanceOfGetTranscriptTopicWithWords(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "id" in value;
isInstance = isInstance && "title" in value;
isInstance = isInstance && "summary" in value;
isInstance = isInstance && "timestamp" in value;
isInstance = isInstance && "duration" in value;
isInstance = isInstance && "transcript" in value;
return isInstance;
}
export function GetTranscriptTopicWithWordsFromJSON(
json: any,
): GetTranscriptTopicWithWords {
return GetTranscriptTopicWithWordsFromJSONTyped(json, false);
}
export function GetTranscriptTopicWithWordsFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): GetTranscriptTopicWithWords {
if (json === undefined || json === null) {
return json;
}
return {
id: json["id"],
title: json["title"],
summary: json["summary"],
timestamp: json["timestamp"],
duration: json["duration"],
transcript: json["transcript"],
segments: !exists(json, "segments") ? undefined : json["segments"],
words: !exists(json, "words") ? undefined : json["words"],
};
}
export function GetTranscriptTopicWithWordsToJSON(
value?: GetTranscriptTopicWithWords | null,
): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
id: value.id,
title: value.title,
summary: value.summary,
timestamp: value.timestamp,
duration: value.duration,
transcript: value.transcript,
segments: value.segments,
words: value.words,
};
}

View File

@@ -0,0 +1,135 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface GetTranscriptTopicWithWordsPerSpeaker
*/
export interface GetTranscriptTopicWithWordsPerSpeaker {
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
id: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
title: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
summary: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
timestamp: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
duration: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
transcript: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
segments?: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopicWithWordsPerSpeaker
*/
wordsPerSpeaker?: any | null;
}
/**
* Check if a given object implements the GetTranscriptTopicWithWordsPerSpeaker interface.
*/
export function instanceOfGetTranscriptTopicWithWordsPerSpeaker(
value: object,
): boolean {
let isInstance = true;
isInstance = isInstance && "id" in value;
isInstance = isInstance && "title" in value;
isInstance = isInstance && "summary" in value;
isInstance = isInstance && "timestamp" in value;
isInstance = isInstance && "duration" in value;
isInstance = isInstance && "transcript" in value;
return isInstance;
}
export function GetTranscriptTopicWithWordsPerSpeakerFromJSON(
json: any,
): GetTranscriptTopicWithWordsPerSpeaker {
return GetTranscriptTopicWithWordsPerSpeakerFromJSONTyped(json, false);
}
export function GetTranscriptTopicWithWordsPerSpeakerFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): GetTranscriptTopicWithWordsPerSpeaker {
if (json === undefined || json === null) {
return json;
}
return {
id: json["id"],
title: json["title"],
summary: json["summary"],
timestamp: json["timestamp"],
duration: json["duration"],
transcript: json["transcript"],
segments: !exists(json, "segments") ? undefined : json["segments"],
wordsPerSpeaker: !exists(json, "words_per_speaker")
? undefined
: json["words_per_speaker"],
};
}
export function GetTranscriptTopicWithWordsPerSpeakerToJSON(
value?: GetTranscriptTopicWithWordsPerSpeaker | null,
): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
id: value.id,
title: value.title,
summary: value.summary,
timestamp: value.timestamp,
duration: value.duration,
transcript: value.transcript,
segments: value.segments,
words_per_speaker: value.wordsPerSpeaker,
};
}

View File

@@ -0,0 +1,84 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface Participant
*/
export interface Participant {
/**
*
* @type {any}
* @memberof Participant
*/
id: any | null;
/**
*
* @type {any}
* @memberof Participant
*/
speaker: any | null;
/**
*
* @type {any}
* @memberof Participant
*/
name: any | null;
}
/**
* Check if a given object implements the Participant interface.
*/
export function instanceOfParticipant(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "id" in value;
isInstance = isInstance && "speaker" in value;
isInstance = isInstance && "name" in value;
return isInstance;
}
export function ParticipantFromJSON(json: any): Participant {
return ParticipantFromJSONTyped(json, false);
}
export function ParticipantFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): Participant {
if (json === undefined || json === null) {
return json;
}
return {
id: json["id"],
speaker: json["speaker"],
name: json["name"],
};
}
export function ParticipantToJSON(value?: Participant | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
id: value.id,
speaker: value.speaker,
name: value.name,
};
}

View File

@@ -0,0 +1,91 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface SpeakerAssignment
*/
export interface SpeakerAssignment {
/**
*
* @type {any}
* @memberof SpeakerAssignment
*/
speaker?: any | null;
/**
*
* @type {any}
* @memberof SpeakerAssignment
*/
participant?: any | null;
/**
*
* @type {any}
* @memberof SpeakerAssignment
*/
timestampFrom: any | null;
/**
*
* @type {any}
* @memberof SpeakerAssignment
*/
timestampTo: any | null;
}
/**
* Check if a given object implements the SpeakerAssignment interface.
*/
export function instanceOfSpeakerAssignment(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "timestampFrom" in value;
isInstance = isInstance && "timestampTo" in value;
return isInstance;
}
export function SpeakerAssignmentFromJSON(json: any): SpeakerAssignment {
return SpeakerAssignmentFromJSONTyped(json, false);
}
export function SpeakerAssignmentFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): SpeakerAssignment {
if (json === undefined || json === null) {
return json;
}
return {
speaker: !exists(json, "speaker") ? undefined : json["speaker"],
participant: !exists(json, "participant") ? undefined : json["participant"],
timestampFrom: json["timestamp_from"],
timestampTo: json["timestamp_to"],
};
}
export function SpeakerAssignmentToJSON(value?: SpeakerAssignment | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
speaker: value.speaker,
participant: value.participant,
timestamp_from: value.timestampFrom,
timestamp_to: value.timestampTo,
};
}

View File

@@ -0,0 +1,70 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface SpeakerAssignmentStatus
*/
export interface SpeakerAssignmentStatus {
/**
*
* @type {any}
* @memberof SpeakerAssignmentStatus
*/
status: any | null;
}
/**
* Check if a given object implements the SpeakerAssignmentStatus interface.
*/
export function instanceOfSpeakerAssignmentStatus(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "status" in value;
return isInstance;
}
export function SpeakerAssignmentStatusFromJSON(
json: any,
): SpeakerAssignmentStatus {
return SpeakerAssignmentStatusFromJSONTyped(json, false);
}
export function SpeakerAssignmentStatusFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): SpeakerAssignmentStatus {
if (json === undefined || json === null) {
return json;
}
return {
status: json["status"],
};
}
export function SpeakerAssignmentStatusToJSON(
value?: SpeakerAssignmentStatus | null,
): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
status: value.status,
};
}

View File

@@ -0,0 +1,75 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface SpeakerMerge
*/
export interface SpeakerMerge {
/**
*
* @type {any}
* @memberof SpeakerMerge
*/
speakerFrom: any | null;
/**
*
* @type {any}
* @memberof SpeakerMerge
*/
speakerTo: any | null;
}
/**
* Check if a given object implements the SpeakerMerge interface.
*/
export function instanceOfSpeakerMerge(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "speakerFrom" in value;
isInstance = isInstance && "speakerTo" in value;
return isInstance;
}
export function SpeakerMergeFromJSON(json: any): SpeakerMerge {
return SpeakerMergeFromJSONTyped(json, false);
}
export function SpeakerMergeFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): SpeakerMerge {
if (json === undefined || json === null) {
return json;
}
return {
speakerFrom: json["speaker_from"],
speakerTo: json["speaker_to"],
};
}
export function SpeakerMergeToJSON(value?: SpeakerMerge | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
speaker_from: value.speakerFrom,
speaker_to: value.speakerTo,
};
}

View File

@@ -0,0 +1,75 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface SpeakerWords
*/
export interface SpeakerWords {
/**
*
* @type {any}
* @memberof SpeakerWords
*/
speaker: any | null;
/**
*
* @type {any}
* @memberof SpeakerWords
*/
words: any | null;
}
/**
* Check if a given object implements the SpeakerWords interface.
*/
export function instanceOfSpeakerWords(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "speaker" in value;
isInstance = isInstance && "words" in value;
return isInstance;
}
export function SpeakerWordsFromJSON(json: any): SpeakerWords {
return SpeakerWordsFromJSONTyped(json, false);
}
export function SpeakerWordsFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): SpeakerWords {
if (json === undefined || json === null) {
return json;
}
return {
speaker: json["speaker"],
words: json["words"],
};
}
export function SpeakerWordsToJSON(value?: SpeakerWords | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
speaker: value.speaker,
words: value.words,
};
}

View File

@@ -0,0 +1,87 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface TranscriptParticipant
*/
export interface TranscriptParticipant {
/**
*
* @type {any}
* @memberof TranscriptParticipant
*/
id?: any | null;
/**
*
* @type {any}
* @memberof TranscriptParticipant
*/
speaker: any | null;
/**
*
* @type {any}
* @memberof TranscriptParticipant
*/
name: any | null;
}
/**
* Check if a given object implements the TranscriptParticipant interface.
*/
export function instanceOfTranscriptParticipant(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "speaker" in value;
isInstance = isInstance && "name" in value;
return isInstance;
}
export function TranscriptParticipantFromJSON(
json: any,
): TranscriptParticipant {
return TranscriptParticipantFromJSONTyped(json, false);
}
export function TranscriptParticipantFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): TranscriptParticipant {
if (json === undefined || json === null) {
return json;
}
return {
id: !exists(json, "id") ? undefined : json["id"],
speaker: json["speaker"],
name: json["name"],
};
}
export function TranscriptParticipantToJSON(
value?: TranscriptParticipant | null,
): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
id: value.id,
speaker: value.speaker,
name: value.name,
};
}

View File

@@ -0,0 +1,73 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface UpdateParticipant
*/
export interface UpdateParticipant {
/**
*
* @type {any}
* @memberof UpdateParticipant
*/
speaker?: any | null;
/**
*
* @type {any}
* @memberof UpdateParticipant
*/
name?: any | null;
}
/**
* Check if a given object implements the UpdateParticipant interface.
*/
export function instanceOfUpdateParticipant(value: object): boolean {
let isInstance = true;
return isInstance;
}
export function UpdateParticipantFromJSON(json: any): UpdateParticipant {
return UpdateParticipantFromJSONTyped(json, false);
}
export function UpdateParticipantFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): UpdateParticipant {
if (json === undefined || json === null) {
return json;
}
return {
speaker: !exists(json, "speaker") ? undefined : json["speaker"],
name: !exists(json, "name") ? undefined : json["name"],
};
}
export function UpdateParticipantToJSON(value?: UpdateParticipant | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
speaker: value.speaker,
name: value.name,
};
}

View File

@@ -55,6 +55,12 @@ export interface UpdateTranscript {
* @memberof UpdateTranscript
*/
shareMode?: any | null;
/**
*
* @type {any}
* @memberof UpdateTranscript
*/
participants?: any | null;
}
/**
@@ -88,6 +94,9 @@ export function UpdateTranscriptFromJSONTyped(
? undefined
: json["long_summary"],
shareMode: !exists(json, "share_mode") ? undefined : json["share_mode"],
participants: !exists(json, "participants")
? undefined
: json["participants"],
};
}
@@ -105,5 +114,6 @@ export function UpdateTranscriptToJSON(value?: UpdateTranscript | null): any {
short_summary: value.shortSummary,
long_summary: value.longSummary,
share_mode: value.shareMode,
participants: value.participants,
};
}

View File

@@ -0,0 +1,92 @@
/* tslint:disable */
/* eslint-disable */
/**
* FastAPI
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { exists, mapValues } from "../runtime";
/**
*
* @export
* @interface Word
*/
export interface Word {
/**
*
* @type {any}
* @memberof Word
*/
text: any | null;
/**
*
* @type {any}
* @memberof Word
*/
start: any | null;
/**
*
* @type {any}
* @memberof Word
*/
end: any | null;
/**
*
* @type {any}
* @memberof Word
*/
speaker?: any | null;
}
/**
* Check if a given object implements the Word interface.
*/
export function instanceOfWord(value: object): boolean {
let isInstance = true;
isInstance = isInstance && "text" in value;
isInstance = isInstance && "start" in value;
isInstance = isInstance && "end" in value;
return isInstance;
}
export function WordFromJSON(json: any): Word {
return WordFromJSONTyped(json, false);
}
export function WordFromJSONTyped(
json: any,
ignoreDiscriminator: boolean,
): Word {
if (json === undefined || json === null) {
return json;
}
return {
text: json["text"],
start: json["start"],
end: json["end"],
speaker: !exists(json, "speaker") ? undefined : json["speaker"],
};
}
export function WordToJSON(value?: Word | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {
text: value.text,
start: value.start,
end: value.end,
speaker: value.speaker,
};
}

View File

@@ -1,14 +1,25 @@
/* tslint:disable */
/* eslint-disable */
export * from "./AudioWaveform";
export * from "./CreateParticipant";
export * from "./CreateTranscript";
export * from "./DeletionStatus";
export * from "./GetTranscript";
export * from "./GetTranscriptSegmentTopic";
export * from "./GetTranscriptTopic";
export * from "./GetTranscriptTopicWithWords";
export * from "./GetTranscriptTopicWithWordsPerSpeaker";
export * from "./HTTPValidationError";
export * from "./PageGetTranscript";
export * from "./Participant";
export * from "./RtcOffer";
export * from "./SpeakerAssignment";
export * from "./SpeakerAssignmentStatus";
export * from "./SpeakerMerge";
export * from "./SpeakerWords";
export * from "./TranscriptParticipant";
export * from "./UpdateParticipant";
export * from "./UpdateTranscript";
export * from "./UserInfo";
export * from "./ValidationError";
export * from "./Word";