File size: 5,085 Bytes
ff30a18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import gradio as gr
import torch
import torchaudio
import librosa
import os
from transformers import AutoProcessor, AutoModelForSpeechSeq2Seq
from huggingface_hub import login
import logging

# Configuration
MODEL_NAME = "Ronaldodev/speech-to-text-fongbe"
HF_TOKEN = os.environ.get("HF_TOKEN")

# Variables globales
model = None
processor = None

# Configuration logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def load_model():
    """Charger le modèle privé au démarrage"""
    global model, processor

    try:
        logger.info("🔄 Chargement du modèle privé...")

        if not HF_TOKEN:
            raise ValueError("HF_TOKEN non configuré dans les secrets")

        # Login avec token privé
        login(token=HF_TOKEN)
        logger.info("✅ Authentification HF réussie")

        # Charger le modèle et processeur
        model = AutoModelForSpeechSeq2Seq.from_pretrained(MODEL_NAME)
        processor = AutoProcessor.from_pretrained(MODEL_NAME)

        logger.info("✅ Modèle chargé avec succès!")
        return True

    except Exception as e:
        logger.error(f"❌ Erreur chargement: {e}")
        return False


def transcribe(audio):
    """Fonction principale de transcription"""

    # Vérifier si le modèle est chargé
    if model is None or processor is None:
        return "❌ Erreur: Modèle non chargé. Vérifiez les logs."

    # Vérifier si un audio est fourni
    if audio is None:
        return "❌ Aucun fichier audio fourni"

    try:
        logger.info(f"🎵 Traitement audio: {audio}")

        # Charger l'audio avec fallback
        try:
            waveform, sample_rate = torchaudio.load(audio)
            logger.info(f"✅ Audio chargé avec torchaudio: {sample_rate}Hz")
        except Exception as e:
            logger.warning(f"⚠️ Torchaudio échoué, essai librosa: {e}")
            waveform, sample_rate = librosa.load(audio, sr=None)
            waveform = torch.tensor(waveform).unsqueeze(0)
            logger.info(f"✅ Audio chargé avec librosa: {sample_rate}Hz")

        # Conversion mono si nécessaire
        if waveform.shape[0] > 1:
            waveform = waveform.mean(dim=0, keepdim=True)
            logger.info("🔄 Conversion stéréo → mono")

        # Resampling à 16kHz si nécessaire
        if sample_rate != 16000:
            logger.info(f"🔄 Resampling {sample_rate}Hz → 16000Hz")
            resampler = torchaudio.transforms.Resample(sample_rate, 16000)
            waveform = resampler(waveform)

        # Préparation des inputs
        inputs = processor(
            waveform.squeeze(),
            sampling_rate=16000,
            return_tensors="pt"
        )

        # Génération de la transcription
        logger.info("🔄 Génération de la transcription...")
        with torch.no_grad():
            result = model.generate(
                **inputs,
                max_length=500,
                do_sample=False,
                num_beams=1
            )

        # Décodage
        transcription = processor.batch_decode(result, skip_special_tokens=True)[0]

        logger.info(f"✅ Transcription réussie: '{transcription}'")
        return transcription.strip()

    except Exception as e:
        error_msg = f"❌ Erreur de transcription: {str(e)}"
        logger.error(error_msg)
        return error_msg


# Charger le modèle au démarrage
print("🚀 DÉMARRAGE API STT FONGBÉ - RONALDODEV")
print("=" * 50)

if load_model():
    print("✅ Modèle chargé - Interface prête!")
    model_status = "✅ Modèle chargé et prêt"
else:
    print("❌ Erreur de chargement du modèle")
    model_status = "❌ Erreur de chargement"

# Interface Gradio simple
demo = gr.Interface(
    fn=transcribe,
    inputs=gr.Audio(
        sources=["upload", "microphone"],
        type="filepath",
        label="🎤 Uploadez un fichier ou enregistrez directement"
    ),
    outputs=gr.Textbox(
        label="📝 Transcription en Fongbé",
        placeholder="La transcription apparaîtra ici...",
        lines=3
    ),
    title="🎤 API STT Fongbé - Ronaldodev",
    description=f"""
    **Reconnaissance vocale pour la langue Fongbé**

    Uploadez un fichier audio (WAV, MP3, M4A) ou enregistrez directement avec votre microphone.

    **Statut:** {model_status}

    **Modèle:** `{MODEL_NAME}`
    """,
    article="""
    ## 🔌 API pour développeurs

    Cette interface expose automatiquement une API REST :

    **Endpoint:** `POST /api/predict`

    **Exemple d'utilisation:**
    ```python
    import requests

    response = requests.post(
        "https://ronaldodev-stt-fongbe.hf.space/api/predict",
        json={"data": [audio_file_path]}
    )

    transcription = response.json()["data"][0]
    ```

    **Pour Flutter:** Utilisez MultipartRequest avec l'endpoint ci-dessus.
    """,
    examples=[
        # Vous pouvez ajouter des fichiers d'exemple si vous en avez
    ],
    theme=gr.themes.Soft(),
    allow_flagging="never"
)

# Lancement de l'interface
demo.launch()