feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto - Configurado MCP server para Premiere Pro - Adicionado documentação e skills - Configurado Gitignore para o projeto
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import json
|
||||
import mimetypes
|
||||
import ssl
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
from urllib import request
|
||||
|
||||
from ...scanner.modelos import SegmentoDeTranscricao
|
||||
|
||||
|
||||
class ProviderDeTranscricaoGroq:
|
||||
"""Provider Groq compatível com o contrato de transcrição do scanner."""
|
||||
|
||||
endpoint = "https://api.groq.com/openai/v1/audio/transcriptions"
|
||||
|
||||
def __init__(self, api_key: str, modelo: str = "whisper-large-v3-turbo",
|
||||
idioma: str = "pt", tempo_limite: float = 120.0,
|
||||
requisicao: Callable[..., Any] | None = None) -> None:
|
||||
if not api_key.strip():
|
||||
raise ValueError("A chave da API Groq é obrigatória.")
|
||||
self.api_key = api_key.strip()
|
||||
self.modelo = modelo
|
||||
self.idioma = idioma
|
||||
self.tempo_limite = tempo_limite
|
||||
self._requisicao = requisicao or request.urlopen
|
||||
try:
|
||||
import certifi
|
||||
self._contexto_ssl = ssl.create_default_context(cafile=certifi.where())
|
||||
except ImportError:
|
||||
self._contexto_ssl = ssl.create_default_context()
|
||||
|
||||
def transcrever(self, clipe: Any) -> list[SegmentoDeTranscricao]:
|
||||
arquivo = getattr(clipe, "arquivo", None)
|
||||
if not arquivo:
|
||||
raise ValueError("O clipe não possui arquivo de origem para transcrição.")
|
||||
caminho = Path(arquivo)
|
||||
if not caminho.is_file():
|
||||
raise FileNotFoundError(f"Arquivo do clipe não encontrado: {caminho}")
|
||||
corpo, tipo = self._multipart(caminho)
|
||||
req = request.Request(self.endpoint, data=corpo, method="POST", headers={
|
||||
"Authorization": f"Bearer {self.api_key}",
|
||||
"Content-Type": tipo,
|
||||
})
|
||||
argumentos = {"timeout": self.tempo_limite}
|
||||
if self._requisicao is request.urlopen:
|
||||
argumentos["context"] = self._contexto_ssl
|
||||
with self._requisicao(req, **argumentos) as resposta:
|
||||
dados = json.loads(resposta.read().decode("utf-8"))
|
||||
return [SegmentoDeTranscricao(float(item["start"]), float(item["end"]),
|
||||
str(item.get("text", "")).strip(),
|
||||
None)
|
||||
for item in dados.get("segments", [])]
|
||||
|
||||
def _multipart(self, caminho: Path) -> tuple[bytes, str]:
|
||||
limite = "----engine-groq-" + uuid.uuid4().hex
|
||||
mime = mimetypes.guess_type(caminho.name)[0] or "application/octet-stream"
|
||||
partes: list[bytes] = []
|
||||
campos = {"model": self.modelo, "language": self.idioma,
|
||||
"response_format": "verbose_json", "timestamp_granularities[]": "segment"}
|
||||
for nome, valor in campos.items():
|
||||
partes.append(f"--{limite}\r\nContent-Disposition: form-data; name=\"{nome}\"\r\n\r\n{valor}\r\n".encode())
|
||||
partes.append(f"--{limite}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{caminho.name}\"\r\nContent-Type: {mime}\r\n\r\n".encode())
|
||||
partes.append(caminho.read_bytes())
|
||||
partes.append(f"\r\n--{limite}--\r\n".encode())
|
||||
return b"".join(partes), f"multipart/form-data; boundary={limite}"
|
||||
Reference in New Issue
Block a user