docs(readme): redesenha o README com hero em SVG [skip ci]
This commit is contained in:
1 parent
2c573a49ea
commit
0e9843c54a
2 files changed
+142
-136
No files matched your search
@@ -1,171 +1,112 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
<h1>Transcript Desktop</h1>
|
<img src="assets/readme/hero.svg" width="100%" alt="Transcript: ditado local para Windows e Linux. Atalho Ctrl+Shift+Space, gravação e o editor Texto transcrito com os botões Copiar e Inserir">
|
||||||
|
|
||||||
<p><strong>Ditado offline para Windows e Linux: grave com um atalho global, revise o texto e cole no app em foco.</strong></p>
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
<a href="#-quickstart">Quickstart</a> ·
|
[Issues](https://git.evandro.dev.br/evandro/transcript/issues) · [Specs](docs/superpowers/specs/) · [Planos](docs/superpowers/plans/)
|
||||||
<a href="#-arquitetura">Arquitetura</a> ·
|
|
||||||
<a href="#-documentação">Documentação</a> ·
|
|
||||||
<a href="https://git.evandro.dev.br/evandro/transcript/issues">Issues</a>
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
## O que é
|
||||||
|
|
||||||
## 📌 O problema
|
Transcript é um app de bandeja para Windows e Linux, feito com Tauri 2. Você aperta um atalho global, fala, e o texto transcrito localmente aparece num editor para revisão antes de ser colado no aplicativo em foco.
|
||||||
|
|
||||||
Ditar texto em qualquer aplicativo do desktop exige gravar, transcrever e colar o resultado por conta própria, e boa parte das opções depende de serviço online. O Transcript fica residente na bandeja, grava por atalho global, transcreve localmente e deixa o texto editável antes de inseri-lo no aplicativo em foco.
|
|
||||||
|
|
||||||
## ✨ O que faz
|
|
||||||
|
|
||||||
- Alterna a gravação com o atalho global `Ctrl+Shift+Space` (evento `transcript://toggle-recording` para o frontend).
|
- Alterna a gravação com o atalho global `Ctrl+Shift+Space` (evento `transcript://toggle-recording` para o frontend).
|
||||||
- Captura o microfone em WAV (cpal + hound) na pasta de dados do app.
|
- Grava o microfone em WAV (`cpal` + `hound`) na pasta de dados do app.
|
||||||
- Transcreve localmente chamando o sidecar `sherpa-onnx-offline` com o modelo Parakeet TDT 0.6B int8 e guarda um diagnóstico de cada tentativa (etapa, exit code, final de stdout/stderr).
|
- Transcreve chamando o sidecar `sherpa-onnx-offline` com o modelo Parakeet TDT 0.6B int8 e guarda um diagnóstico de cada tentativa (etapa, exit code, final de stdout/stderr).
|
||||||
- Inclui adaptadores para o sidecar CrispASR (modelo GGUF legado) e para APIs compatíveis com OpenAI.
|
- Mostra o texto num editor, com os botões Copiar e Inserir.
|
||||||
- Mostra o texto num editor, com os botões Copiar e Inserir, para revisar antes de colar.
|
- Mantém um ícone na bandeja com o menu Mostrar app, Iniciar gravação e Sair.
|
||||||
- Cola no app em foco: copia para o clipboard e aciona `Ctrl+V` (PowerShell no Windows, `xdotool` no X11).
|
|
||||||
- Mantém ícone na bandeja com o menu Mostrar app, Iniciar gravação e Sair; o clique esquerdo mostra a janela.
|
|
||||||
- Lista o catálogo de modelos com status e baixa o modelo padrão.
|
- Lista o catálogo de modelos com status e baixa o modelo padrão.
|
||||||
|
|
||||||
## 🚀 Quickstart
|
## Por que usar
|
||||||
|
|
||||||
| Ferramenta | Versão |
|
A transcrição roda na sua máquina: o comando que encerra a gravação chama o `sherpa-onnx-offline` local, sem serviço online no caminho. O texto só vai para o app em foco depois que você revisa e clica em Inserir, que copia para o clipboard e manda `Ctrl+V`.
|
||||||
|---|---|
|
|
||||||
| Node.js + npm | 22 (usada nos workflows; não há `.nvmrc` nem `engines`) |
|
Não use ainda se você precisa de um ditado que funcione hoje: o código atual não compila (veja [Estado do projeto](#estado-do-projeto)). Também não há colagem automática no Wayland nem no macOS, e o atalho é fixo.
|
||||||
| Rust (cargo) | `stable`, edition 2021 (workflows usam `dtolnay/rust-toolchain@stable`) |
|
|
||||||
| Tauri CLI | `^2.9.0` (devDependency) |
|
## Como funciona
|
||||||
| Linux (build) | `libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libasound2-dev` |
|
|
||||||
| Linux X11 (colar) | `xdotool`, opcional |
|
- O atalho emite um evento que o frontend escuta para iniciar ou parar a gravação.
|
||||||
| `tar` com bzip2 | usado por `scripts/setup-fixtures.mjs` |
|
- Ao parar, `stop_recording_and_transcribe` fecha o WAV, roda o sidecar (de 1 a 4 threads) e devolve o texto num snapshot para o editor.
|
||||||
|
- Só depois da revisão o botão Inserir chama `request_insert_text`, que copia o texto e tenta colar.
|
||||||
|
- O código também tem adaptadores para o sidecar CrispASR (modelo GGUF legado) e para APIs compatíveis com OpenAI (padrão `http://localhost:8022/v1/audio/transcriptions`), mas nenhum comando os usa hoje.
|
||||||
|
|
||||||
|
| Sistema | Inserção no app em foco | Fallback |
|
||||||
|
|---|---|---|
|
||||||
|
| Windows | Clipboard + `Ctrl+V` via PowerShell `SendKeys` | Se o `Ctrl+V` falhar, o texto fica copiado e uma mensagem avisa. |
|
||||||
|
| Linux X11 | Clipboard + `xdotool key --clearmodifiers ctrl+v` | Sem `xdotool`, o texto fica copiado para colar à mão. |
|
||||||
|
| Linux Wayland | Só copia | Cole com `Ctrl+V`. |
|
||||||
|
|
||||||
|
A sessão é detectada por `XDG_SESSION_TYPE`, `WAYLAND_DISPLAY` e `DISPLAY`.
|
||||||
|
|
||||||
|
| Modelo | Formato | Tamanho no catálogo | Idiomas | Uso |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8` | tarball `.tar.bz2` do release `asr-models` do k2-fsa/sherpa-onnx | ~640 MB | 25 idiomas europeus, incluindo `pt` | Padrão |
|
||||||
|
| `parakeet-tdt-0.6b-v3-q8_0` | GGUF `Q8_0`, repositório `cstr/parakeet-tdt-0.6b-v3-GGUF` | 745121600 bytes | `pt`, `en` | Legado, para o adaptador CrispASR |
|
||||||
|
|
||||||
|
## Início rápido
|
||||||
|
|
||||||
|
| Ferramenta | Versão | Observação |
|
||||||
|
|---|---|---|
|
||||||
|
| Node.js + npm | 22 | Versão usada nos workflows; não há `.nvmrc` nem `engines`. |
|
||||||
|
| Rust (cargo) | stable, edition 2021 | Os workflows usam `dtolnay/rust-toolchain@stable`. |
|
||||||
|
| Tauri CLI | `^2.9.0` | devDependency, vem com `npm ci`. |
|
||||||
|
| Linux (build) | `libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libasound2-dev` | Pacotes instalados no CI. |
|
||||||
|
| Linux X11 (colar) | `xdotool` | Opcional. |
|
||||||
|
| `tar` com bzip2 | qualquer | Usado por `scripts/setup-fixtures.mjs`. |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
git clone https://git.evandro.dev.br/evandro/transcript.git
|
||||||
|
cd transcript
|
||||||
npm ci
|
npm ci
|
||||||
node scripts/setup-sidecar.mjs # baixa sherpa-onnx-offline para src-tauri/binaries/
|
node scripts/setup-sidecar.mjs # baixa o sherpa-onnx-offline para src-tauri/binaries/
|
||||||
npm run tauri:dev # app em desenvolvimento (Vite em 127.0.0.1:1420)
|
npm run tauri:dev # app em desenvolvimento (Vite em 127.0.0.1:1420)
|
||||||
npm run tauri:build # bundles em src-tauri/target/release/bundle/
|
npm run tauri:build # bundles em src-tauri/target/release/bundle/
|
||||||
```
|
```
|
||||||
|
|
||||||
O modelo não vai no instalador: o app o baixa para a pasta de dados (`%LOCALAPPDATA%\transcript\models` no Windows, `~/.local/share/transcript/models` no Linux) pelo comando Tauri `download_default_model_command`. As gravações ficam em `recordings/` na mesma pasta.
|
Hoje os dois comandos `tauri:*` param na compilação do Rust. O front end sozinho roda com `npm run dev`, e os testes dele com `npm test -- --run`.
|
||||||
|
|
||||||
Não há `.env.example` e nenhuma variável é obrigatória. As opcionais:
|
O modelo não vem no instalador: o app baixa para a pasta de dados (`%LOCALAPPDATA%\transcript\models` no Windows, `~/.local/share/transcript/models` no Linux) pelo comando `download_default_model_command`. As gravações ficam em `recordings/` na mesma pasta.
|
||||||
|
|
||||||
| Variável | Obrigatória | Descrição |
|
## Configuração
|
||||||
|---|---|---|
|
|
||||||
| `SHERPA_ONNX_SIDECAR` | Não | Caminho do sidecar; tem prioridade sobre `src-tauri/binaries/` e sobre o `PATH`. |
|
|
||||||
| `SHERPA_ONNX_VERSION` | Não | Versão do release sherpa-onnx baixada por `setup-sidecar.mjs` (padrão `v1.12.23`). |
|
|
||||||
| `SHERPA_ONNX_TRIPLE` | Não | Target triple do sidecar (padrão: detectado via `rustc -vV`). |
|
|
||||||
|
|
||||||
## 🧱 Arquitetura
|
Não há `.env.example` e nenhuma variável é obrigatória.
|
||||||
|
|
||||||
```mermaid
|
| Variável | Descrição |
|
||||||
flowchart LR
|
|
||||||
HK["Hotkey global Ctrl+Shift+Space"] --> UI["Frontend TypeScript"]
|
|
||||||
UI --> CMD["Comandos Tauri em Rust"]
|
|
||||||
CMD --> REC["Gravação WAV com cpal e hound"]
|
|
||||||
REC --> ASR["Sidecar sherpa-onnx-offline"]
|
|
||||||
ASR --> UI
|
|
||||||
UI -->|Inserir| INS["Clipboard e Ctrl+V no app em foco"]
|
|
||||||
```
|
|
||||||
|
|
||||||
O hotkey emite um evento que o frontend escuta para iniciar ou parar a gravação. Ao parar, `stop_recording_and_transcribe` fecha o WAV, roda o sidecar e devolve o texto num snapshot para o editor. Só depois da revisão o botão Inserir chama `request_insert_text`, que copia o texto e tenta colar. As threads do sidecar são limitadas a 1–4.
|
|
||||||
|
|
||||||
### Caminhos de transcrição
|
|
||||||
|
|
||||||
| Caminho | Arquivo | Estado no código |
|
|
||||||
|---|---|---|
|
|
||||||
| Sidecar sherpa-onnx (local) | `transcription/sherpa_onnx.rs` | É o único chamado por `stop_recording_and_transcribe`. Procura o binário em `SHERPA_ONNX_SIDECAR`, depois em `src-tauri/binaries/sherpa-onnx-offline-<triple>`, depois no `PATH`. |
|
|
||||||
| Sidecar CrispASR (local) | `transcription/crispasr.rs` | Adaptador que executa `<sidecar> -m <modelo.gguf> -f <audio.wav> -t <threads>`. Hoje nenhum comando o instancia. O spec original recomendava compilar o `parakeet-main` do CrispASR (branch `parakeet`). |
|
|
||||||
| API OpenAI-compatible | `transcription/openai.rs` | Adaptador de envio do WAV. `settings` guarda `mode` (`localFirst` ou `apiOnly`, padrão `apiOnly`) e o endpoint padrão `http://localhost:8022/v1/audio/transcriptions`. |
|
|
||||||
|
|
||||||
### Modelos
|
|
||||||
|
|
||||||
| ID | Formato | Tamanho no catálogo | Idiomas | Uso |
|
|
||||||
|---|---|---|---|---|
|
|
||||||
| `sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8` | tarball `.tar.bz2` do release `asr-models` do k2-fsa/sherpa-onnx (`encoder`, `decoder`, `joiner` int8 + `tokens.txt`) | ~640 MB | 25 idiomas europeus, incluindo `pt` | Padrão; recomendado para PC simples |
|
|
||||||
| `parakeet-tdt-0.6b-v3-q8_0` | GGUF `Q8_0`, repositório `cstr/parakeet-tdt-0.6b-v3-GGUF` | 745121600 bytes | `pt`, `en` | Legado, para o adaptador CrispASR |
|
|
||||||
|
|
||||||
### Compatibilidade por sistema
|
|
||||||
|
|
||||||
| Sistema | Inserção no app em foco | Fallback |
|
|
||||||
|---|---|---|
|
|
||||||
| Windows | Clipboard + `Ctrl+V` via PowerShell `SendKeys` | Se o `Ctrl+V` falhar, o texto fica copiado e a mensagem avisa. |
|
|
||||||
| Linux X11 | Clipboard + `xdotool key --clearmodifiers ctrl+v` | Sem `xdotool`, o texto fica copiado para colar manualmente. |
|
|
||||||
| Linux Wayland | Só copia (suporte parcial) | Sem colagem automática: cole com `Ctrl+V`. |
|
|
||||||
| Linux sem sessão detectada | Só copia | Cole manualmente no aplicativo desejado. |
|
|
||||||
|
|
||||||
A sessão é detectada por `XDG_SESSION_TYPE`, `WAYLAND_DISPLAY` e `DISPLAY`. O método de inserção configurável é `clipboardPaste` (padrão), `keyTyping` ou `manualCopy`.
|
|
||||||
|
|
||||||
## 🗂️ Estrutura
|
|
||||||
|
|
||||||
```text
|
|
||||||
src/ Frontend TypeScript (app.ts, main.ts, styles.css, app.test.ts)
|
|
||||||
src-tauri/src/
|
|
||||||
audio/ Captura do microfone em WAV
|
|
||||||
transcription/ sherpa_onnx.rs, crispasr.rs, openai.rs
|
|
||||||
injection/ Clipboard, paste automático e fallback manual
|
|
||||||
models/ Catálogo e download de modelos
|
|
||||||
settings/ Configuração padrão
|
|
||||||
tray.rs shortcuts.rs ui_commands.rs app_state.rs diagnostics.rs error.rs
|
|
||||||
src-tauri/binaries/ Sidecar sherpa-onnx-offline e DLLs onnxruntime (Windows)
|
|
||||||
src-tauri/tests/fixtures/ Modelo ONNX grande para teste real (o clone passa de 1 GB)
|
|
||||||
scripts/ setup-sidecar.mjs, setup-fixtures.mjs
|
|
||||||
.github/workflows/ ci.yml, build.yml, release.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 Scripts
|
|
||||||
|
|
||||||
| Comando | O que faz |
|
|
||||||
|---|---|
|
|---|---|
|
||||||
| `npm run dev` | Vite em `127.0.0.1:1420`, só o frontend. |
|
| `SHERPA_ONNX_SIDECAR` | Caminho do sidecar; tem prioridade sobre a pasta `binaries/` e o `PATH`. |
|
||||||
| `npm run build` | `tsc --noEmit` e `vite build`. |
|
| `SHERPA_ONNX_VERSION` | Versão do release do sherpa-onnx baixada por `setup-sidecar.mjs` (padrão `v1.12.23`). |
|
||||||
| `npm test` | `vitest` (ambiente jsdom); em modo não interativo use `npm test -- --run`, como o CI. |
|
| `SHERPA_ONNX_TRIPLE` | Target triple do sidecar (padrão: detectado via `rustc -vV`). |
|
||||||
| `npm run typecheck` | `tsc --noEmit`. |
|
|
||||||
| `npm run tauri:dev` | `tauri dev`. |
|
|
||||||
| `npm run tauri:build` | `tauri build`. |
|
|
||||||
| `cargo test --manifest-path src-tauri/Cargo.toml` | Testes Rust. |
|
|
||||||
| `node scripts/setup-sidecar.mjs` | Baixa o release `*-shared` do sherpa-onnx e extrai `sherpa-onnx-offline` para `src-tauri/binaries/`. Plataformas: Linux x64/arm64, macOS, Windows x64. |
|
|
||||||
| `node scripts/setup-fixtures.mjs` | Baixa `parakeet-sample.wav` para `src-tauri/tests/fixtures/`. |
|
|
||||||
|
|
||||||
### Workflows (`.github/workflows/`)
|
O método de inserção nas configurações aceita `clipboardPaste` (padrão), `keyTyping` e `manualCopy`.
|
||||||
|
|
||||||
| Arquivo | Gatilho | O que faz |
|
## Estado do projeto
|
||||||
|---|---|---|
|
|
||||||
| `ci.yml` | PR e push em `main` | Em `ubuntu-22.04` com Node 22: `npm ci`, `typecheck`, `npm run test -- --run`, `build` e `cargo test`. Depois prepara sidecar, fixture e modelo, e roda o teste real de transcrição com `--ignored`. |
|
|
||||||
| `build.yml` | Push em `main` e manual | Matriz `windows-latest` e `ubuntu-22.04`: `npm run tauri:build` e upload de `src-tauri/target/release/bundle/**/*` (`windows-bundles`, `linux-bundles`). |
|
|
||||||
| `release.yml` | Tag `v*.*.*` e manual (input `tag`) | `tauri-apps/tauri-action@v0` nas mesmas duas plataformas; publica a GitHub Release `Transcript <tag>`, sem rascunho e sem pré-release. |
|
|
||||||
|
|
||||||
## 📚 Documentação
|
Protótipo em desenvolvimento por uma pessoa. As versões divergem: `0.1.0` em `package.json` e `Cargo.toml`, `0.3.1` em `tauri.conf.json`. O que a leitura do código mostra:
|
||||||
|
|
||||||
- [Design do app](docs/superpowers/specs/2026-06-10-transcription-app-design.md)
|
- **O crate Rust não compila como está:** `settings/mod.rs` usa `crate::shortcuts::DEFAULT_HOTKEY`, que não existe; `transcription/openai.rs` importa `crate::secrets`, módulo que `lib.rs` não declara; `ui_commands.rs` lê `settings.transcription.model_id`, campo que `TranscriptionSettings` não tem.
|
||||||
- [sherpa-onnx como sidecar](docs/superpowers/specs/2026-06-11-sherpa-onnx-sidecar.md)
|
- **O frontend chama comandos que não estão registrados** no `invoke_handler` de `lib.rs`: `stop_recording` (usado pelo botão Parar), `transcribe_pending`, `minimize_window`, `close_window`, `save_openai_api_key` e `clear_openai_api_key`.
|
||||||
- [Redesign do frontend](docs/superpowers/specs/2026-08-08-frontend-redesign-design.md)
|
- **Nome do sidecar:** `setup-sidecar.mjs` grava `src-tauri/binaries/sherpa-onnx-offline-<triple>`, mas o app procura `sherpa-onnx-offline` sem o sufixo e cai no `PATH`. Até isso mudar, aponte `SHERPA_ONNX_SIDECAR` para o binário.
|
||||||
- Planos: [MVP](docs/superpowers/plans/2026-06-10-transcription-app-mvp.md), [integrações nativas](docs/superpowers/plans/2026-06-10-transcription-app-native-integrations.md), [redesign](docs/superpowers/plans/2026-08-08-frontend-redesign.md)
|
- `keyTyping` não tem efeito: `request_insert_text` usa sempre `ClipboardPaste`.
|
||||||
- Tauri: [commands](https://v2.tauri.app/develop/calling-rust), [system tray](https://v2.tauri.app/learn/system-tray), [sidecars](https://v2.tauri.app/develop/sidecar), [pipelines GitHub](https://v2.tauri.app/distribute/pipelines/github), [pré-requisitos Linux](https://v2.tauri.app/start/prerequisites)
|
- `tauri.conf.json` não declara `bundle.externalBin` (o sidecar não vai no instalador), `bundle.resources` aponta para `resources/whisper/`, que não existe, e só `icons/icon.ico` existe dos ícones listados. whisper.cpp só aparece no spec do redesign.
|
||||||
- Modelos: [NVIDIA Parakeet v3](https://huggingface.co/nvidia/parakeet-tdt-0.6b-v3/blob/main/README.md), [cstr GGUF](https://huggingface.co/cstr/parakeet-tdt-0.6b-v3-GGUF)
|
- O atalho `Ctrl+Shift+Space` é fixo em `shortcuts.rs`, e o item Iniciar gravação da bandeja só mostra a janela.
|
||||||
|
- `ci.yml` baixa o modelo `v3-int8` (o catálogo usa `v2-int8`) e chama o teste `sherpa_onnx::tests::real_transcription_returns_known_text`, que não existe em `sherpa_onnx.rs`.
|
||||||
|
|
||||||
## 🛣️ Limitações e próximos passos
|
Workflows em `.github/workflows/`: `ci.yml` (PR e push em `main`: typecheck, testes, build e `cargo test` no Ubuntu 22.04), `build.yml` (push em `main` e manual: bundles para Windows e Linux como artefatos) e `release.yml` (tag `v*.*.*` ou manual: publica a GitHub Release `Transcript <tag>`).
|
||||||
|
|
||||||
- **whisper.cpp:** só aparece no spec do redesign, e `bundle.resources` aponta para `resources/whisper/`, pasta que não existe no repositório. Não há código nem modelo Whisper no catálogo; `whisper-1` é só um exemplo de nome de modelo na API.
|
Antes de abrir um PR: `npm run typecheck && npm test -- --run && cargo test --manifest-path src-tauri/Cargo.toml`.
|
||||||
- O app ainda não escolhe o caminho de transcrição por `mode`: `stop_recording_and_transcribe` sempre usa o sherpa-onnx.
|
|
||||||
- `tauri.conf.json` não declara `bundle.externalBin`, embora o spec preveja o sidecar empacotado no instalador.
|
|
||||||
- Divergências vistas na leitura do código, que não foi compilado: o frontend invoca `stop_recording`, `transcribe_pending`, `minimize_window`, `close_window`, `save_openai_api_key` e `clear_openai_api_key`, ausentes do `invoke_handler` de `lib.rs`; `openai.rs` importa `crate::secrets`, que `lib.rs` não declara; `ui_commands.rs` lê `settings.transcription.model_id` e `settings` usa `shortcuts::DEFAULT_HOTKEY`, e nenhum dos dois existe.
|
|
||||||
- O hotkey `Ctrl+Shift+Space` é fixo em `shortcuts.rs`, e o item Iniciar gravação da bandeja só mostra a janela.
|
|
||||||
- O catálogo aponta para o modelo `v2-int8`, mas o `ci.yml` baixa o `v3-int8` (~670 MB) e cita o teste `real_transcription_returns_known_text`, que não está em `sherpa_onnx.rs`.
|
|
||||||
- As versões divergem: `0.1.0` em `package.json` e `Cargo.toml`, `0.3.1` em `tauri.conf.json`.
|
|
||||||
|
|
||||||
## 🤝 Contribuindo
|
## Licença
|
||||||
|
|
||||||
Mantenha módulos pequenos, com responsabilidades claras. Antes de abrir o PR, estes comandos devem passar:
|
Sem licença publicada: todos os direitos reservados.
|
||||||
|
|
||||||
```bash
|
---
|
||||||
npm run typecheck && npm test -- --run && cargo test --manifest-path src-tauri/Cargo.toml
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📄 Licença
|
<div align="center">
|
||||||
|
<sub>Feito por <a href="https://evandro.dev.br">Evandro Fonseca Junior</a> · <a href="https://git.evandro.dev.br/evandro">git.evandro.dev.br</a></sub>
|
||||||
Sem licença definida — todos os direitos reservados.
|
</div>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="420" viewBox="0 0 1200 420" role="img" aria-labelledby="title desc">
|
||||||
|
<title id="title">Transcript</title>
|
||||||
|
<desc id="desc">Transcript: ditado local para Windows e Linux. À direita, o atalho Ctrl+Shift+Space, uma forma de onda com o estado Gravando e o editor Texto transcrito com os botões Copiar e Inserir.</desc>
|
||||||
|
|
||||||
|
<rect width="1200" height="420" rx="24" fill="#f4efe7"/>
|
||||||
|
|
||||||
|
<g id="title-block" font-family="system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif">
|
||||||
|
<text x="64" y="156" font-size="68" font-weight="700" fill="#15120f">Transcript</text>
|
||||||
|
<text x="64" y="214" font-size="28" fill="#15120f">Ditado local: grave com um atalho,</text>
|
||||||
|
<text x="64" y="252" font-size="28" fill="#15120f">revise o texto e cole no app em foco.</text>
|
||||||
|
<text x="64" y="326" font-size="20" fill="#665e55" font-family="ui-monospace, "SF Mono", Consolas, monospace">Tauri 2 · Rust · TypeScript · sherpa-onnx</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g id="dictation" font-family="system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif">
|
||||||
|
<g id="hotkey" font-size="20" font-weight="600" fill="#15120f">
|
||||||
|
<rect x="640" y="52" width="84" height="48" rx="10" fill="#fffdfa" stroke="#312923" stroke-width="2"/>
|
||||||
|
<text x="682" y="83" text-anchor="middle">Ctrl</text>
|
||||||
|
<text x="740" y="83" text-anchor="middle" fill="#7a4f38">+</text>
|
||||||
|
<rect x="756" y="52" width="96" height="48" rx="10" fill="#fffdfa" stroke="#312923" stroke-width="2"/>
|
||||||
|
<text x="804" y="83" text-anchor="middle">Shift</text>
|
||||||
|
<text x="868" y="83" text-anchor="middle" fill="#7a4f38">+</text>
|
||||||
|
<rect x="884" y="52" width="180" height="48" rx="10" fill="#fffdfa" stroke="#312923" stroke-width="2"/>
|
||||||
|
<text x="974" y="83" text-anchor="middle">Space</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g id="recording">
|
||||||
|
<rect x="640" y="140" width="128" height="40" rx="20" fill="#eed6cd"/>
|
||||||
|
<text x="704" y="167" font-size="18" font-weight="700" fill="#8a241d" text-anchor="middle">Gravando</text>
|
||||||
|
<g fill="#8a241d">
|
||||||
|
<rect x="792" y="152" width="8" height="16" rx="4"/>
|
||||||
|
<rect x="808" y="140" width="8" height="40" rx="4"/>
|
||||||
|
<rect x="824" y="130" width="8" height="60" rx="4"/>
|
||||||
|
<rect x="840" y="144" width="8" height="32" rx="4"/>
|
||||||
|
<rect x="856" y="124" width="8" height="72" rx="4"/>
|
||||||
|
<rect x="872" y="136" width="8" height="48" rx="4"/>
|
||||||
|
<rect x="888" y="148" width="8" height="24" rx="4"/>
|
||||||
|
<rect x="904" y="132" width="8" height="56" rx="4"/>
|
||||||
|
<rect x="920" y="120" width="8" height="80" rx="4"/>
|
||||||
|
<rect x="936" y="138" width="8" height="44" rx="4"/>
|
||||||
|
<rect x="952" y="150" width="8" height="20" rx="4"/>
|
||||||
|
<rect x="968" y="134" width="8" height="52" rx="4"/>
|
||||||
|
<rect x="984" y="126" width="8" height="68" rx="4"/>
|
||||||
|
<rect x="1000" y="142" width="8" height="36" rx="4"/>
|
||||||
|
<rect x="1016" y="152" width="8" height="16" rx="4"/>
|
||||||
|
<rect x="1032" y="138" width="8" height="44" rx="4"/>
|
||||||
|
<rect x="1048" y="146" width="8" height="28" rx="4"/>
|
||||||
|
<rect x="1064" y="154" width="8" height="12" rx="4"/>
|
||||||
|
<rect x="1080" y="156" width="8" height="8" rx="4"/>
|
||||||
|
<rect x="1096" y="156" width="8" height="8" rx="4"/>
|
||||||
|
<rect x="1112" y="156" width="8" height="8" rx="4"/>
|
||||||
|
<rect x="1128" y="156" width="8" height="8" rx="4"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g id="editor">
|
||||||
|
<rect x="640" y="220" width="496" height="148" rx="16" fill="#fffdfa" stroke="#ddd5cb" stroke-width="2"/>
|
||||||
|
<text x="664" y="256" font-size="18" font-weight="700" fill="#312923">Texto transcrito</text>
|
||||||
|
<text x="664" y="292" font-size="20" fill="#15120f">Amanhã às 9h revisamos o contrato.</text>
|
||||||
|
<rect x="896" y="312" width="104" height="40" rx="12" fill="#eadfd2"/>
|
||||||
|
<text x="948" y="338" font-size="18" font-weight="700" fill="#15120f" text-anchor="middle">Copiar</text>
|
||||||
|
<rect x="1012" y="312" width="104" height="40" rx="12" fill="#eadfd2"/>
|
||||||
|
<text x="1064" y="338" font-size="18" font-weight="700" fill="#15120f" text-anchor="middle">Inserir</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.1 KiB |
Reference in new issue
Block a user