import gradio as gr
import requests
import base64
import json
import os
from typing import Dict, Any
from pydub import AudioSegment
#---------------------------------------------------------------------------------------------------------------------------------
def read_audio_file(file_path: str) -> bytes:
"""
Reads an audio file from the specified file path.
Args:
file_path (str): The path to the audio file.
Returns:
bytes: The content of the audio file.
Raises:
IOError: If there is an error reading the audio file.
"""
try:
with open(file_path, "rb") as audio_file:
return audio_file.read()
except IOError as e:
raise IOError(f"Erreur de lecture du fichier audio : {e}")
#---------------------------------------------------------------------------------------------------------------------------------
def prepare_config(diarization: bool = False, word_time_offsets: bool = False) -> Dict[str, Any]:
"""
Prepares the configuration for the audio transcription.
Args:
diarization (bool): Whether to add speaker diarization to the configuration.
word_time_offsets (bool): Whether to enable word time offsets in the configuration.
Returns:
Dict[str, Any]: The prepared configuration.
"""
return {
"add_speaker_diarization_to_config": diarization,
"enable_word_time_offsets": word_time_offsets,
"add_word_boosting_to_config": None,
}
#---------------------------------------------------------------------------------------------------------------------------------
def transcribe_audio(url: str, api_key: str, audio_content: bytes, config: Dict[str, Any]) -> Dict[str, Any]:
"""
Sends a request to the API to transcribe the audio content.
Args:
url (str): The API endpoint URL.
api_key (str): The API key for authentication.
audio_content (bytes): The audio content to be transcribed.
config (Dict[str, Any]): The configuration for the transcription.
Returns:
Dict[str, Any]: The transcription result.
Raises:
Exception: If there is an error during the API request.
"""
headers = {"X-Ovh-Application": api_key}
config_json = json.dumps(config)
files = {
'audio': ('audio.wav', audio_content, 'audio/wav'),
'config': ('config.json', config_json, 'application/json')
}
try:
response = requests.post(url, files=files, headers=headers)
response.raise_for_status() # Raise an exception for bad status codes
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"Erreur lors de la requête à l'API : {e}")
#---------------------------------------------------------------------------------------------------------------------------------
def process_transcription(transcription: Dict[str, Any]) -> str:
"""
Processes the transcription result and returns a concatenated transcript.
Args:
transcription (Dict[str, Any]): The transcription result.
Returns:
str: The concatenated transcript.
"""
full_transcript = ""
for sentence in transcription:
for alternative in sentence["alternatives"]:
full_transcript += alternative["transcript"] + " "
return full_transcript.strip()
#---------------------------------------------------------------------------------------------------------------------------------
def summary(content: str, context: str, choice: str) -> str:
"""
Generates a summary for the given content using the specified language model.
Args:
content (str): The content to be summarized.
choice (str): The language model choice.
Returns:
str: The generated summary.
Raises:
Exception: If there is an error during the API request.
"""
if choice == "Llama-3-70B-Instruct":
url = "https://llama-3-70b-instruct.endpoints.kepler.ai.cloud.ovh.net/api/openai_compat/v1/chat/completions"
model="Meta-Llama-3-70B-Instruct"
elif choice == "Llama-3-8B-Instruct":
url = "https://Llama-3-8B-Instruct.endpoints.kepler.ai.cloud.ovh.net/api/openai_compat/v1/chat/completions"
model="Meta-Llama-3-8B-Instruct"
elif choice == "Mistral-7B-Instruct":
url = "https://Mistral-7B-Instruct-v02.endpoints.kepler.ai.cloud.ovh.net/api/openai_compat/v1/chat/completions"
model="Mistral-7B-Instruct-v0.2"
elif choice == "Mixtral-8x22b-Instruct":
url = "https://Mixtral-8x22B-Instruct-v01.endpoints.kepler.ai.cloud.ovh.net/api/openai_compat/v1/chat/completions"
model="Mixtral-8x22B-Instruct-v0.1"
elif choice == "Mixtral-8x7b-instruct":
url = "https://mixtral-8x7b-instruct-v01.endpoints.kepler.ai.cloud.ovh.net/api/openai_compat/v1/chat/completions"
model="Mixtral-8x7B-Instruct-v0.1"
else:
url = "https://llama-3-70b-instruct.endpoints.kepler.ai.cloud.ovh.net/api/openai_compat/v1/chat/completions"
model="Meta-Llama-3-70B-Instruct"
prompt = f"""
Vous êtes mon assistant et votre seule mission est de me fournir un résumé du texte situé entre <>.
Le texte supplémentaire présent entre ## (s'il n'est pas vide) fournit des éléments de contexte à ce texte.
Veuillez fournir votre réponse en français uniquement, avec une longueur maximale de 5 phrases.
Texte : <{content}>
Contexte : #{context}#
"""
payload = {
"max_tokens": 512,
"messages": [
{
"content": prompt,
"name": "User",
"role": "user"
}
],
"model": model,
"temperature": 0,
}
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {os.getenv('OVH_API_KEY')}",
}
response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200:
response_data = response.json()
choices = response_data["choices"]
for choice in choices:
return choice["message"]["content"]
else:
return f"Error: {response.status_code}"
#---------------------------------------------------------------------------------------------------------------------------------
def choose_language(choice: str) -> str:
"""
Returns the appropriate API URL based on the selected language.
Args:
choice (str): The language choice.
Returns:
str: The API URL for the selected language.
"""
languages = {
"fr": "https://nvr-asr-fr-fr.endpoints.kepler.ai.cloud.ovh.net/api/v1/asr/recognize",
"en": "https://nvr-asr-en-gb.endpoints.kepler.ai.cloud.ovh.net/api/v1/asr/recognize",
"en/us": "https://nvr-asr-en-us.endpoints.kepler.ai.cloud.ovh.net/api/v1/asr/recognize",
"de": "https://nvr-asr-de-de.endpoints.kepler.ai.cloud.ovh.net/api/v1/asr/recognize",
"es": "https://nvr-asr-es-es.endpoints.kepler.ai.cloud.ovh.net/api/v1/asr/recognize",
"it": "https://nvr-asr-it-it.endpoints.kepler.ai.cloud.ovh.net/api/v1/asr/recognize"
}
return languages.get(choice, "https://nvr-asr-fr-fr.endpoints.kepler.ai.cloud.ovh.net/api/v1/asr/recognize")
#---------------------------------------------------------------------------------------------------------------------------------
def convert_audio_to_16000hz(input_file: str) -> str:
"""
Converts the given audio file to 16000 Hz and returns the path to the converted file.
Args:
input_file (str): The path to the input audio file.
Returns:
str: The path to the converted audio file.
Raises:
Exception: If there is an error during the conversion.
"""
try:
audio = AudioSegment.from_file(input_file)
audio = audio.set_channels(1).set_frame_rate(16000)
output_file = "processed_audio.wav"
audio.export(output_file, format="wav")
return output_file
except Exception as e:
raise Exception(f"Erreur lors de la conversion du fichier audio : {e}")
#---------------------------------------------------------------------------------------------------------------------------------
def transcribe_and_summarize(audio_file, language_choice, llm_choice, context):
"""
Transcribes the audio file and summarizes the transcription using the specified language model.
Args:
audio_file: The path to the audio file.
language_choice: The selected language for transcription.
llm_choice: The selected language model for summarization.
Returns:
tuple: The transcription and the summary.
Raises:
Exception: If there is an error during the process.
"""
try:
api_key = os.environ.get("OVH_API_KEY", "") # Utiliser une variable d'environnement pour la clé API
processed_audio = convert_audio_to_16000hz(audio_file)
audio_content = read_audio_file(processed_audio)
url = choose_language(language_choice)
config = prepare_config()
transcription = transcribe_audio(url, api_key, audio_content, config)
result = process_transcription(transcription)
summary_result = summary(content=result, context=context, choice=llm_choice)
return result, summary_result[:-10]
except Exception as e:
return f"Une erreur est survenue : {e}", ""
#---------------------------------------------------------------------------------------------------------------------------------
# Gradio Interface
def process_input(choice, audio_file=None, text_input=None, lang_choice=None, llm_choice=None, context_input=None):
"""
Processes the input based on the user's choice (Audio or Text).
Args:
choice: The type of input (Audio or Text).
audio_file: The audio file input.
text_input: The text input.
lang_choice: The language choice for audio transcription.
llm_choice: The language model choice for summarization.
Returns:
tuple: The transcription (if audio) and the summary.
"""
max_chars = 200
if len(context_input) > max_chars:
return "", "Le contexte ne peut pas excéder 200 caractères."
else :
if choice == "Audio":
if audio_file is not None:
return transcribe_and_summarize(audio_file, lang_choice, llm_choice, context=context_input,)
return "Veuillez fournir une piste audio", ""
elif choice == "Texte":
summary_result = summary(content=text_input, context=context_input, choice=llm_choice)
return "", summary_result[:-10]
else:
return "Choix invalide", ""
#---------------------------------------------------------------------------------------------------------------------------------
language_choices = ["fr", "en", "en/us", "de", "es", "it"]
llm_choices = ["Llama-3-70B-Instruct", "Llama-3-8B-Instruct", "Mistral-7B-Instruct", "Mixtral-8x22b-Instruct", "Mixtral-8x7b-instruct"]
#---------------------------------------------------------------------------------------------------------------------------------
with gr.Blocks() as iface:
choice_input = gr.Radio(choices=["Audio", "Texte"], label="Type d'entrée")
audio_input = gr.Audio(sources=["microphone", "upload"], type="filepath", visible=False, label="Source audio")
text_input = gr.Textbox(lines=5, placeholder="Entrez le texte ici...", visible=False, label='Source texte')
lang_dropdown = gr.Dropdown(value=language_choices[0], choices=language_choices, label="Choisissez la langue de l'audio", visible=False)
llm_dropdown = gr.Dropdown(value=llm_choices[0], choices=llm_choices, label="Choisissez le LLM pour effectuer le résumé", visible=False)
context_input = gr.Textbox(lines=8, placeholder="Entrez le contexte ici (optionnel).\n\nExemples :\nIl s'agit d'un appel téléphonique professionnel entre...\nIl s'agit d'une émission de radio qui parle de...\nCe texte scientifique parle de...\n\nTaille du contexte limitée à 200 caractères", visible=False, label="Contexte du contenu")
transcription_output = gr.Textbox(label="Transcription", visible=False)
summary_output = gr.Textbox(label="Résumé", visible=False)
def update_visibility(choice):
if choice == "Audio":
return gr.update(value=None, visible=True), gr.update(visible=False), gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(value="", visible=True)
elif choice == "Texte":
return gr.update(visible=False), gr.update(value="", visible=True), gr.update(visible=False), gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), gr.update(value="", visible=True)
else:
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
choice_input.change(fn=update_visibility, inputs=choice_input, outputs=[audio_input, text_input, lang_dropdown, llm_dropdown, context_input, transcription_output, summary_output])
gr.Interface(
fn=process_input,
inputs=[
choice_input,
audio_input,
text_input,
lang_dropdown,
llm_dropdown,
context_input
],
outputs=[
transcription_output,
summary_output
],
title="""
Créer un résumé à partir d'un texte ou d'un enregistrement audio
Utilisation des AI Endpoints d'OVHcloud
Codé par Emmanuel Mancuso👋🏼
""",
description="""
Téléchargez un fichier audio 🔊 ou entrez un texte 📃
choisissez la langue pour l'audio
choisissez le modèle de LLM pour obtenir le résumé 🚀
""",
allow_flagging='never'
)
#---------------------------------------------------------------------------------------------------------------------------------
iface.launch()