Flask code:
#!/usr/bin/python3
from flask import Flask, request, jsonify
import anyio
import asyncari
import logging
import aioudp
import os
import vosk
import array
import sys
import aiohttp
app = Flask(__name__)
ast_host = os.getenv("AST_HOST", '127.0.0.1')
ast_port = int(os.getenv("AST_ARI_PORT", 8088))
ast_url = os.getenv("AST_URL", 'http://%s:%d/'%(ast_host,ast_port))
ast_username = os.getenv("AST_USER", 'asterisk')
ast_password = os.getenv("AST_PASS", 'asterisk')
ast_app = os.getenv("AST_APP", 'v')
model = vosk.Model('vosk-model-pt-fb-v0.1.1-20220516_2113/')
channels = {}
class Channel:
async def rtp_handler(self, connection):
async for message in connection:
data = array.array('h', message[12:])
data.byteswap()
if self.rec.AcceptWaveform(data.tobytes()):
res = self.rec.Result()
else:
res = self.rec.PartialResult()
print(res)
async def init(self, client, channel):
self.port = 45000 + len(channels)
self.rec = vosk.KaldiRecognizer(model, 16000)
self.udp = aioudp.serve("127.0.0.1", self.port, self.rtp_handler)
await self.udp.__aenter__()
bridge = await client.bridges.create(type='mixing')
media_id = client.generate_id()
# Define uma variável global no Asterisk usando o endpoint /asterisk/variable
async with aiohttp.ClientSession() as session:
params = {
'variable': 'MEDIA_ID',
'value': media_id
}
async with session.post(
f"{ast_url}ari/asterisk/variable",
params=params,
auth=aiohttp.BasicAuth(ast_username, ast_password)
) as response:
if response.status != 204:
print(f"Failed to set global variable: {await response.text()}")
# Cria um canal de mídia externa
await client.channels.externalMedia(
channelId=media_id,
app=ast_app,
external_host='127.0.0.1:' + str(self.port),
format='slin16'
)
# Adiciona o canal espionado e o canal de mídia externa à ponte
await bridge.addChannel(channel=[media_id, channel.id])
async def create_channel_in_stasis(client, endpoint):
"""Cria um novo canal no contexto Stasis."""
channel = await client.channels.originate(
endpoint=endpoint,
app=ast_app,
appArgs=['stasis-start']
)
return channel
async def main(channel_id):
async with asyncari.connect(ast_url, ast_app, ast_username, ast_password) as client:
# Cria um canal espionado (snoop) do canal existente
snoop_channel = await client.channels.snoopChannel(
channelId=channel_id,
app=ast_app,
spy='in', # Espiona entrada e saída de áudio
whisper='none' # Não interfere no áudio original
)
# Inicializa o canal local para transcrição
local_channel = Channel()
await local_channel.init(client, snoop_channel)
channels[snoop_channel.id] = local_channel
# Mantém o script em execução para evitar que o aplicativo Stasis seja desativado
await anyio.sleep_forever()
@app.route('/start_transcription', methods=['POST'])
def start_transcription():
data = request.json
channel_id = data.get('channel_id')
if not channel_id:
return jsonify({"error": "channel_id is required"}), 400
logging.basicConfig(level=logging.DEBUG)
anyio.run(main, channel_id)
return jsonify({"status": "Transcription started", "channel_id": channel_id}), 200
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)