agent: связь с сервером + UI-экраны + ASR Qwen3 + settings

This commit is contained in:
2026-09-23 11:53:57 +03:00
parent d5aa844fa0
commit b923bc6196
29 changed files with 3845 additions and 32 deletions
@@ -1,9 +1,77 @@
package pw.binom.agentik.android
import android.app.Application
import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import pw.binom.agentik.android.agent.AgentConnection
import pw.binom.agentik.android.agent.real.HttpAgentConnection
import pw.binom.agentik.android.asr.QwenDownloadWorker
import pw.binom.agentik.android.settings.SettingsRepository
import java.util.concurrent.TimeUnit
/**
* Точка входа приложения. Пока пустая: сюда будут подниматься настройки
* (адрес агента и токен) и хранилище.
* Точка входа приложения. Поднимает фоновые сервисы:
* - периодический [QwenDownloadWorker]: раз в 6 часов проверяет/докачивает голосовую модель
* Qwen3-ASR по Wi-Fi (UNMETERED). Зарегистрирован через [ExistingPeriodicWorkPolicy.KEEP],
* чтобы перезапуск приложения не сбрасывал уже запланированный запуск и не дёргал воркер
* лишний раз.
* - singleton-фабрика [agentConnection] — единая точка подключения к агенту,
* живёт до вызова `close()` (никогда в этой PR — приложение короткоживущее).
* В фазах тестирования можно подменить на stub: `(application as AgentikApp).agentConnection = StubAgentConnection(...)`.
* - [settingsRepository] — JSON-персистентность [pw.binom.agentik.android.settings.Settings]
* в `filesDir/settings.json`. Передаётся в UI через [MainActivity].
*/
class AgentikApp : Application()
class AgentikApp : Application() {
/**
* Singleton-фабрика агента-фасада. Создаётся лениво при первом обращении,
* живёт до вызова `close()` (никогда в этой PR — приложение короткоживущее).
*
* NB: используем `lateinit` (а не `by Delegates.notNull()`), чтобы
* работал `::agentConnection.isInitialized` — `Delegates.notNull()`
* делегат не поддерживает эту проверку.
*/
lateinit var agentConnection: AgentConnection
private set
/**
* Singleton-репозиторий для JSON-персистентности настроек в `filesDir/settings.json`.
* Создаётся лениво при первом обращении (после `onCreate()`) — `Application`
* сам передаёт себя как `Context`.
*/
val settingsRepository: SettingsRepository by lazy { SettingsRepository(this) }
override fun onCreate() {
super.onCreate()
if (!::agentConnection.isInitialized) {
agentConnection = HttpAgentConnection(context = this)
}
scheduleQwenDownload()
}
private fun scheduleQwenDownload() {
val request = PeriodicWorkRequestBuilder<QwenDownloadWorker>(6, TimeUnit.HOURS)
.setConstraints(
Constraints.Builder()
// Wi-Fi only — мобильная сеть не качает 940 МБ.
.setRequiredNetworkType(NetworkType.UNMETERED)
.build(),
)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.MINUTES)
.build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
UNIQUE_WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
request,
)
}
private companion object {
const val UNIQUE_WORK_NAME = "qwen-model-download"
}
}