Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

All notable changes to Sonario for Android are documented here.

## 1.4.0

- Replaces the retired Llama 4 Scout cloud model with the fixed Groq model
`qwen/qwen3.6-27b`.
- Automatically ignores and migrates stale model IDs stored by older installs or
saved sessions.
- Resizes cloud chunks and output budgets so each request fits beneath Qwen's
free-tier 8K-token-per-minute limit.
- Queues requests against conservative local TPM, RPM, and daily budgets instead
of repeatedly hitting minute-based 429 errors.
- Reads Groq's live remaining-token and reset headers and displays a countdown
while waiting for the provider's actual token window.
- Detects organization-wide daily exhaustion, stops without retrying all day, and
preserves completed checkpoints for Resume.
- Uses Qwen's non-thinking mode for routine summaries to reduce unnecessary token
consumption.

## 1.3.3

- Keeps the Ask field visible when the software keyboard opens.
Expand Down
63 changes: 48 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ or a bulleted outline.

**Status:** working. YouTube transcript summarization, web-article and pasted-text
summarization, Groq cloud, on-device inference, saved sessions, resumable
checkpoints, and source Q&A are functional as of version 1.3.3.
checkpoints, and source Q&A are functional as of version 1.4.0.

Sonario has two engines, and you pick which to use per summary:

- **Groq cloud** (recommended) - sends your text to Groq's API and summarizes
with a large model (Llama 4 Scout by default) in seconds. Fast, handles big
documents in one pass. You bring your own free API key. Your text goes to
Groq's servers.
with Qwen 3.6 27B. Sonario splits large sources into rate-safe requests, waits
for Groq's minute windows, and checkpoints each completed call. You bring your
own API key. Your text goes to Groq's servers.
- **On-device** - runs a model locally via llama.cpp. Private (nothing leaves the
phone except fetching the link), but slow: CPU-only, so a summary takes minutes
and the phone warms up. A private fallback rather than the daily driver.
Expand All @@ -22,6 +22,10 @@ Sonario has two engines, and you pick which to use per summary:

- Summarizes YouTube captions, web articles, pasted text, PDF, EPUB, DOCX, TXT,
and Markdown files.
- Uses `qwen/qwen3.6-27b` as the only Groq cloud model, preventing retired model
IDs from being restored by an old setting or saved session.
- Queues cloud requests against conservative TPM/RPM limits and Groq's live reset
headers instead of repeatedly failing with minute-based 429 errors.
- Keeps long cloud summaries alive with a foreground service and retries
temporary DNS, timeout, and network-handoff failures.
- Saves up to 12 recent sessions locally, restores the latest session on launch,
Expand Down Expand Up @@ -51,11 +55,17 @@ Sonario has two engines, and you pick which to use per summary:
1. Install the APK (see below) and open Sonario.
2. On the first screen, tap **Use Groq cloud instead** (skips the local-model
download).
3. Get a free Groq API key at console.groq.com (no credit card). Create a key.
3. Get a Groq API key at console.groq.com and create a key.
4. In Sonario's Settings, paste the key and tap **Save key**.
5. Back on the main screen, make sure the toggle is on **Groq cloud**, paste a
YouTube link or article URL, and tap **Summarize**.

Qwen 3.6 27B's published Groq free-tier baseline is 8K tokens per minute and
200K tokens per day, applied across the whole Groq organization. Sonario uses
slightly lower internal working limits for safety, follows the provider's live
remaining-token/reset headers, and displays a countdown between calls. Extra
keys in the same organization share the same quota and do not multiply it.

## Quick start (on-device, fully private)

1. Open Sonario. On the first screen, tap **Get** on a model (Qwen2.5 1.5B is the
Expand Down Expand Up @@ -107,18 +117,31 @@ no captions. These are still undocumented YouTube endpoints, so a future YouTube
change can require another extractor update. Failed requests show **Extractor
build 2** diagnostics so you can confirm the new APK is actually installed.

## Qwen cloud and rate-aware queueing (1.4.0)

- The Groq cloud path is pinned to `qwen/qwen3.6-27b`; old model preferences and
saved Scout session IDs can no longer control the request model.
- Source chunks, detailed-output budgets, chapter excerpts, and Ask excerpts are
sized so one call fits beneath the free-tier 8K TPM ceiling.
- Sonario leaves headroom below the published TPM/RPM/daily limits, reads Groq's
`x-ratelimit-remaining-tokens` and reset headers, and waits with a visible
countdown before the next call.
- Routine summaries use Qwen's non-thinking mode to avoid spending output tokens
on hidden reasoning that is unnecessary for summarization.
- When Groq reports daily exhaustion, Sonario stops rather than waiting all day.
Every completed call remains checkpointed so Resume continues later.

## Background reliability and Ask fixes (1.2.0)

- Cloud requests now retry transient DNS, Wi-Fi/mobile-data handoff, connection,
and timeout failures for up to ten minutes instead of immediately ending with
- Cloud requests retry transient DNS, Wi-Fi/mobile-data handoff, connection, and
timeout failures for up to ten minutes instead of immediately ending with
`Unable to resolve host api.groq.com`.
- A foreground service holds a partial CPU wake lock and a temporary Wi-Fi lock
only while a summary or source question is active. The notification displays
rate-limit waits and network-retry status.
- Groq responses are buffered before being committed to a summary, so a failed
connection can be retried without duplicating a partial response.
- The Ask box now shows the actual API/network error in place, keeps the typed
- The Ask box shows the actual API/network error in place, keeps the typed
question after a failure, and searches relevant passages across the whole
source instead of sending only the first portion of a long video or book.
- Long jobs have a visible Cancel control, stale errors clear when a new source is
Expand Down Expand Up @@ -153,12 +176,13 @@ and the summarize pipeline talks only to that:

- `llm/InferenceEngine.kt` - shared interface (`ensureReady`, `stream`).
- `llm/LlmEngine.kt` - on-device via Llamatik/llama.cpp.
- `llm/GroqEngine.kt` - Groq cloud via the OpenAI-compatible streaming API.
- `llm/GroqEngine.kt` - Qwen 3.6 through Groq's OpenAI-compatible streaming API.
- `llm/RateLimiter.kt` - local pacing plus synchronization with Groq reset headers.
- `llm/ModelDownloader.kt` - resumable GGUF download.
- `data/Settings.kt` - engine choice, Groq key, Groq model (local prefs).
- `data/Settings.kt` - engine choice and Groq key (local preferences).
- `source/SourceFetcher.kt` - YouTube (InnerTube) and web-article fetching.
- `summarize/SummarizeEngine.kt` - map-reduce summarizer; chunking adapts to the
engine (small bounded chunks on-device, large/one-pass for the 128k cloud model).
- `summarize/SummarizeEngine.kt` - map-reduce summarizer with bounded cloud calls
sized for Groq's TPM limits and small CPU-bounded on-device chunks.
- `summarize/Prompts.kt` - prompts carried over from Sonario desktop.
- `ui/` - Compose screens, theme, settings, the CPU/RAM meter, crash screen.
- `CrashReporter.kt` - global uncaught-exception logger.
Expand All @@ -182,13 +206,22 @@ MIT. See LICENSE.

## Clear all saved sessions (1.3.1)

The Recent sessions card now has a **Clear** button. After confirmation, it permanently deletes all locally saved session folders, including source transcripts, chapter data, summaries, checkpoints, and saved Q&A. Exported files outside the app are left alone.
The Recent sessions card has a **Clear** button. After confirmation, it
permanently deletes all locally saved session folders, including source
transcripts, chapter data, summaries, checkpoints, and saved Q&A. Exported files
outside the app are left alone.

## Saved and resumable sessions (1.3.0)

Sonario now saves summaries locally instead of keeping the only copy in an Activity/ViewModel. The most recent session is restored after an app or Activity restart, and a Recent sessions panel can open, resume, or delete prior work.
Sonario saves summaries locally instead of keeping the only copy in an
Activity/ViewModel. The most recent session is restored after an app or Activity
restart, and a Recent sessions panel can open, resume, or delete prior work.

For long summaries, Sonario checkpoints after every completed LLM call. If Android or the network interrupts the run, Resume skips already-completed condensed chunks and derived views so those Groq tokens are not spent twice. Completed source text and Ask history are stored with the session. Up to 12 recent sessions are retained in the app's private files directory.
For long summaries, Sonario checkpoints after every completed LLM call. If
Android or the network interrupts the run, Resume skips already-completed
condensed chunks and derived views so those Groq tokens are not spent twice.
Completed source text and Ask history are stored with the session. Up to 12
recent sessions are retained in the app's private files directory.

## Keyboard-safe Ask field (1.3.3)

Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ android {
applicationId = "ai.sonario.app"
minSdk = 28 // Android 9. 8 Elite phones are far above this.
targetSdk = 36
versionCode = 9
versionName = "1.3.3"
versionCode = 10
versionName = "1.4.0"
vectorDrawables { useSupportLibrary = true }
ndk { abiFilters += "arm64-v8a" } // modern phones; keeps APK lean
}
Expand Down
28 changes: 19 additions & 9 deletions app/src/main/java/ai/sonario/app/data/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import android.content.Context
enum class EngineChoice { ON_DEVICE, GROQ }

/**
* Simple local settings, backed by SharedPreferences. Stores the engine choice,
* the user's Groq API key, and the Groq model string. The key never leaves the
* device except in the Authorization header of requests the user initiates.
* Simple local settings, backed by SharedPreferences. Stores the engine choice
* and the user's Groq API key. Cloud inference is intentionally pinned to one
* supported model so stale saved sessions cannot restore a retired model ID.
*/
class Settings(context: Context) {
private val prefs = context.applicationContext
Expand All @@ -24,19 +24,29 @@ class Settings(context: Context) {
get() = prefs.getString(KEY_GROQ_KEY, null)
set(v) = prefs.edit().putString(KEY_GROQ_KEY, v?.trim()).apply()

/**
* Kept as a property for saved-session compatibility, but Sonario no longer
* accepts an arbitrary cloud model. Reading or writing this value always
* migrates it to the current fixed model.
*/
var groqModel: String
get() = prefs.getString(KEY_GROQ_MODEL, DEFAULT_GROQ_MODEL)
?: DEFAULT_GROQ_MODEL
set(v) = prefs.edit().putString(KEY_GROQ_MODEL,
v.trim().ifBlank { DEFAULT_GROQ_MODEL }).apply()
get() {
if (prefs.getString(KEY_GROQ_MODEL, null) != DEFAULT_GROQ_MODEL) {
prefs.edit().putString(KEY_GROQ_MODEL, DEFAULT_GROQ_MODEL).apply()
}
return DEFAULT_GROQ_MODEL
}
set(@Suppress("UNUSED_PARAMETER") value) {
prefs.edit().putString(KEY_GROQ_MODEL, DEFAULT_GROQ_MODEL).apply()
}

val hasGroqKey: Boolean get() = !groqApiKey.isNullOrBlank()

companion object {
private const val KEY_ENGINE = "engine"
private const val KEY_GROQ_KEY = "groq_api_key"
private const val KEY_GROQ_MODEL = "groq_model"
// Default model. Groq's lineup changes; this is user-editable in Settings.
const val DEFAULT_GROQ_MODEL = "meta-llama/llama-4-scout-17b-16e-instruct"

const val DEFAULT_GROQ_MODEL = "qwen/qwen3.6-27b"
}
}
Loading
Loading