WIP: Submit transcoding jobs via a HTTP API #6
@ -7,6 +7,7 @@ import se.su.dsv.whisperapi.core.Transcription;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -59,4 +60,16 @@ public class JDBCTransactionRepository implements TransactionRepository {
|
||||
.param("filename", filename)
|
||||
.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFiles(Transcription transcription) {
|
||||
return jdbcClient.sql("""
|
||||
SELECT filename
|
||||
FROM transcriptions_files
|
||||
WHERE transcription_id = :transcription_id
|
||||
""")
|
||||
.param("transcription_id", transcription.id())
|
||||
.query(String.class)
|
||||
.list();
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class WhisperApiApplication {
|
||||
TransactionRepository transcriptionRepository,
|
||||
WhisperFrontendConfiguration config)
|
||||
{
|
||||
return new TranscriptionService(transcriptionRepository, config.transcriptionFilesDirectory());
|
||||
return new TranscriptionService(transcriptionRepository, config.transcriptionFilesDirectory(), config.jobsDirectory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -6,6 +6,7 @@ import java.nio.file.Path;
|
||||
|
||||
@ConfigurationProperties(prefix = "whisper.frontend")
|
||||
public record WhisperFrontendConfiguration(
|
||||
Path transcriptionFilesDirectory)
|
||||
Path transcriptionFilesDirectory,
|
||||
Path jobsDirectory)
|
||||
{
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import se.su.dsv.whisperapi.core.CreateTranscription;
|
||||
import se.su.dsv.whisperapi.core.OutputFormat;
|
||||
import se.su.dsv.whisperapi.core.Transcription;
|
||||
@ -92,4 +93,34 @@ public class ApiController {
|
||||
throw new FileUploadFailed();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/api/transcriptions/{id}/job", consumes = "*/*")
|
||||
public ResponseEntity<Void> submitTranscriptionJob(
|
||||
Principal owner,
|
||||
UriComponentsBuilder uriComponentsBuilder,
|
||||
@PathVariable("id") String id)
|
||||
{
|
||||
UUID uuid = UUID.fromString(id);
|
||||
Transcription transcription = transcriptionService.getTranscription(owner, uuid)
|
||||
.orElseThrow(() -> new TranscriptionNotFound(id));
|
||||
transcriptionService.submitTranscriptionJob(transcription, jobId -> uriComponentsBuilder.cloneBuilder()
|
||||
.path("api")
|
||||
.pathSegment("transcriptions")
|
||||
.pathSegment(id)
|
||||
.pathSegment("job")
|
||||
.pathSegment("callback")
|
||||
.pathSegment(jobId.toString())
|
||||
.build()
|
||||
.toUri());
|
||||
return ResponseEntity.accepted().build();
|
||||
}
|
||||
|
||||
@PostMapping("/api/transcriptions/{id}/job/callback/{jobId}")
|
||||
public ResponseEntity<JobCallbackResponse> jobCallback(
|
||||
@PathVariable("id") String transcriptionId,
|
||||
@PathVariable("jobId") String jobId,
|
||||
@RequestBody JobCallbackResponse jobCallbackResponse)
|
||||
{
|
||||
return ResponseEntity.ok(jobCallbackResponse);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package se.su.dsv.whisperapi.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "result")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = JobCallbackResponse.Success.class, name = "Success"),
|
||||
@JsonSubTypes.Type(value = JobCallbackResponse.Failure.class, name = "Failure")
|
||||
})
|
||||
public sealed interface JobCallbackResponse {
|
||||
record Success(@JsonProperty("resultfile") String resultFileAbsolutePath) implements JobCallbackResponse {
|
||||
}
|
||||
|
||||
record Failure(@JsonProperty("errormessage") String errorMessage) implements JobCallbackResponse {
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package se.su.dsv.whisperapi.core;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface CallbackUriGenerator {
|
||||
URI generateCallbackUri(UUID jobId);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package se.su.dsv.whisperapi.core;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -10,4 +11,10 @@ public interface TransactionRepository {
|
||||
Optional<Transcription> findByOwnerAndId(Principal owner, UUID uuid);
|
||||
|
||||
void addFileToTranscription(Transcription transcription, String filename);
|
||||
|
||||
/**
|
||||
* @return the list of filenames that have been {@link #addFileToTranscription added}
|
||||
* to the transcription.
|
||||
*/
|
||||
List<String> getFiles(Transcription transcription);
|
||||
}
|
||||
|
@ -1,20 +1,29 @@
|
||||
package se.su.dsv.whisperapi.core;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TranscriptionService {
|
||||
private final TransactionRepository transactionRepository;
|
||||
private final Path fileDirectory;
|
||||
private final Path jobsDirectory;
|
||||
|
||||
public TranscriptionService(TransactionRepository transactionRepository, Path fileDirectory) {
|
||||
public TranscriptionService(TransactionRepository transactionRepository, Path fileDirectory, Path jobsDirectory) {
|
||||
this.transactionRepository = transactionRepository;
|
||||
this.fileDirectory = fileDirectory;
|
||||
this.jobsDirectory = jobsDirectory;
|
||||
}
|
||||
|
||||
|
||||
@ -45,4 +54,45 @@ public class TranscriptionService {
|
||||
transactionRepository.addFileToTranscription(transcription, file.filename());
|
||||
}
|
||||
}
|
||||
|
||||
public void submitTranscriptionJob(Transcription transcription, CallbackUriGenerator callbackUriGenerator) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
List<String> filenames = transactionRepository.getFiles(transcription);
|
||||
for (String filename : filenames) {
|
||||
UUID jobId = UUID.randomUUID();
|
||||
Path fileToBeTranscribed = fileDirectory.resolve(transcription.id().toString()).resolve(filename);
|
||||
Path jobFile = jobsDirectory.resolve(jobId + ".json");
|
||||
URI callbackUri = callbackUriGenerator.generateCallbackUri(jobId);
|
||||
|
||||
record Job(
|
||||
@JsonProperty("jobfile") String absolutePathToFileToBeTranscribed,
|
||||
@JsonProperty("outputformat") String outputFormat,
|
||||
@JsonProperty("origin") String origin,
|
||||
@JsonProperty("callback") String callbackUri)
|
||||
{
|
||||
}
|
||||
Job job = new Job(
|
||||
fileToBeTranscribed.toAbsolutePath().toString(),
|
||||
toWhisperFormat(transcription.outputFormat()),
|
||||
transcription.owner().getName(),
|
||||
callbackUri.toString());
|
||||
|
||||
try {
|
||||
objectMapper.writeValue(jobFile.toFile(), job);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String toWhisperFormat(OutputFormat outputFormat) {
|
||||
return switch (outputFormat) {
|
||||
case PLAIN_TEXT -> "text";
|
||||
case VTT -> "vtt";
|
||||
case SRT -> "srt";
|
||||
case TSV -> "tsv";
|
||||
case JSON -> "json";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -17,3 +17,4 @@ spring.mvc.problemdetails.enabled=true
|
||||
# that is correctly handled will be logged as a warning
|
||||
spring.mvc.log-resolved-exception=false
|
||||
whisper.frontend.transcription-files-directory=/tmp
|
||||
whisper.frontend.jobs-directory=/tmp
|
||||
|
Loading…
x
Reference in New Issue
Block a user