feat: criado repositório jhonny-editor no Gitea

criado repositório jhonny-editor no Gitea
adicionado script admin/deploy.command com commit automático
atualizado admin/DEV-NOTES.md com template limpo

Resumo:
- 48 arquivos alterados
- 26 novos
- 19 modificados
- 3 removidos

 22 files changed, 658 insertions(+), 568 deletions(-)

Arquivos:
  - AGENTS.md
  - admin/DEV-NOTES.md
  - admin/OpenCut.command
  - admin/commit.command
  - admin/deploy.command
  - admin/update.command
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/cep-plugin/styles.css
  - code/engine/ARQUITETURA.md
  - code/engine/arquitetura/README.md
  - code/engine/gerar_relatorio_timeline.py
  - code/engine/integracoes/apple_speech/apple_speech_transcriber.swift
  - code/engine/integracoes/apple_speech/provider_de_transcricao_apple.py
  - code/engine/integracoes/midia/__init__.py
  - code/engine/integracoes/whisper/provider_de_transcricao_local.py
  - code/engine/scanner/__init__.py
  - code/engine/scanner/coordenacao/__init__.py
  - code/engine/scanner/descoberta/__init__.py
  - code/engine/scanner/modelos.py
  - code/engine/scanner/transcricao_da_timeline.py
  - code/src/tools/discovery.ts
  - :memory:.ses
  - admin/Jhonny.command
  - admin/inativos/OpenCut.command
  - admin/inativos/update.command
  - code/docs/glossario-analise-emocional.md
  - code/docs/levantamento-apple-vision-e-apple-intelligence.md
  - code/docs/levantamento-ferramentas-analise-visual-local.md
  - code/engine/arquitetura/biblioteca-inteligente-de-videos.md
  - code/engine/executar_scanner.py
  - code/engine/integracoes/huggingface/
  - code/engine/integracoes/midia/extracao_de_metadados.py
  - code/engine/integracoes/visual/
  - code/engine/requirements-visual.txt
  - code/engine/scanner/configuracao_visual.py
  - code/engine/scanner/descoberta/descoberta_de_arquivos.py
  - code/engine/scanner/metadados.py
  - code/engine/scanner/relatorio_visual.py
  - code/engine/scanner/retakes/
  - code/engine/scanner/visual.py
  - code/engine/testes/test_analise_visual_local.py
  - code/engine/testes/test_arquivos_e_metadados.py
  - code/engine/testes/test_provider_de_transcricao_apple.py
  - code/relatorios/analise-brools/
  - code/relatorios/analise-visual/
  - code/relatorios/audio/arquivos/
  - code/relatorios/transcricao-timeline.md
This commit is contained in:
João Henrique
2026-09-08 16:13:27 -04:00
parent b541f502ba
commit b9bf3b2863
76 changed files with 16147 additions and 322 deletions
@@ -1,44 +1,82 @@
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
/// Encapsula o ciclo de vida do Apple Speech para a Engine.
///
/// A classe não conhece o scanner, o catálogo ou a persistência. Sua única
/// responsabilidade é converter um arquivo de mídia em JSON temporal. O
/// processo é Foundation-only para poder ser executado como CLI sem iniciar
/// AppKit ou NSApplication.
final class TranscritorDeFalaApple {
private let semaforo = DispatchSemaphore(value: 0)
private var payload: [String: Any] = ["segmentos": []]
private var codigoDeSaida: Int32 = 0
private var finalizado = false
func executar(argumentos: [String]) -> Int32 {
guard argumentos.count >= 3 else {
return finalizar("uso: apple-speech-transcriber arquivo locale [somente_no_dispositivo]", 2)
}
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)
let arquivo = URL(fileURLWithPath: argumentos[1])
let locale = Locale(identifier: argumentos[2])
let somenteNoDispositivo = argumentos.count > 3 && argumentos[3] == "true"
guard let recognizer = SFSpeechRecognizer(locale: locale), recognizer.isAvailable else {
return finalizar("Apple Speech indisponível para o locale solicitado", 3)
}
SFSpeechRecognizer.requestAuthorization { [weak self] status in
guard let self else { return }
guard status == .authorized else {
self.finalizar("Permissão do Apple Speech não concedida", 4)
return
}
let request = SFSpeechURLRecognitionRequest(url: arquivo)
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 {
if somenteNoDispositivo && recognizer.supportsOnDeviceRecognition {
request.requiresOnDeviceRecognition = true
}
recognizer.recognitionTask(with: request) { [weak self] resultado, erro in
guard let self else { return }
if let resultado, resultado.isFinal {
self.payload["segmentos"] = resultado.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)!)
self.finalizar(nil, 0)
} else if let erro {
self.finalizar("Falha no Apple Speech: \(erro.localizedDescription)", 5)
}
if error != nil || result?.isFinal == true { self.finalizar(nil, 0) }
}
}
semaforo.wait()
imprimirResultado()
return codigoDeSaida
}
private func finalizar(_ mensagem: String?, _ codigo: Int32) {
@discardableResult
private func finalizar(_ mensagem: String?, _ codigo: Int32) -> Int32 {
guard !finalizado else { return codigoDeSaida }
finalizado = true
if let mensagem { fputs(mensagem + "\n", stderr) }
NSApplication.shared.terminate(nil)
exit(codigo)
codigoDeSaida = codigo
semaforo.signal()
return codigo
}
private func imprimirResultado() {
guard let dados = try? JSONSerialization.data(withJSONObject: payload),
let texto = String(data: dados, encoding: .utf8) else {
fputs("Não foi possível serializar o resultado do Apple Speech\n", stderr)
codigoDeSaida = 6
return
}
print(texto)
}
}
let app = NSApplication.shared
let delegate = AppDelegate()
app.delegate = delegate
app.setActivationPolicy(.accessory)
app.run()
let transcritor = TranscritorDeFalaApple()
exit(transcritor.executar(argumentos: CommandLine.arguments))
@@ -7,10 +7,10 @@ from ...scanner.modelos import SegmentoDeTranscricao
class ProviderDeTranscricaoApple:
"""Provider nativo macOS Speech; o áudio não passa por API Groq."""
"""Provider nativo macOS Speech, local por padrão e sem AppKit."""
def __init__(self, executavel: str = "/private/tmp/AppleSpeechTranscriber.app/Contents/MacOS/apple-speech-transcriber", locale: str = "pt-BR",
somente_no_dispositivo: bool = False) -> None:
somente_no_dispositivo: bool = True) -> None:
self.executavel = executavel
self.locale = locale
self.somente_no_dispositivo = somente_no_dispositivo
@@ -24,5 +24,5 @@ class ProviderDeTranscricaoApple:
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"))
return [SegmentoDeTranscricao(float(s["inicio"]), float(s["fim"]), str(s["texto"]).strip(), s.get("confianca"))
for s in dados.get("segmentos", [])]