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 ( from reflector.views.transcripts_participants import (
router as transcripts_participants_router, 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_upload import router as transcripts_upload_router
from reflector.views.transcripts_webrtc import router as transcripts_webrtc_router from reflector.views.transcripts_webrtc import router as transcripts_webrtc_router
from reflector.views.transcripts_websocket import router as transcripts_websocket_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_router, prefix="/v1")
app.include_router(transcripts_audio_router, prefix="/v1") app.include_router(transcripts_audio_router, prefix="/v1")
app.include_router(transcripts_participants_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_upload_router, prefix="/v1")
app.include_router(transcripts_websocket_router, prefix="/v1") app.include_router(transcripts_websocket_router, prefix="/v1")
app.include_router(transcripts_webrtc_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.processors.types import Word as ProcessorWord
from reflector.settings import settings from reflector.settings import settings
from reflector.storage import Storage from reflector.storage import Storage
from sqlalchemy.sql import false
transcripts = sqlalchemy.Table( transcripts = sqlalchemy.Table(
"transcript", "transcript",
@@ -30,6 +31,9 @@ transcripts = sqlalchemy.Table(
sqlalchemy.Column("participants", sqlalchemy.JSON), sqlalchemy.Column("participants", sqlalchemy.JSON),
sqlalchemy.Column("source_language", sqlalchemy.String, nullable=True), sqlalchemy.Column("source_language", sqlalchemy.String, nullable=True),
sqlalchemy.Column("target_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( sqlalchemy.Column(
"audio_location", "audio_location",
sqlalchemy.String, sqlalchemy.String,
@@ -138,6 +142,7 @@ class Transcript(BaseModel):
target_language: str = "en" target_language: str = "en"
share_mode: Literal["private", "semi-private", "public"] = "private" share_mode: Literal["private", "semi-private", "public"] = "private"
audio_location: str = "local" audio_location: str = "local"
reviewed: bool = False
def add_event(self, event: str, data: BaseModel) -> TranscriptEvent: def add_event(self, event: str, data: BaseModel) -> TranscriptEvent:
ev = TranscriptEvent(event=event, data=data.model_dump()) ev = TranscriptEvent(event=event, data=data.model_dump())
@@ -248,6 +253,23 @@ class Transcript(BaseModel):
url += f"?token={token}" url += f"?token={token}"
return url 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: class TranscriptController:
async def get_all( async def get_all(
@@ -362,7 +384,7 @@ class TranscriptController:
await database.execute(query) await database.execute(query)
return transcript 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 Update a transcript fields with key/values in values
""" """
@@ -372,8 +394,9 @@ class TranscriptController:
.values(**values) .values(**values)
) )
await database.execute(query) await database.execute(query)
for key, value in values.items(): if mutate:
setattr(transcript, key, value) for key, value in values.items():
setattr(transcript, key, value)
async def remove_by_id( async def remove_by_id(
self, self,
@@ -410,7 +433,11 @@ class TranscriptController:
Append an event to a transcript Append an event to a transcript
""" """
resp = transcript.add_event(event=event, data=data) 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 return resp
async def upsert_topic( async def upsert_topic(
@@ -422,7 +449,11 @@ class TranscriptController:
Append an event to a transcript Append an event to a transcript
""" """
transcript.upsert_topic(topic) 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): async def move_mp3_to_storage(self, transcript: Transcript):
""" """
@@ -450,7 +481,11 @@ class TranscriptController:
Add/update a participant to a transcript Add/update a participant to a transcript
""" """
result = transcript.upsert_participant(participant) 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 return result
async def delete_participant( async def delete_participant(
@@ -462,7 +497,11 @@ class TranscriptController:
Delete a participant from a transcript Delete a participant from a transcript
""" """
transcript.delete_participant(participant_id) 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() transcripts_controller = TranscriptController()

View File

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

View File

@@ -13,6 +13,7 @@ from reflector.db.transcripts import (
transcripts_controller, transcripts_controller,
) )
from reflector.processors.types import Transcript as ProcessorTranscript from reflector.processors.types import Transcript as ProcessorTranscript
from reflector.processors.types import Word
from reflector.settings import settings from reflector.settings import settings
router = APIRouter() router = APIRouter()
@@ -49,6 +50,7 @@ class GetTranscript(BaseModel):
source_language: str | None source_language: str | None
target_language: str | None target_language: str | None
participants: list[TranscriptParticipant] | None participants: list[TranscriptParticipant] | None
reviewed: bool
class CreateTranscript(BaseModel): class CreateTranscript(BaseModel):
@@ -65,6 +67,7 @@ class UpdateTranscript(BaseModel):
long_summary: Optional[str] = Field(None) long_summary: Optional[str] = Field(None)
share_mode: Optional[Literal["public", "semi-private", "private"]] = Field(None) share_mode: Optional[Literal["public", "semi-private", "private"]] = Field(None)
participants: Optional[list[TranscriptParticipant]] = Field(None) participants: Optional[list[TranscriptParticipant]] = Field(None)
reviewed: Optional[bool] = Field(None)
class DeletionStatus(BaseModel): class DeletionStatus(BaseModel):
@@ -121,6 +124,7 @@ class GetTranscriptTopic(BaseModel):
title: str title: str
summary: str summary: str
timestamp: float timestamp: float
duration: float | None
transcript: str transcript: str
segments: list[GetTranscriptSegmentTopic] = [] segments: list[GetTranscriptSegmentTopic] = []
@@ -130,6 +134,7 @@ class GetTranscriptTopic(BaseModel):
# In previous version, words were missing # In previous version, words were missing
# Just output a segment with speaker 0 # Just output a segment with speaker 0
text = topic.transcript text = topic.transcript
duration = None
segments = [ segments = [
GetTranscriptSegmentTopic( GetTranscriptSegmentTopic(
text=topic.transcript, text=topic.transcript,
@@ -141,6 +146,7 @@ class GetTranscriptTopic(BaseModel):
# New versions include words # New versions include words
transcript = ProcessorTranscript(words=topic.words) transcript = ProcessorTranscript(words=topic.words)
text = transcript.text text = transcript.text
duration = transcript.duration
segments = [ segments = [
GetTranscriptSegmentTopic( GetTranscriptSegmentTopic(
text=segment.text, text=segment.text,
@@ -156,9 +162,59 @@ class GetTranscriptTopic(BaseModel):
timestamp=topic.timestamp, timestamp=topic.timestamp,
transcript=text, transcript=text,
segments=segments, 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) @router.get("/transcripts/{transcript_id}", response_model=GetTranscript)
async def transcript_get( async def transcript_get(
transcript_id: str, transcript_id: str,
@@ -215,3 +271,46 @@ async def transcript_get_topics(
return [ return [
GetTranscriptTopic.from_transcript_topic(topic) for topic in transcript.topics 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,12 +59,13 @@ async def transcript_add_participant(
) )
# ensure the speaker is unique # ensure the speaker is unique
for p in transcript.participants: if participant.speaker is not None:
if p.speaker == participant.speaker: for p in transcript.participants:
raise HTTPException( if p.speaker == participant.speaker:
status_code=400, raise HTTPException(
detail="Speaker already assigned", status_code=400,
) detail="Speaker already assigned",
)
obj = await transcripts_controller.upsert_participant( obj = await transcripts_controller.upsert_participant(
transcript, TranscriptParticipant(**participant.dict()) transcript, TranscriptParticipant(**participant.dict())

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: ) as mock_move:
mock_move.return_value = True mock_move.return_value = True
yield 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}") response = await ac.get(f"/transcripts/{tid}")
assert response.status_code == 404 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", id: "1",
timestamp: 10, timestamp: 10,
duration: 10,
summary: "This is test topic 1", summary: "This is test topic 1",
title: "Topic 1: Introduction to Quantum Mechanics", title: "Topic 1: Introduction to Quantum Mechanics",
transcript: transcript:
@@ -103,6 +104,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{ {
id: "2", id: "2",
timestamp: 20, timestamp: 20,
duration: 10,
summary: "This is test topic 2", summary: "This is test topic 2",
title: "Topic 2: Machine Learning Algorithms", title: "Topic 2: Machine Learning Algorithms",
transcript: transcript:
@@ -123,6 +125,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{ {
id: "3", id: "3",
timestamp: 30, timestamp: 30,
duration: 10,
summary: "This is test topic 3", summary: "This is test topic 3",
title: "Topic 3: Mental Health Awareness", title: "Topic 3: Mental Health Awareness",
transcript: "Ways to improve mental health and reduce stigma.", transcript: "Ways to improve mental health and reduce stigma.",
@@ -142,6 +145,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{ {
id: "4", id: "4",
timestamp: 40, timestamp: 40,
duration: 10,
summary: "This is test topic 4", summary: "This is test topic 4",
title: "Topic 4: Basics of Productivity", title: "Topic 4: Basics of Productivity",
transcript: "Tips and tricks to increase daily productivity.", transcript: "Tips and tricks to increase daily productivity.",
@@ -161,6 +165,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{ {
id: "5", id: "5",
timestamp: 50, timestamp: 50,
duration: 10,
summary: "This is test topic 5", summary: "This is test topic 5",
title: "Topic 5: Future of Aviation", title: "Topic 5: Future of Aviation",
transcript: transcript:
@@ -190,6 +195,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
{ {
id: "1", id: "1",
timestamp: 10, timestamp: 10,
duration: 10,
summary: "This is test topic 1", summary: "This is test topic 1",
title: title:
"Topic 1: Introduction to Quantum Mechanics, a brief overview of quantum mechanics and its principles.", "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", id: "2",
timestamp: 20, timestamp: 20,
duration: 10,
summary: "This is test topic 2", summary: "This is test topic 2",
title: title:
"Topic 2: Machine Learning Algorithms, understanding the different types of machine learning algorithms.", "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", id: "3",
timestamp: 30, timestamp: 30,
duration: 10,
summary: "This is test topic 3", summary: "This is test topic 3",
title: title:
"Topic 3: Mental Health Awareness, ways to improve mental health and reduce stigma.", "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", id: "4",
timestamp: 40, timestamp: 40,
duration: 10,
summary: "This is test topic 4", summary: "This is test topic 4",
title: title:
"Topic 4: Basics of Productivity, tips and tricks to increase daily productivity.", "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", id: "5",
timestamp: 50, timestamp: 50,
duration: 10,
summary: "This is test topic 5", summary: "This is test topic 5",
title: title:
"Topic 5: Future of Aviation, exploring the advancements and possibilities in aviation.", "Topic 5: Future of Aviation, exploring the advancements and possibilities in aviation.",

View File

@@ -2,16 +2,27 @@ apis/DefaultApi.ts
apis/index.ts apis/index.ts
index.ts index.ts
models/AudioWaveform.ts models/AudioWaveform.ts
models/CreateParticipant.ts
models/CreateTranscript.ts models/CreateTranscript.ts
models/DeletionStatus.ts models/DeletionStatus.ts
models/GetTranscript.ts models/GetTranscript.ts
models/GetTranscriptSegmentTopic.ts models/GetTranscriptSegmentTopic.ts
models/GetTranscriptTopic.ts models/GetTranscriptTopic.ts
models/GetTranscriptTopicWithWords.ts
models/GetTranscriptTopicWithWordsPerSpeaker.ts
models/HTTPValidationError.ts models/HTTPValidationError.ts
models/PageGetTranscript.ts models/PageGetTranscript.ts
models/Participant.ts
models/RtcOffer.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/UpdateTranscript.ts
models/UserInfo.ts models/UserInfo.ts
models/ValidationError.ts models/ValidationError.ts
models/Word.ts
models/index.ts models/index.ts
runtime.ts runtime.ts

View File

@@ -15,37 +15,73 @@
import * as runtime from "../runtime"; import * as runtime from "../runtime";
import type { import type {
AudioWaveform, AudioWaveform,
CreateParticipant,
CreateTranscript, CreateTranscript,
DeletionStatus, DeletionStatus,
GetTranscript, GetTranscript,
GetTranscriptTopicWithWordsPerSpeaker,
HTTPValidationError, HTTPValidationError,
PageGetTranscript, PageGetTranscript,
Participant,
RtcOffer, RtcOffer,
SpeakerAssignment,
SpeakerAssignmentStatus,
SpeakerMerge,
UpdateParticipant,
UpdateTranscript, UpdateTranscript,
} from "../models"; } from "../models";
import { import {
AudioWaveformFromJSON, AudioWaveformFromJSON,
AudioWaveformToJSON, AudioWaveformToJSON,
CreateParticipantFromJSON,
CreateParticipantToJSON,
CreateTranscriptFromJSON, CreateTranscriptFromJSON,
CreateTranscriptToJSON, CreateTranscriptToJSON,
DeletionStatusFromJSON, DeletionStatusFromJSON,
DeletionStatusToJSON, DeletionStatusToJSON,
GetTranscriptFromJSON, GetTranscriptFromJSON,
GetTranscriptToJSON, GetTranscriptToJSON,
GetTranscriptTopicWithWordsPerSpeakerFromJSON,
GetTranscriptTopicWithWordsPerSpeakerToJSON,
HTTPValidationErrorFromJSON, HTTPValidationErrorFromJSON,
HTTPValidationErrorToJSON, HTTPValidationErrorToJSON,
PageGetTranscriptFromJSON, PageGetTranscriptFromJSON,
PageGetTranscriptToJSON, PageGetTranscriptToJSON,
ParticipantFromJSON,
ParticipantToJSON,
RtcOfferFromJSON, RtcOfferFromJSON,
RtcOfferToJSON, RtcOfferToJSON,
SpeakerAssignmentFromJSON,
SpeakerAssignmentToJSON,
SpeakerAssignmentStatusFromJSON,
SpeakerAssignmentStatusToJSON,
SpeakerMergeFromJSON,
SpeakerMergeToJSON,
UpdateParticipantFromJSON,
UpdateParticipantToJSON,
UpdateTranscriptFromJSON, UpdateTranscriptFromJSON,
UpdateTranscriptToJSON, UpdateTranscriptToJSON,
} from "../models"; } from "../models";
export interface V1TranscriptAddParticipantRequest {
transcriptId: any;
createParticipant: CreateParticipant;
}
export interface V1TranscriptAssignSpeakerRequest {
transcriptId: any;
speakerAssignment: SpeakerAssignment;
}
export interface V1TranscriptDeleteRequest { export interface V1TranscriptDeleteRequest {
transcriptId: any; transcriptId: any;
} }
export interface V1TranscriptDeleteParticipantRequest {
transcriptId: any;
participantId: any;
}
export interface V1TranscriptGetRequest { export interface V1TranscriptGetRequest {
transcriptId: any; transcriptId: any;
} }
@@ -59,14 +95,37 @@ export interface V1TranscriptGetAudioWaveformRequest {
transcriptId: any; transcriptId: any;
} }
export interface V1TranscriptGetParticipantRequest {
transcriptId: any;
participantId: any;
}
export interface V1TranscriptGetParticipantsRequest {
transcriptId: any;
}
export interface V1TranscriptGetTopicsRequest { export interface V1TranscriptGetTopicsRequest {
transcriptId: any; transcriptId: any;
} }
export interface V1TranscriptGetTopicsWithWordsRequest {
transcriptId: any;
}
export interface V1TranscriptGetTopicsWithWordsPerSpeakerRequest {
transcriptId: any;
topicId: any;
}
export interface V1TranscriptGetWebsocketEventsRequest { export interface V1TranscriptGetWebsocketEventsRequest {
transcriptId: any; transcriptId: any;
} }
export interface V1TranscriptMergeSpeakerRequest {
transcriptId: any;
speakerMerge: SpeakerMerge;
}
export interface V1TranscriptRecordWebrtcRequest { export interface V1TranscriptRecordWebrtcRequest {
transcriptId: any; transcriptId: any;
rtcOffer: RtcOffer; rtcOffer: RtcOffer;
@@ -77,6 +136,12 @@ export interface V1TranscriptUpdateRequest {
updateTranscript: UpdateTranscript; updateTranscript: UpdateTranscript;
} }
export interface V1TranscriptUpdateParticipantRequest {
transcriptId: any;
participantId: any;
updateParticipant: UpdateParticipant;
}
export interface V1TranscriptsCreateRequest { export interface V1TranscriptsCreateRequest {
createTranscript: CreateTranscript; createTranscript: CreateTranscript;
} }
@@ -129,6 +194,154 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value(); 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 * Transcript Delete
*/ */
@@ -190,6 +403,82 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value(); 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 * Transcript Get
*/ */
@@ -379,6 +668,145 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value(); 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 * Transcript Get Topics
*/ */
@@ -442,6 +870,145 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value(); 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 * Transcript Get Websocket Events
*/ */
@@ -497,6 +1064,80 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value(); 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 * Transcript Record Webrtc
*/ */
@@ -647,6 +1288,95 @@ export class DefaultApi extends runtime.BaseAPI {
return await response.value(); 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 * 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 * @memberof GetTranscript
*/ */
targetLanguage: any | null; 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 && "createdAt" in value;
isInstance = isInstance && "sourceLanguage" in value; isInstance = isInstance && "sourceLanguage" in value;
isInstance = isInstance && "targetLanguage" in value; isInstance = isInstance && "targetLanguage" in value;
isInstance = isInstance && "participants" in value;
return isInstance; return isInstance;
} }
@@ -145,6 +152,7 @@ export function GetTranscriptFromJSONTyped(
shareMode: !exists(json, "share_mode") ? undefined : json["share_mode"], shareMode: !exists(json, "share_mode") ? undefined : json["share_mode"],
sourceLanguage: json["source_language"], sourceLanguage: json["source_language"],
targetLanguage: json["target_language"], targetLanguage: json["target_language"],
participants: json["participants"],
}; };
} }
@@ -169,5 +177,6 @@ export function GetTranscriptToJSON(value?: GetTranscript | null): any {
share_mode: value.shareMode, share_mode: value.shareMode,
source_language: value.sourceLanguage, source_language: value.sourceLanguage,
target_language: value.targetLanguage, target_language: value.targetLanguage,
participants: value.participants,
}; };
} }

View File

@@ -43,6 +43,12 @@ export interface GetTranscriptTopic {
* @memberof GetTranscriptTopic * @memberof GetTranscriptTopic
*/ */
timestamp: any | null; timestamp: any | null;
/**
*
* @type {any}
* @memberof GetTranscriptTopic
*/
duration: any | null;
/** /**
* *
* @type {any} * @type {any}
@@ -66,6 +72,7 @@ export function instanceOfGetTranscriptTopic(value: object): boolean {
isInstance = isInstance && "title" in value; isInstance = isInstance && "title" in value;
isInstance = isInstance && "summary" in value; isInstance = isInstance && "summary" in value;
isInstance = isInstance && "timestamp" in value; isInstance = isInstance && "timestamp" in value;
isInstance = isInstance && "duration" in value;
isInstance = isInstance && "transcript" in value; isInstance = isInstance && "transcript" in value;
return isInstance; return isInstance;
@@ -87,6 +94,7 @@ export function GetTranscriptTopicFromJSONTyped(
title: json["title"], title: json["title"],
summary: json["summary"], summary: json["summary"],
timestamp: json["timestamp"], timestamp: json["timestamp"],
duration: json["duration"],
transcript: json["transcript"], transcript: json["transcript"],
segments: !exists(json, "segments") ? undefined : json["segments"], segments: !exists(json, "segments") ? undefined : json["segments"],
}; };
@@ -106,6 +114,7 @@ export function GetTranscriptTopicToJSON(
title: value.title, title: value.title,
summary: value.summary, summary: value.summary,
timestamp: value.timestamp, timestamp: value.timestamp,
duration: value.duration,
transcript: value.transcript, transcript: value.transcript,
segments: value.segments, 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 * @memberof UpdateTranscript
*/ */
shareMode?: any | null; shareMode?: any | null;
/**
*
* @type {any}
* @memberof UpdateTranscript
*/
participants?: any | null;
} }
/** /**
@@ -88,6 +94,9 @@ export function UpdateTranscriptFromJSONTyped(
? undefined ? undefined
: json["long_summary"], : json["long_summary"],
shareMode: !exists(json, "share_mode") ? undefined : json["share_mode"], 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, short_summary: value.shortSummary,
long_summary: value.longSummary, long_summary: value.longSummary,
share_mode: value.shareMode, 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 */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
export * from "./AudioWaveform"; export * from "./AudioWaveform";
export * from "./CreateParticipant";
export * from "./CreateTranscript"; export * from "./CreateTranscript";
export * from "./DeletionStatus"; export * from "./DeletionStatus";
export * from "./GetTranscript"; export * from "./GetTranscript";
export * from "./GetTranscriptSegmentTopic"; export * from "./GetTranscriptSegmentTopic";
export * from "./GetTranscriptTopic"; export * from "./GetTranscriptTopic";
export * from "./GetTranscriptTopicWithWords";
export * from "./GetTranscriptTopicWithWordsPerSpeaker";
export * from "./HTTPValidationError"; export * from "./HTTPValidationError";
export * from "./PageGetTranscript"; export * from "./PageGetTranscript";
export * from "./Participant";
export * from "./RtcOffer"; 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 "./UpdateTranscript";
export * from "./UserInfo"; export * from "./UserInfo";
export * from "./ValidationError"; export * from "./ValidationError";
export * from "./Word";