basyx commited on
Commit
f2be6bd
·
verified ·
1 Parent(s): 4dcba1b

feat: enable optional remote diarization

Browse files
Files changed (1) hide show
  1. app/services/media_service.py +33 -5
app/services/media_service.py CHANGED
@@ -12,6 +12,7 @@ from app.core.logger import get_logger
12
  from app.core.response import SuccessResponse
13
  from app.models.media import InputMedia, OperationResult, ResolvedRequest
14
  from app.services.cleanup import CleanupService
 
15
  from app.services.ffmpeg_service import FFmpegService
16
  from app.services.ffprobe_service import FFprobeService
17
  from app.services.input_resolver import InputResolver
@@ -40,6 +41,7 @@ class MediaProcessor:
40
  ytdlp: YTDLPService,
41
  whisper: WhisperService,
42
  assets: CanonicalAssetService | None = None,
 
43
  ) -> None:
44
  self.settings = settings
45
  self.resolver = resolver
@@ -50,6 +52,7 @@ class MediaProcessor:
50
  self.ytdlp = ytdlp
51
  self.whisper = whisper
52
  self.assets = assets
 
53
 
54
  async def run(
55
  self, resolved: ResolvedRequest, operation_name: str, operation: Operation
@@ -89,11 +92,24 @@ class MediaProcessor:
89
  from app.core.exceptions import InputError
90
  raise InputError("beam_size must be between 1 and 20")
91
 
92
- diarization = self._diarization(params.get("diarization"))
93
- if diarization is None and len(inputs) > 1:
 
 
 
 
 
94
  diarization = self._load_diarization_file(inputs[1])
 
 
 
 
 
 
 
 
95
 
96
- return await self.whisper.transcribe(
97
  inputs[0].temp_path,
98
  output_dir,
99
  model_name=params.get("model"),
@@ -111,16 +127,28 @@ class MediaProcessor:
111
  diarization=diarization,
112
  )
113
 
 
 
 
 
 
 
 
114
  @staticmethod
115
  def _diarization(value: Any) -> list[dict[str, Any]] | None:
116
  if value is None or value == "":
117
  return None
 
 
118
  if isinstance(value, str):
 
 
 
119
  try:
120
- value = json.loads(value)
121
  except json.JSONDecodeError as exc:
122
  from app.core.exceptions import InputError
123
- raise InputError("diarization must be valid JSON") from exc
124
  if not isinstance(value, list):
125
  from app.core.exceptions import InputError
126
  raise InputError("diarization must be a JSON array of speaker spans")
 
12
  from app.core.response import SuccessResponse
13
  from app.models.media import InputMedia, OperationResult, ResolvedRequest
14
  from app.services.cleanup import CleanupService
15
+ from app.services.diarization_service import DiarizationService
16
  from app.services.ffmpeg_service import FFmpegService
17
  from app.services.ffprobe_service import FFprobeService
18
  from app.services.input_resolver import InputResolver
 
41
  ytdlp: YTDLPService,
42
  whisper: WhisperService,
43
  assets: CanonicalAssetService | None = None,
44
+ diarization: DiarizationService | None = None,
45
  ) -> None:
46
  self.settings = settings
47
  self.resolver = resolver
 
52
  self.ytdlp = ytdlp
53
  self.whisper = whisper
54
  self.assets = assets
55
+ self.diarization = diarization or DiarizationService(settings)
56
 
57
  async def run(
58
  self, resolved: ResolvedRequest, operation_name: str, operation: Operation
 
92
  from app.core.exceptions import InputError
93
  raise InputError("beam_size must be between 1 and 20")
94
 
95
+ diarization_value = params.get("diarization")
96
+ diarization_source = "none"
97
+ diarization = self._diarization(diarization_value)
98
+
99
+ if diarization is not None:
100
+ diarization_source = "inline"
101
+ elif len(inputs) > 1:
102
  diarization = self._load_diarization_file(inputs[1])
103
+ diarization_source = "file"
104
+ elif self._bool(diarization_value, False):
105
+ diarization = await self.diarization.diarize(
106
+ inputs[0].temp_path,
107
+ inputs[0].mime_type,
108
+ inputs[0].filename,
109
+ )
110
+ diarization_source = "backend"
111
 
112
+ result = await self.whisper.transcribe(
113
  inputs[0].temp_path,
114
  output_dir,
115
  model_name=params.get("model"),
 
127
  diarization=diarization,
128
  )
129
 
130
+ result.metadata = {
131
+ **result.metadata,
132
+ "diarization_source": diarization_source,
133
+ "diarization_configured": self.diarization.is_configured,
134
+ }
135
+ return result
136
+
137
  @staticmethod
138
  def _diarization(value: Any) -> list[dict[str, Any]] | None:
139
  if value is None or value == "":
140
  return None
141
+ if isinstance(value, bool):
142
+ return None
143
  if isinstance(value, str):
144
+ stripped = value.strip()
145
+ if stripped.lower() in {"true", "1", "yes", "on"}:
146
+ return None
147
  try:
148
+ value = json.loads(stripped)
149
  except json.JSONDecodeError as exc:
150
  from app.core.exceptions import InputError
151
+ raise InputError("diarization must be valid JSON or a boolean flag") from exc
152
  if not isinstance(value, list):
153
  from app.core.exceptions import InputError
154
  raise InputError("diarization must be a JSON array of speaker spans")