Speech to Text: Omarchy bar plugin for dictation
A bar widget plus a stdlib-only Python daemon. Press a language's key to record, press it again to stop: the text is pasted at the cursor (or handed to the default coding agent with a second key). While recording the bar shows a waveform (yellow while the microphone opens, green while listening) and the words as they are recognised; the recording is transcribed at every pause, so stopping only transcribes the last phrase. Every recording and its text are kept in a searchable history with playback, copy, paste and delete. Uses Omarchy's own dictation engine (voxtype, local Whisper) by default and downloads any model a language needs by itself; whisper.cpp or a custom command can be picked instead. Key bindings are applied at runtime through Hyprland's Lua API and never touch a key something else already uses.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import QtQuick
|
||||
|
||||
// A row of thin bars mirrored around the middle. `levels` holds 0..1 values,
|
||||
// newest last; the bars show the most recent `bars` of them. With `idle` on
|
||||
// (nothing to show yet, or transcribing) the bars breathe gently instead.
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var levels: []
|
||||
property int bars: 20
|
||||
property real barWidth: 2
|
||||
property real gap: 2
|
||||
property color color: "white"
|
||||
property bool idle: false // gentle breathing (nothing to show yet, or transcribing)
|
||||
property bool sine: false // a travelling sine wave (the microphone is still connecting)
|
||||
property real minHeight: 2
|
||||
|
||||
implicitWidth: bars * (barWidth + gap) - gap
|
||||
implicitHeight: 16
|
||||
|
||||
property real phase: 0
|
||||
Timer {
|
||||
interval: 40
|
||||
repeat: true
|
||||
running: (root.idle || root.sine) && root.visible
|
||||
onTriggered: root.phase += root.sine ? 0.35 : 0.2
|
||||
}
|
||||
|
||||
function levelAt(i) {
|
||||
var lv = levels || []
|
||||
var offset = lv.length - bars
|
||||
var v = offset + i >= 0 ? Number(lv[offset + i]) : 0
|
||||
return isFinite(v) ? Math.max(0, Math.min(1, v)) : 0
|
||||
}
|
||||
|
||||
function breath(i) {
|
||||
return 0.12 + 0.1 * (1 + Math.sin(phase + i * 0.45)) / 2
|
||||
}
|
||||
|
||||
function wave(i) {
|
||||
return 0.15 + 0.75 * (1 + Math.sin(i * 0.7 - phase)) / 2
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: root.gap
|
||||
Repeater {
|
||||
model: root.bars
|
||||
Rectangle {
|
||||
required property int index
|
||||
readonly property real lv: root.sine ? root.wave(index) : root.idle ? root.breath(index) : root.levelAt(index)
|
||||
width: root.barWidth
|
||||
height: Math.max(root.minHeight, Math.round(lv * root.height))
|
||||
radius: root.barWidth / 2
|
||||
color: root.color
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Behavior on height { NumberAnimation { duration: 70 } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user