Compare commits

..

8 Commits

Author SHA1 Message Date
Gitea Actions
b4c0589b04 chore: bump sidecar version to 1.0.12 [skip ci] 2026-04-11 02:44:12 +00:00
Developer
66c441b17f Revert macOS workflow to pre-signing state
All checks were successful
Tests / Python Backend Tests (push) Successful in 5s
Tests / Frontend Tests (push) Successful in 7s
Tests / Rust Sidecar Tests (push) Successful in 1m59s
Remove all signing env vars and setup steps. The local act runner's
keychain interferes with Tauri's auto-detection. Will re-add signing
once Apple Developer verification is complete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:41:46 -07:00
Developer
94bc704950 Fix settings save blocking event loop and overwriting config keys
Some checks failed
Tests / Python Backend Tests (push) Successful in 5s
Tests / Frontend Tests (push) Successful in 8s
Tests / Rust Sidecar Tests (push) Has been cancelled
- Run apply_settings in thread pool executor to prevent engine reload
  from blocking the HTTP response (caused "TypeError: Failed to fetch")
- Flatten nested config objects into dot-notation keys before saving
  so partial updates don't wipe out unincluded keys like auth_token

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:40:51 -07:00
Developer
7900d2d9f2 Detect cloud-only sidecar from compute devices (no sidecar rebuild needed)
All checks were successful
Tests / Python Backend Tests (push) Successful in 5s
Tests / Frontend Tests (push) Successful in 7s
Tests / Rust Sidecar Tests (push) Successful in 1m57s
Use the existing /api/compute-devices response to determine if only cloud
is available, instead of relying on the backend's is_cloud_only status field.
Hides Local (Whisper) option when the sidecar only supports cloud.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:36:13 -07:00
Developer
e0396df7b0 Use ad-hoc signing when no Apple certificate is configured
All checks were successful
Tests / Python Backend Tests (push) Successful in 5s
Tests / Frontend Tests (push) Successful in 7s
Tests / Rust Sidecar Tests (push) Successful in 2m4s
Prevents Tauri from auto-detecting local keychain certificates on the
build machine, which causes SecKeychainItemImport failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:30:44 -07:00
Gitea Actions
ad89735822 chore: bump version to 2.0.17 [skip ci] 2026-04-11 02:27:20 +00:00
Developer
f0b5890eba Hide Local (Whisper) mode option when using cloud-only sidecar
All checks were successful
Tests / Python Backend Tests (push) Successful in 6s
Tests / Frontend Tests (push) Successful in 7s
Tests / Rust Sidecar Tests (push) Successful in 2m3s
- Expose is_cloud_only flag in /api/status response
- Add isCloudOnly to backend store state
- Conditionally hide Local (Whisper) radio button in Settings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:24:01 -07:00
Developer
8df1ab9817 Remove macOS signing config until Apple Developer verification completes
All checks were successful
Tests / Python Backend Tests (push) Successful in 5s
Tests / Frontend Tests (push) Successful in 7s
Tests / Rust Sidecar Tests (push) Successful in 2m0s
hardenedRuntime triggers code signing which fails without a valid certificate.
Entitlements.plist and Info.plist remain for when signing is re-enabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:21:20 -07:00
10 changed files with 36 additions and 36 deletions

View File

@@ -39,27 +39,7 @@ jobs:
- name: Install npm dependencies
run: npm ci
- name: Setup code signing
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY_CONTENT }}
run: |
if [ -n "${APPLE_API_KEY_CONTENT}" ]; then
echo "Setting up notarization API key..."
mkdir -p ~/private_keys
echo "${APPLE_API_KEY_CONTENT}" > ~/private_keys/AuthKey_${APPLE_API_KEY}.p8
else
echo "No signing secrets configured, skipping code signing setup"
fi
- name: Build Tauri app
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_API_KEY_PATH: ~/private_keys/AuthKey_${{ secrets.APPLE_API_KEY }}.p8
run: npm run tauri build
- name: Upload to release
@@ -111,6 +91,3 @@ jobs:
"${REPO_API}/releases/${RELEASE_ID}/assets?name=${encoded_name}")
echo "Upload response: HTTP ${HTTP_CODE}"
done
- name: Cleanup signing artifacts
run: rm -rf ~/private_keys

View File

@@ -212,7 +212,11 @@ class APIServer:
@app.put("/api/config")
async def update_config(update: ConfigUpdate):
engine_reloaded, message = ctrl.apply_settings(update.settings)
import asyncio
loop = asyncio.get_event_loop()
engine_reloaded, message = await loop.run_in_executor(
None, ctrl.apply_settings, update.settings
)
return {
"status": "ok",
"message": message,

View File

@@ -608,8 +608,17 @@ class AppController:
Returns (engine_reload_needed, message).
"""
if new_config:
for key, value in new_config.items():
self.config.set(key, value)
# Flatten nested dicts into dot-notation keys so we merge
# individual values instead of replacing entire sections
# (e.g. remote.mode instead of overwriting all of remote)
def _flatten(d, prefix=""):
for k, v in d.items():
full_key = f"{prefix}{k}" if not prefix else f"{prefix}.{k}"
if isinstance(v, dict):
_flatten(v, full_key)
else:
self.config.set(full_key, v)
_flatten(new_config)
# Update web server display settings
if self.web_server:
@@ -682,6 +691,7 @@ class AppController:
"transcription_count": len(self.transcriptions),
"remote_mode": remote_mode,
"server_sync_enabled": self.config.get('server_sync.enabled', False),
"is_cloud_only": self.is_cloud_only,
}
def get_audio_devices(self) -> list[dict]:

View File

@@ -1,7 +1,7 @@
{
"name": "local-transcription",
"private": true,
"version": "2.0.16",
"version": "2.0.17",
"type": "module",
"scripts": {
"dev": "vite dev",

View File

@@ -1,6 +1,6 @@
[project]
name = "local-transcription"
version = "1.0.11"
version = "1.0.12"
description = "A standalone desktop application for real-time speech-to-text transcription using Whisper models"
readme = "README.md"
requires-python = ">=3.9"

View File

@@ -1,6 +1,6 @@
[package]
name = "local-transcription"
version = "2.0.16"
version = "2.0.17"
description = "Real-time speech-to-text transcription for streamers"
authors = ["Local Transcription Contributors"]
edition = "2021"

View File

@@ -1,6 +1,6 @@
{
"productName": "Local Transcription",
"version": "2.0.16",
"version": "2.0.17",
"identifier": "net.anhonesthost.local-transcription",
"build": {
"frontendDist": "../dist",
@@ -34,10 +34,6 @@
"icons/icon.ico",
"icons/icon.png"
],
"macOS": {
"entitlements": "Entitlements.plist",
"hardenedRuntime": true
},
"windows": {
"digestAlgorithm": "sha256"
}

View File

@@ -47,6 +47,9 @@
let autoCheckUpdates = $state(true);
let isCloudMode = $derived(remoteMode === "managed" || remoteMode === "byok");
let isCloudOnly = $derived(
computeDevices.length > 0 && computeDevices.every(d => d.id === "cloud")
);
// Room creation / join state
let shareCode = $state("");
@@ -453,6 +456,7 @@
/>
Managed Service
</label>
{#if !isCloudOnly}
<label>
<input
type="radio"
@@ -462,6 +466,7 @@
/>
Local (Whisper)
</label>
{/if}
</div>
{#if remoteMode === "byok"}
<div class="field">

View File

@@ -19,6 +19,7 @@ interface BackendState {
wsConnection: WebSocket | null;
version: string;
lastError: string;
isCloudOnly: boolean;
}
let state = $state<BackendState>({
@@ -30,6 +31,7 @@ let state = $state<BackendState>({
wsConnection: null,
version: "1.4.0",
lastError: "",
isCloudOnly: false,
});
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
@@ -72,6 +74,9 @@ async function pollStatus() {
if (data.version) {
state.version = data.version;
}
if (data.is_cloud_only !== undefined) {
state.isCloudOnly = data.is_cloud_only;
}
}
} catch {
// API not ready yet, will retry
@@ -285,6 +290,9 @@ export const backendStore = {
get lastError() {
return state.lastError;
},
get isCloudOnly() {
return state.isCloudOnly;
},
get apiBaseUrl() {
return `http://localhost:${state.port}`;
},

View File

@@ -1,7 +1,7 @@
"""Version information for Local Transcription."""
__version__ = "2.0.16"
__version_info__ = (2, 0, 16)
__version__ = "2.0.17"
__version_info__ = (2, 0, 17)
# Version history:
# 1.4.0 - Auto-update feature: