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,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>apple-speech-transcriber</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.genialsistemas.apple-speech-transcriber</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Apple Speech Transcriber</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>NSSpeechRecognitionUsageDescription</key>
|
||||
<string>O scanner precisa reconhecer a fala dos clipes da timeline para gerar a transcrição.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,3 @@
|
||||
from .provider_de_transcricao_apple import ProviderDeTranscricaoApple
|
||||
|
||||
__all__ = ["ProviderDeTranscricaoApple"]
|
||||
@@ -0,0 +1,44 @@
|
||||
import AppKit
|
||||
import Foundation
|
||||
import Speech
|
||||
|
||||
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
guard CommandLine.arguments.count >= 3 else { finalizar("uso: arquivo locale [somente_no_dispositivo]", 2); return }
|
||||
let url = URL(fileURLWithPath: CommandLine.arguments[1])
|
||||
let locale = Locale(identifier: CommandLine.arguments[2])
|
||||
let somenteNoDispositivo = CommandLine.arguments.count > 3 && CommandLine.arguments[3] == "true"
|
||||
guard let recognizer = SFSpeechRecognizer(locale: locale), recognizer.isAvailable else {
|
||||
finalizar("Apple Speech indisponível para o locale solicitado", 3); return
|
||||
}
|
||||
SFSpeechRecognizer.requestAuthorization { status in
|
||||
guard status == .authorized else { self.finalizar("Permissão do Apple Speech não concedida", 4); return }
|
||||
let request = SFSpeechURLRecognitionRequest(url: url)
|
||||
request.shouldReportPartialResults = false
|
||||
if somenteNoDispositivo && recognizer.supportsOnDeviceRecognition { request.requiresOnDeviceRecognition = true }
|
||||
recognizer.recognitionTask(with: request) { result, error in
|
||||
if let result = result, result.isFinal {
|
||||
let segmentos = result.bestTranscription.segments.map {
|
||||
["inicio": $0.timestamp, "fim": $0.timestamp + $0.duration,
|
||||
"texto": $0.substring, "confianca": $0.confidence] as [String: Any]
|
||||
}
|
||||
let data = try! JSONSerialization.data(withJSONObject: ["segmentos": segmentos])
|
||||
print(String(data: data, encoding: .utf8)!)
|
||||
}
|
||||
if error != nil || result?.isFinal == true { self.finalizar(nil, 0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func finalizar(_ mensagem: String?, _ codigo: Int32) {
|
||||
if let mensagem { fputs(mensagem + "\n", stderr) }
|
||||
NSApplication.shared.terminate(nil)
|
||||
exit(codigo)
|
||||
}
|
||||
}
|
||||
|
||||
let app = NSApplication.shared
|
||||
let delegate = AppDelegate()
|
||||
app.delegate = delegate
|
||||
app.setActivationPolicy(.accessory)
|
||||
app.run()
|
||||
@@ -0,0 +1,28 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
from typing import Any
|
||||
|
||||
from ...scanner.modelos import SegmentoDeTranscricao
|
||||
|
||||
|
||||
class ProviderDeTranscricaoApple:
|
||||
"""Provider nativo macOS Speech; o áudio não passa por API Groq."""
|
||||
|
||||
def __init__(self, executavel: str = "/private/tmp/AppleSpeechTranscriber.app/Contents/MacOS/apple-speech-transcriber", locale: str = "pt-BR",
|
||||
somente_no_dispositivo: bool = False) -> None:
|
||||
self.executavel = executavel
|
||||
self.locale = locale
|
||||
self.somente_no_dispositivo = somente_no_dispositivo
|
||||
|
||||
def transcrever(self, clipe: Any) -> list[SegmentoDeTranscricao]:
|
||||
arquivo = Path(clipe.arquivo)
|
||||
if not arquivo.is_file():
|
||||
raise FileNotFoundError(f"Arquivo de áudio não encontrado: {arquivo}")
|
||||
resultado = subprocess.run(
|
||||
[self.executavel, str(arquivo), self.locale, str(self.somente_no_dispositivo).lower()],
|
||||
check=True, capture_output=True, text=True,
|
||||
)
|
||||
dados = json.loads(resultado.stdout)
|
||||
return [SegmentoDeTranscricao(float(s["inicio"]), float(s["fim"]), str(s["texto"]), s.get("confianca"))
|
||||
for s in dados.get("segmentos", [])]
|
||||
Reference in New Issue
Block a user