373d10595b
Captures roughly forty version bumps (v0.2.6 → v0.2.47) of work that
accumulated without commits.
- Pluggable provider system under server/providers/: gemini, anthropic,
openai, openai-compatible, ollama, whisper-compatible, relay. Mix and
match transcription + analysis per request via the picker UI.
- Relay backend integration. Hardcoded relay URL in server/relay-default.js
(operator-controlled at build time, not user-configurable). New
/api/relay/{status,policy} endpoints proxy to the relay; balance pings
populate a cached credit display.
- Per-install identity in server/install-id.js for relay credit accounting.
Sent to the relay as X-Recap-Install-Id; persists across upgrades, lost
on a full uninstall + reinstall. Not surfaced in the UI.
- Admin login gate (server/admin-auth.js + setAdminPassword action). Scrypt
password hash + HMAC-signed session cookie.
- Entitlement scheme rename: pro / max (each paired with subscriptions and
relay_pro / relay_max), replacing the misleading "core" entitlement
that conflicted with the user-facing "Core" tier name.
- Activation screen: dynamic credit count pulled from /api/relay/policy,
"Skip — use free mode" button, accurate paid-feature list.
- Top toolbar: inline credit-balance pill (or "BYO configured" fallback),
Upgrade + "I have a key" buttons.
- Picker UI: per-provider sections with Save/Test/Delete buttons, sections
collapsible by chevron, default-collapsed unless currently selected,
"Use comped credits (reset to relay)" link when the user has strayed,
green hint under inputs whose values are server-configured.
- Activity log: chevron-collapsible groups per video, refresh-survival via
localStorage + a 500-entry server-side buffer, explicit Clear button.
- YouTube captions fast-path with user toggle (skips audio download + AI
transcription when captions are available — uncheck for speaker labels).
- Cancel button: AbortController plumbed through every provider SDK call;
retryAPI short-circuits on AbortError; cancellation events surface in
the activity log instead of silent retries.
- Long-video analysis: auto-coalesce transcript entries before building the
analysis prompt so local-model context windows (32k-ish) don't overflow.
Original entries preserved for transcript display via an index map; the
analyzer sees a coarser view but click-to-seek timestamps stay precise.
- StartOS action grouping (Setup / AI Providers) so the actions list is
navigable.
- Manifest description rewritten to reflect multi-provider support and
free-tier relay credits.
- Smaller fixes: summarize-button enablement no longer requires a Gemini
key when other providers are configured; analysis fallback chain handles
context-length and 503 capacity errors; single-segment expansion for
providers that don't return per-segment timestamps (Parakeet et al.);
many other UX polish items.
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import { sdk } from '../sdk'
|
|
import { configFile } from '../file-models/config.json'
|
|
|
|
const { InputSpec, Value } = sdk
|
|
|
|
// Standard Ollama port. Hardcoded because Ollama upstream uses 11434
|
|
// universally — its StartOS package preserves this. If a future
|
|
// release changes the port we can swap to a runtime
|
|
// sdk.serviceInterface.get(...) lookup against ollama's exposed
|
|
// interface, but for now hardcode + override-on-mismatch is simpler
|
|
// and avoids a guess at the interface ID.
|
|
const OLLAMA_DEFAULT_PORT = 11434
|
|
|
|
const inputSpec = InputSpec.of({
|
|
ollama_base_url: Value.text({
|
|
name: 'Ollama Base URL',
|
|
description:
|
|
'URL of your Ollama server. If you have the Ollama StartOS package installed on this server, this field is pre-populated automatically. Override only if you want to point at a different Ollama instance (e.g. on another machine: http://192.168.1.10:11434).',
|
|
required: false,
|
|
default: 'http://localhost:11434',
|
|
minLength: 0,
|
|
maxLength: 256,
|
|
patterns: [
|
|
{
|
|
regex: '^(https?://.+)?$',
|
|
description: 'Must be empty or start with http:// or https://',
|
|
},
|
|
],
|
|
}),
|
|
})
|
|
|
|
// Best-effort detection of an Ollama instance running on this same
|
|
// StartOS server. StartOS exposes every package on its own internal
|
|
// `<package-id>.startos` hostname, reachable from any other package's
|
|
// container without explicit networking config (per the Service
|
|
// Packaging docs). Returns the URL when ollama is installed, null
|
|
// otherwise.
|
|
async function detectStartOsOllamaUrl(effects: any): Promise<string | null> {
|
|
try {
|
|
const check = await sdk.checkDependencies(effects, ['ollama'])
|
|
if (!check.installedSatisfied('ollama')) return null
|
|
return `http://ollama.startos:${OLLAMA_DEFAULT_PORT}`
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export const setOllamaUrl = sdk.Action.withInput(
|
|
'set-ollama-url',
|
|
|
|
async ({ effects }) => ({
|
|
name: 'Set Ollama Server URL',
|
|
description:
|
|
'Configure where to reach a local Ollama server for topic analysis. No API key required (Ollama runs locally). Does not transcribe audio. Auto-pre-populates if the Ollama StartOS package is installed on this server.',
|
|
warning: null,
|
|
allowedStatuses: 'any',
|
|
group: 'AI Providers',
|
|
visibility: 'enabled',
|
|
}),
|
|
|
|
inputSpec,
|
|
|
|
async ({ effects }) => {
|
|
const config = await configFile.read().once()
|
|
// If the user has already set a value, respect it — don't
|
|
// overwrite a manual override on every action open.
|
|
if (config?.ollama_base_url) {
|
|
return { ollama_base_url: config.ollama_base_url }
|
|
}
|
|
const auto = await detectStartOsOllamaUrl(effects)
|
|
if (auto) return { ollama_base_url: auto }
|
|
return { ollama_base_url: 'http://localhost:11434' }
|
|
},
|
|
|
|
async ({ effects, input }) => {
|
|
await configFile.merge(effects, {
|
|
ollama_base_url: (input.ollama_base_url || '').trim(),
|
|
})
|
|
return null
|
|
},
|
|
)
|