elevenlabs_field-1.0.0-beta7/src/ElevenLabsGenerateService.php
src/ElevenLabsGenerateService.php
<?php
namespace Drupal\elevenlabs_field;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Utility\Token;
use Drupal\file\FileRepositoryInterface;
/**
* Takes care of the Generating files from ElevenLabs.
*/
class ElevenLabsGenerateService {
/**
* The file system interface.
*/
protected FileSystemInterface $fileSystem;
/**
* The api interface.
*/
protected ElevenLabsApiService $api;
/**
* The entity type manager.
*/
protected EntityTypeManagerInterface $entityType;
/**
* The file repository.
*/
protected FileRepositoryInterface $fileRepo;
/**
* The token system.
*/
protected Token $token;
/**
* The models.
*/
protected array $models = [];
/**
* Construtor of ElevenLabs Generator Service.
*
* @param \Drupal\Core\File\FileSystemInterface $fileSystem
* The file system interface.
* @param \Drupal\elevenlabs_field\ElevenLabsApiService $api
* The ElevenLabs API interface.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityType
* The Entity Type manager interface.
* @param \Drupal\file\FileRepositoryInterface $fileRepo
* The file repository.
* @param \Drupal\Core\Utility\Token $token
* The token service.
*/
public function __construct(FileSystemInterface $fileSystem, ElevenLabsApiService $api, EntityTypeManagerInterface $entityType, FileRepositoryInterface $fileRepo, Token $token) {
$this->fileSystem = $fileSystem;
$this->api = $api;
$this->entityType = $entityType;
$this->fileRepo = $fileRepo;
$this->models = $this->api->getModels();
$this->token = $token;
}
/**
* Generate files.
*
* @param string $text
* The text to create for.
* @param string $speaker
* The speaker to create for.
* @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
* The field definition.
* @param string $model
* The model to create with.
* @param array $options
* The extra options.
*
* @return array
* An array of file and history id.
*/
public function generateFile($text, $speaker, FieldDefinitionInterface $fieldDefinition, $model, $options = []) {
$return = [];
$filePath = $this->getFilePath($fieldDefinition);
$audioData = $this->api->textToSpeech($text, $speaker, $model, $options);
if (is_string($audioData)) {
// Remove old data if exists.
$file = $this->generateAudio($audioData, $filePath);
// Elevenlabs is not consistent with writes.
sleep(1);
$historyId = $this->findHistoryId($text, $speaker);
if ($historyId && $file) {
$return = [
'file' => $file,
'history_item_id' => $historyId,
];
}
}
return $return;
}
/**
* Gets the file path.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
* The field definition interface.
*
* @return string
* The path.
*/
public function getFilePath(FieldDefinitionInterface $fieldDefinition) {
$settings = $fieldDefinition->getSettings();
$path = $settings['uri_scheme'] ?? 'public';
$path .= '://' . rtrim($this->token->replace($settings['file_directory']), '/');
$path .= '/' . $this->token->replace($settings['file_name'] ?? 'elevenlabs') . '.mp3';
return $path;
}
/**
* Get the wanted model.
*
* @param string $modelName
* The model or auto.
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The entity.
*
* @return string
* The model.
*/
public function validateModel($modelName, ContentEntityInterface $entity) {
// Only change if model is auto.
if ($modelName == 'auto') {
$modelName = ElevenLabsApiService::$defaultModel;
$langCode = $entity->get('langcode')->value ?? NULL;
if ($langCode) {
foreach ($this->models as $model) {
if (array_search($langCode, array_column($model['languages'], 'language_id'), TRUE)) {
return $model['model_id'];
}
}
}
}
return $modelName;
}
/**
* Remove old file.
*
* @param int $id
* The file to remove.
*/
public function removeFile($id) {
if ($id) {
$file = $this->entityType->getStorage('file')->load($id);
$file ? $file->delete() : NULL;
}
}
/**
* Generate Audio file.
*
* @param string $audioData
* Binary.
* @param string $filePath
* Path to store.
*
* @return \Drupal\file\Entity\File
* A file entity.
*/
private function generateAudio($audioData, $filePath) {
$dir = substr($filePath, 0, -(strlen(basename($filePath))));
$this->fileSystem->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
$file = $this->fileRepo->writeData($audioData, $filePath, FileSystemInterface::EXISTS_RENAME);
return $file;
}
/**
* Find the history Id.
*
* @param string $text
* The text to search for.
* @param string $speaker
* The speaker to search for.
*
* @return string
* The history item id.
*/
private function findHistoryId($text, $speaker) {
$history = $this->api->getHistoryListing();
if (is_array($history)) {
foreach ($history['history'] as $historyItem) {
if ($historyItem['text'] == $text && $historyItem['voice_id'] == $speaker) {
return $historyItem['history_item_id'];
}
}
}
}
}
