feat(stage11): audio integration — STT for interviews, podcasts, press conferences with timestamped claims
This commit is contained in:
@@ -538,7 +538,7 @@ class VisionEvidenceModel(Base):
|
||||
|
||||
extracted_text = Column(Text, nullable=False)
|
||||
image_data_url = Column(Text, nullable=True)
|
||||
entities = Column(JSON, nullable=False, default=dict)
|
||||
extracted_entities = Column(JSON, nullable=False, default=dict)
|
||||
|
||||
confidence = Column(Float, nullable=False, default=0.5)
|
||||
confidence_label = Column(String(16), nullable=False, default="medium")
|
||||
@@ -601,4 +601,157 @@ VisionEvidenceModel.entities = relationship(
|
||||
back_populates="evidence",
|
||||
cascade="all, delete-orphan",
|
||||
foreign_keys="VisionEntityModel.evidence_id",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Stage 11 — Audio Evidence Extraction (Speech-to-Text)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class AudioSegmentType(str, enum.Enum):
|
||||
"""Klassifikation der Audio-Quelle (Stage 11)."""
|
||||
|
||||
INTERVIEW = "interview"
|
||||
PODCAST = "podcast"
|
||||
PRESSEKONFERENZ = "pressekonferenz"
|
||||
REDEN = "reden"
|
||||
SONSTIGE = "sonstige"
|
||||
|
||||
|
||||
class AudioTranscriptModel(Base):
|
||||
"""Transkript eines Audio-Eintrags (Stage 11).
|
||||
|
||||
Felder:
|
||||
uuid: Primärschlüssel (UUID)
|
||||
research_run_id: Research-Run-Zuordnung
|
||||
source_id: Quelle, von der das Audio stammt
|
||||
segment_type: Art des Audio-Materials
|
||||
transcript_text: Gesamtes Transkript als Text
|
||||
audio_file_url: URL der Audio-Datei (optional)
|
||||
duration_seconds: Gesamtdauer in Sekunden
|
||||
language: Sprache des Audios
|
||||
confidence: Confidence der STT-Erkennung
|
||||
created_at / updated_at: Zeitstempel
|
||||
"""
|
||||
|
||||
__tablename__ = "audio_transcripts"
|
||||
|
||||
id = Column(String(36), primary_key=True, default=lambda: str(uuid4()))
|
||||
research_run_id = Column(String(36), nullable=False)
|
||||
source_id = Column(String(36), ForeignKey("sources.id"), nullable=True)
|
||||
|
||||
segment_type = Column(Enum(AudioSegmentType), nullable=True)
|
||||
|
||||
transcript_text = Column(Text, nullable=False, default="")
|
||||
audio_file_url = Column(Text, nullable=True)
|
||||
duration_seconds = Column(Float, nullable=False, default=0.0)
|
||||
language = Column(String(16), nullable=False, default="unknown")
|
||||
confidence = Column(Float, nullable=False, default=0.5)
|
||||
|
||||
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
segments = relationship(
|
||||
"AudioTranscriptSegmentModel",
|
||||
back_populates="transcript",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
claims = relationship(
|
||||
"AudioClaimModel",
|
||||
back_populates="transcript",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_audio_transcripts_research_run_id", "research_run_id"),
|
||||
Index("ix_audio_transcripts_segment_type", "segment_type"),
|
||||
Index("ix_audio_transcripts_source_id", "source_id"),
|
||||
)
|
||||
|
||||
|
||||
class AudioTranscriptSegmentModel(Base):
|
||||
"""Segment des Audio-Transkripts (Stage 11).
|
||||
|
||||
Felder:
|
||||
uuid: Primärschlüssel (UUID)
|
||||
transcript_id: FK zum AudioTranscript
|
||||
start_time: Start-Zeitstempel in Sekunden
|
||||
end_time: Ende-Zeitstempel in Sekunden
|
||||
text: Transkribierter Text
|
||||
speaker_id: ID des Sprechers
|
||||
speaker_type: Kategorie des Sprechers
|
||||
confidence: Confidence der STT-Erkennung
|
||||
"""
|
||||
|
||||
__tablename__ = "audio_transcript_segments"
|
||||
|
||||
id = Column(String(36), primary_key=True, default=lambda: str(uuid4()))
|
||||
transcript_id = Column(
|
||||
String(36),
|
||||
ForeignKey("audio_transcripts.id"),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
start_time = Column(Float, nullable=False, default=0.0)
|
||||
end_time = Column(Float, nullable=False, default=0.0)
|
||||
text = Column(Text, nullable=False, default="")
|
||||
speaker_id = Column(String(64), nullable=False, default="")
|
||||
speaker_type = Column(String(64), nullable=True)
|
||||
confidence = Column(Float, nullable=False, default=0.5)
|
||||
|
||||
# Relationships
|
||||
transcript = relationship("AudioTranscriptModel", back_populates="segments")
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_audio_transcript_segments_transcript_id", "transcript_id"),
|
||||
Index("ix_audio_transcript_segments_speaker_id", "speaker_id"),
|
||||
)
|
||||
|
||||
|
||||
class AudioClaimModel(Base):
|
||||
"""Claim extrahiert aus Audio mit Zeitstempel (Stage 11).
|
||||
|
||||
Jeder Claim aus Audio hat einen Zeitstempel im Original-Audio
|
||||
und muss quellenverknüpft sein (Provenance-Pflicht).
|
||||
|
||||
Felder:
|
||||
uuid: Primärschlüssel (UUID)
|
||||
transcript_id: FK zum AudioTranscript
|
||||
claim_text: Die extrahierte Behauptung
|
||||
timestamp_start: Start-Zeitstempel im Original-Audio
|
||||
timestamp_end: Ende-Zeitstempel im Original-Audio
|
||||
speaker_id: ID des Sprechers
|
||||
source_url: URL der Quelle (Provenance)
|
||||
evidence_span: Zitat oder Textpassage
|
||||
claim_type: Art des Claims
|
||||
confidence: Confidence der Claim-Extraktion
|
||||
"""
|
||||
|
||||
__tablename__ = "audio_claims"
|
||||
|
||||
id = Column(String(36), primary_key=True, default=lambda: str(uuid4()))
|
||||
transcript_id = Column(
|
||||
String(36),
|
||||
ForeignKey("audio_transcripts.id"),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
claim_text = Column(Text, nullable=False)
|
||||
timestamp_start = Column(Float, nullable=False, default=0.0)
|
||||
timestamp_end = Column(Float, nullable=False, default=0.0)
|
||||
speaker_id = Column(String(64), nullable=False, default="")
|
||||
source_url = Column(Text, nullable=True)
|
||||
evidence_span = Column(Text, nullable=True)
|
||||
claim_type = Column(String(64), nullable=True)
|
||||
confidence = Column(Float, nullable=False, default=0.5)
|
||||
|
||||
# Relationships
|
||||
transcript = relationship("AudioTranscriptModel", back_populates="claims")
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_audio_claims_transcript_id", "transcript_id"),
|
||||
Index("ix_audio_claims_claim_type", "claim_type"),
|
||||
Index("ix_audio_claims_speaker_id", "speaker_id"),
|
||||
)
|
||||
Reference in New Issue
Block a user