@glassly/engine 0.3.8-dev.997 → 0.3.8-dev.999
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/engine.d.ts +2 -0
- package/build/engine.d.ts.map +1 -1
- package/build/facades/ai.d.ts +3 -0
- package/build/facades/ai.d.ts.map +1 -1
- package/build/facades/ai.js +3 -0
- package/build/facades/ai.js.map +1 -1
- package/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +5 -0
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js +2 -0
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/LocalTranslationService.d.ts +2 -0
- package/build/services/LocalTranslationService.d.ts.map +1 -1
- package/build/services/LocalTranslationService.js +22 -0
- package/build/services/LocalTranslationService.js.map +1 -1
- package/build/services/OfflineActivity.d.ts +54 -0
- package/build/services/OfflineActivity.d.ts.map +1 -0
- package/build/services/OfflineActivity.js +86 -0
- package/build/services/OfflineActivity.js.map +1 -0
- package/build/services/STTModelManager.d.ts +1 -0
- package/build/services/STTModelManager.d.ts.map +1 -1
- package/build/services/STTModelManager.js +6 -0
- package/build/services/STTModelManager.js.map +1 -1
- package/build/services/controllers.d.ts.map +1 -1
- package/build/services/controllers.js +1 -0
- package/build/services/controllers.js.map +1 -1
- package/build/services/effectiveCapabilities.js +3 -1
- package/build/services/effectiveCapabilities.js.map +1 -1
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +7 -0
- package/build/stores/settings.js.map +1 -1
- package/build/types/capabilities/memomind-one.d.ts.map +1 -1
- package/build/types/capabilities/memomind-one.js +1 -0
- package/build/types/capabilities/memomind-one.js.map +1 -1
- package/build/types/capabilities/rayneo-io.d.ts.map +1 -1
- package/build/types/capabilities/rayneo-io.js +3 -2
- package/build/types/capabilities/rayneo-io.js.map +1 -1
- package/build/types/enums.d.ts +2 -1
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +1 -0
- package/build/types/enums.js.map +1 -1
- package/package.json +7 -7
- package/src/facades/ai.ts +4 -0
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/index.ts +8 -0
- package/src/services/LocalMiniappRuntime.ts +4 -0
- package/src/services/LocalSttFallbackCoordinator.ts +4 -0
- package/src/services/LocalTranslationService.ts +20 -0
- package/src/services/OfflineActivity.ts +131 -0
- package/src/services/STTModelManager.ts +6 -0
- package/src/services/controllers.ts +1 -0
- package/src/services/effectiveCapabilities.ts +3 -1
- package/src/stores/settings.ts +7 -0
- package/src/types/capabilities/memomind-one.ts +1 -0
- package/src/types/capabilities/rayneo-io.ts +3 -2
- package/src/types/enums.ts +1 -0
package/build/types/enums.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare enum ControllerTypes {
|
|
|
20
20
|
APPLE_WATCH = "Apple Watch",
|
|
21
21
|
WEAR_OS = "Wear OS Watch",
|
|
22
22
|
GAMEBRICK = "IINE Gamebrick",
|
|
23
|
-
IINE_ANANKE = "IINE Ananke Gen 2"
|
|
23
|
+
IINE_ANANKE = "IINE Ananke Gen 2",
|
|
24
|
+
ZERO2 = "8BitDo Zero 2"
|
|
24
25
|
}
|
|
25
26
|
//# sourceMappingURL=enums.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,SAAS,sBAAsB;IAC/B,IAAI,SAAS;IACb,EAAE,sBAAsB;IACxB,EAAE,sBAAsB;IACxB,IAAI,gBAAgB;IACpB,KAAK,iBAAiB;IACtB,IAAI,eAAe;IACnB,GAAG,mBAAmB;IACtB,IAAI,SAAS;IACb,KAAK,oBAAoB;IACzB,SAAS,cAAc;IACvB,YAAY,iBAAiB;CAC9B;AAED,oBAAY,eAAe;IACzB,EAAE,sBAAsB;IACxB,WAAW,qBAAqB;IAChC,WAAW,gBAAgB;IAC3B,OAAO,kBAAkB;IACzB,SAAS,mBAAmB;IAC5B,WAAW,sBAAsB;
|
|
1
|
+
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,SAAS,sBAAsB;IAC/B,IAAI,SAAS;IACb,EAAE,sBAAsB;IACxB,EAAE,sBAAsB;IACxB,IAAI,gBAAgB;IACpB,KAAK,iBAAiB;IACtB,IAAI,eAAe;IACnB,GAAG,mBAAmB;IACtB,IAAI,SAAS;IACb,KAAK,oBAAoB;IACzB,SAAS,cAAc;IACvB,YAAY,iBAAiB;CAC9B;AAED,oBAAY,eAAe;IACzB,EAAE,sBAAsB;IACxB,WAAW,qBAAqB;IAChC,WAAW,gBAAgB;IAC3B,OAAO,kBAAkB;IACzB,SAAS,mBAAmB;IAC5B,WAAW,sBAAsB;IACjC,KAAK,kBAAkB;CACxB"}
|
package/build/types/enums.js
CHANGED
|
@@ -23,5 +23,6 @@ export var ControllerTypes;
|
|
|
23
23
|
ControllerTypes["WEAR_OS"] = "Wear OS Watch";
|
|
24
24
|
ControllerTypes["GAMEBRICK"] = "IINE Gamebrick";
|
|
25
25
|
ControllerTypes["IINE_ANANKE"] = "IINE Ananke Gen 2";
|
|
26
|
+
ControllerTypes["ZERO2"] = "8BitDo Zero 2";
|
|
26
27
|
})(ControllerTypes || (ControllerTypes = {}));
|
|
27
28
|
//# sourceMappingURL=enums.js.map
|
package/build/types/enums.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,MAAM,CAAN,IAAY,WAcX;AAdD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,8CAA+B,CAAA;IAC/B,4BAAa,CAAA;IACb,uCAAwB,CAAA;IACxB,uCAAwB,CAAA;IACxB,mCAAoB,CAAA;IACpB,qCAAsB,CAAA;IACtB,kCAAmB,CAAA;IACnB,qCAAsB,CAAA;IACtB,4BAAa,CAAA;IACb,wCAAyB,CAAA;IACzB,sCAAuB,CAAA;IACvB,4CAA6B,CAAA;AAC/B,CAAC,EAdW,WAAW,KAAX,WAAW,QActB;AAED,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,MAAM,CAAN,IAAY,WAcX;AAdD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,8CAA+B,CAAA;IAC/B,4BAAa,CAAA;IACb,uCAAwB,CAAA;IACxB,uCAAwB,CAAA;IACxB,mCAAoB,CAAA;IACpB,qCAAsB,CAAA;IACtB,kCAAmB,CAAA;IACnB,qCAAsB,CAAA;IACtB,4BAAa,CAAA;IACb,wCAAyB,CAAA;IACzB,sCAAuB,CAAA;IACvB,4CAA6B,CAAA;AAC/B,CAAC,EAdW,WAAW,KAAX,WAAW,QActB;AAED,MAAM,CAAN,IAAY,eAQX;AARD,WAAY,eAAe;IACzB,2CAAwB,CAAA;IACxB,mDAAgC,CAAA;IAChC,8CAA2B,CAAA;IAC3B,4CAAyB,CAAA;IACzB,+CAA4B,CAAA;IAC5B,oDAAiC,CAAA;IACjC,0CAAuB,CAAA;AACzB,CAAC,EARW,eAAe,KAAf,eAAe,QAQ1B","sourcesContent":["export {HardwareType, HardwareRequirementLevel} from \"@glassly/miniapp/hardware\"\n\nexport enum DeviceTypes {\n NONE = \"None\",\n SIMULATED = \"Simulated Glasses\",\n AR99 = \"AR99\",\n G1 = \"Even Realities G1\",\n G2 = \"Even Realities G2\",\n LIVE = \"Mentra Live\",\n MACH1 = \"Mentra Mach1\",\n Z100 = \"Vuzix Z100\",\n NEX = \"Mentra Display\",\n NIMO = \"NIMO\",\n FRAME = \"Brilliant Frame\",\n RAYNEO_IO = \"RayNeo iO\",\n MEMOMIND_ONE = \"MemoMind One\",\n}\n\nexport enum ControllerTypes {\n R1 = \"Even Realities R1\",\n NEURAL_BAND = \"Meta Neural Band\",\n APPLE_WATCH = \"Apple Watch\",\n WEAR_OS = \"Wear OS Watch\",\n GAMEBRICK = \"IINE Gamebrick\",\n IINE_ANANKE = \"IINE Ananke Gen 2\",\n ZERO2 = \"8BitDo Zero 2\",\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassly/engine",
|
|
3
|
-
"version": "0.3.8-dev.
|
|
3
|
+
"version": "0.3.8-dev.999",
|
|
4
4
|
"description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -97,17 +97,17 @@
|
|
|
97
97
|
"registry": "https://registry.npmjs.org/"
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
|
-
"@glassly/bluetooth-sdk": "0.3.8-dev.
|
|
101
|
-
"@glassly/cloud-client": "0.3.8-dev.
|
|
102
|
-
"@glassly/cloud-protocol": "0.3.8-dev.
|
|
103
|
-
"@glassly/crust": "0.3.8-dev.
|
|
104
|
-
"@glassly/miniapp": "0.3.8-dev.
|
|
100
|
+
"@glassly/bluetooth-sdk": "0.3.8-dev.999",
|
|
101
|
+
"@glassly/cloud-client": "0.3.8-dev.999",
|
|
102
|
+
"@glassly/cloud-protocol": "0.3.8-dev.999",
|
|
103
|
+
"@glassly/crust": "0.3.8-dev.999",
|
|
104
|
+
"@glassly/miniapp": "0.3.8-dev.999",
|
|
105
105
|
"buffer": "^6.0.3",
|
|
106
106
|
"events": "^3.3.0",
|
|
107
107
|
"react-native-marked": "8.3.2",
|
|
108
108
|
"semver": "^7.7.4",
|
|
109
109
|
"typesafe-ts": "^1.7.1",
|
|
110
|
-
"@glassly/llm-providers": "0.3.8-dev.
|
|
110
|
+
"@glassly/llm-providers": "0.3.8-dev.999",
|
|
111
111
|
"@huggingface/jinja": "^0.5.9",
|
|
112
112
|
"jsonrepair": "^3.12.0"
|
|
113
113
|
},
|
package/src/facades/ai.ts
CHANGED
|
@@ -12,6 +12,7 @@ import localLlmModelManager, {
|
|
|
12
12
|
type LocalLlmModelId,
|
|
13
13
|
} from "../services/LocalLlmModelManager"
|
|
14
14
|
import localLlmProvider from "../services/LocalLlmProvider"
|
|
15
|
+
import offlineActivity, {type OfflineActivity} from "../services/OfflineActivity"
|
|
15
16
|
|
|
16
17
|
export const ai = {
|
|
17
18
|
local: {
|
|
@@ -40,4 +41,7 @@ export const ai = {
|
|
|
40
41
|
unload: (): Promise<void> => localLlmProvider.unload(),
|
|
41
42
|
formatBytes: (bytes: number): string => LocalLlmModelManager.formatBytes(bytes),
|
|
42
43
|
},
|
|
44
|
+
offlineActivity: (): OfflineActivity => offlineActivity.current(),
|
|
45
|
+
onOfflineActivity: (listener: (activity: OfflineActivity) => void): (() => void) =>
|
|
46
|
+
offlineActivity.subscribe(listener),
|
|
43
47
|
}
|
|
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
|
|
|
12
12
|
export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "0.3.8",
|
|
15
|
-
"releaseIdentity": "0.3.8-dev.
|
|
16
|
-
"releaseSetId": "glassly-0.3.8-dev.
|
|
17
|
-
"sourceCommit": "
|
|
15
|
+
"releaseIdentity": "0.3.8-dev.999",
|
|
16
|
+
"releaseSetId": "glassly-0.3.8-dev.999",
|
|
17
|
+
"sourceCommit": "15805ad92fd12494432f6f7e1b6ff936f8f1b83d",
|
|
18
18
|
"otaManifestUrl": null,
|
|
19
19
|
"otaManifestSha256": null
|
|
20
20
|
})
|
package/src/index.ts
CHANGED
|
@@ -64,6 +64,14 @@ export type {
|
|
|
64
64
|
LocalLlmModelId,
|
|
65
65
|
} from "./services/LocalLlmModelManager"
|
|
66
66
|
export {DEFAULT_LOCAL_LLM_MODEL, isLocalLlmModelId} from "./services/LocalLlmModelManager"
|
|
67
|
+
export type {
|
|
68
|
+
OfflineActivity,
|
|
69
|
+
OfflineActivityReason,
|
|
70
|
+
OfflineLlmActivity,
|
|
71
|
+
OfflineTranscriptionActivity,
|
|
72
|
+
OfflineTranslationActivity,
|
|
73
|
+
OfflineTranslationPair,
|
|
74
|
+
} from "./services/OfflineActivity"
|
|
67
75
|
|
|
68
76
|
// Shared user memory timeline (engine.memory / Settings > Memory). Entry and
|
|
69
77
|
// session shapes are canonical in @glassly/miniapp (the session.memory
|
|
@@ -57,6 +57,7 @@ import type {AiTier, AiTierProvider, SavedLlmKeys} from "./AiTierResolution"
|
|
|
57
57
|
import {decideLlmRoute, localLlmReason, type LocalLlmReason} from "./LlmRouting"
|
|
58
58
|
import localLlmModelManager from "./LocalLlmModelManager"
|
|
59
59
|
import localLlmProvider from "./LocalLlmProvider"
|
|
60
|
+
import offlineActivity from "./OfflineActivity"
|
|
60
61
|
import {HttpError} from "@glassly/cloud-client"
|
|
61
62
|
import type {
|
|
62
63
|
QuotaStatusPayload,
|
|
@@ -4343,6 +4344,7 @@ class LocalMiniappRuntime {
|
|
|
4343
4344
|
return
|
|
4344
4345
|
}
|
|
4345
4346
|
|
|
4347
|
+
const endActivity = offlineActivity.beginLlm(reason, localLlmModelManager.model(modelId).label)
|
|
4346
4348
|
try {
|
|
4347
4349
|
// webSearch is a vendor server-side grant; the phone has none.
|
|
4348
4350
|
const {webSearch: _webSearch, ...localRequest} = request
|
|
@@ -4367,6 +4369,8 @@ class LocalMiniappRuntime {
|
|
|
4367
4369
|
undefined,
|
|
4368
4370
|
primaryError ?? {code: MiniappErrorCode.AI_LOCAL_UNAVAILABLE, message},
|
|
4369
4371
|
)
|
|
4372
|
+
} finally {
|
|
4373
|
+
endActivity()
|
|
4370
4374
|
}
|
|
4371
4375
|
}
|
|
4372
4376
|
|
|
@@ -2,6 +2,7 @@ import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
|
|
|
2
2
|
import {ISLAND_SETTINGS_KEYS} from "../runtime/config"
|
|
3
3
|
import {useSettingsStore} from "../stores/settings"
|
|
4
4
|
import {cloudClientService} from "./CloudClientService"
|
|
5
|
+
import offlineActivity from "./OfflineActivity"
|
|
5
6
|
import sttModelManager from "./STTModelManager"
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -223,6 +224,9 @@ class LocalSttFallbackCoordinator {
|
|
|
223
224
|
|
|
224
225
|
private publishReason(): void {
|
|
225
226
|
const reason = this.localActive ? this.currentReason() : ""
|
|
227
|
+
offlineActivity.setTranscription(
|
|
228
|
+
this.localActive ? {reason: this.currentReason(), model: sttModelManager.currentModelLabel()} : null,
|
|
229
|
+
)
|
|
226
230
|
const store = useSettingsStore.getState()
|
|
227
231
|
if (store.getSetting(ISLAND_SETTINGS_KEYS.localSttFallbackReason) !== reason) {
|
|
228
232
|
store.setSetting(ISLAND_SETTINGS_KEYS.localSttFallbackReason, reason)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import offlineActivity, {type ServedTranslationPair} from "./OfflineActivity"
|
|
1
2
|
import {offlineTranslationManager} from "./OfflineTranslationManager"
|
|
2
3
|
|
|
3
4
|
/** One concrete-target `translation:<source>:<target>` stream and who listens to it. */
|
|
@@ -67,6 +68,7 @@ export class LocalTranslationService {
|
|
|
67
68
|
|
|
68
69
|
attach(host: Host): void {
|
|
69
70
|
this.host = host
|
|
71
|
+
offlineActivity.setTranslationSource(() => this.servedPairs())
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
setSubscriptions(subscriptions: LocalTranslationSubscription[]): void {
|
|
@@ -75,6 +77,24 @@ export class LocalTranslationService {
|
|
|
75
77
|
for (const key of this.lanes.keys()) {
|
|
76
78
|
if (!live.has(key.substring(key.indexOf(">") + 1))) this.lanes.delete(key)
|
|
77
79
|
}
|
|
80
|
+
offlineActivity.refresh()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
servedPairs(): ServedTranslationPair[] {
|
|
84
|
+
if (!this.host || !offlineTranslationManager.isSupported()) return []
|
|
85
|
+
const pairs = new Map<string, ServedTranslationPair>()
|
|
86
|
+
let primaryUp: boolean | null = null
|
|
87
|
+
for (const sub of this.subscriptions) {
|
|
88
|
+
if (baseLanguage(sub.source) === baseLanguage(sub.target)) continue
|
|
89
|
+
if (!sub.forceLocal) {
|
|
90
|
+
primaryUp ??= this.host.primaryUp()
|
|
91
|
+
if (primaryUp || !sub.cloud) continue
|
|
92
|
+
}
|
|
93
|
+
const key = `${sub.source}>${sub.target}`
|
|
94
|
+
const existing = pairs.get(key)
|
|
95
|
+
pairs.set(key, {source: sub.source, target: sub.target, forceLocal: sub.forceLocal || !!existing?.forceLocal})
|
|
96
|
+
}
|
|
97
|
+
return [...pairs.values()]
|
|
78
98
|
}
|
|
79
99
|
|
|
80
100
|
onLocalTranscript(transcript: LocalTranscript, sourceLanguage: string): void {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the phone is running on-device right now (transcription, translation,
|
|
3
|
+
* LLM) and why, for the home offline card. Producers push in; it imports
|
|
4
|
+
* nothing at runtime so their test stubs stay unaffected.
|
|
5
|
+
*/
|
|
6
|
+
import type {LocalLlmReason} from "./LlmRouting"
|
|
7
|
+
import type {LocalSttFallbackReason} from "./LocalSttFallbackCoordinator"
|
|
8
|
+
|
|
9
|
+
export type OfflineActivityReason = LocalSttFallbackReason | LocalLlmReason
|
|
10
|
+
|
|
11
|
+
export interface OfflineTranscriptionActivity {
|
|
12
|
+
reason: LocalSttFallbackReason
|
|
13
|
+
model: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface OfflineTranslationPair {
|
|
17
|
+
source: string
|
|
18
|
+
target: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface OfflineTranslationActivity {
|
|
22
|
+
reason: OfflineActivityReason
|
|
23
|
+
pairs: OfflineTranslationPair[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface OfflineLlmActivity {
|
|
27
|
+
reason: LocalLlmReason
|
|
28
|
+
model: string
|
|
29
|
+
requests: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface OfflineActivity {
|
|
33
|
+
transcription: OfflineTranscriptionActivity | null
|
|
34
|
+
translation: OfflineTranslationActivity | null
|
|
35
|
+
llm: OfflineLlmActivity | null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ServedTranslationPair extends OfflineTranslationPair {
|
|
39
|
+
forceLocal: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const EMPTY: OfflineActivity = {transcription: null, translation: null, llm: null}
|
|
43
|
+
|
|
44
|
+
class OfflineActivityTracker {
|
|
45
|
+
private transcription: OfflineTranscriptionActivity | null = null
|
|
46
|
+
private llmRuns: Array<{reason: LocalLlmReason; model: string}> = []
|
|
47
|
+
private translationSource: (() => ServedTranslationPair[]) | null = null
|
|
48
|
+
private snapshot: OfflineActivity = EMPTY
|
|
49
|
+
private snapshotKey = JSON.stringify(EMPTY)
|
|
50
|
+
private listeners = new Set<(activity: OfflineActivity) => void>()
|
|
51
|
+
|
|
52
|
+
current(): OfflineActivity {
|
|
53
|
+
return this.snapshot
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
subscribe(listener: (activity: OfflineActivity) => void): () => void {
|
|
57
|
+
this.listeners.add(listener)
|
|
58
|
+
return () => {
|
|
59
|
+
this.listeners.delete(listener)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setTranscription(transcription: OfflineTranscriptionActivity | null): void {
|
|
64
|
+
this.transcription = transcription
|
|
65
|
+
this.refresh()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
beginLlm(reason: LocalLlmReason, model: string): () => void {
|
|
69
|
+
const run = {reason, model}
|
|
70
|
+
this.llmRuns.push(run)
|
|
71
|
+
this.refresh()
|
|
72
|
+
let ended = false
|
|
73
|
+
return () => {
|
|
74
|
+
if (ended) return
|
|
75
|
+
ended = true
|
|
76
|
+
this.llmRuns = this.llmRuns.filter((r) => r !== run)
|
|
77
|
+
this.refresh()
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setTranslationSource(source: (() => ServedTranslationPair[]) | null): void {
|
|
82
|
+
this.translationSource = source
|
|
83
|
+
this.refresh()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
refresh(): void {
|
|
87
|
+
const next: OfflineActivity = {
|
|
88
|
+
transcription: this.transcription,
|
|
89
|
+
translation: this.translation(),
|
|
90
|
+
llm: this.llm(),
|
|
91
|
+
}
|
|
92
|
+
const key = JSON.stringify(next)
|
|
93
|
+
if (key === this.snapshotKey) return
|
|
94
|
+
this.snapshotKey = key
|
|
95
|
+
this.snapshot = next
|
|
96
|
+
for (const listener of this.listeners) {
|
|
97
|
+
try {
|
|
98
|
+
listener(next)
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.warn("OfflineActivity: listener failed:", error)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
reset(): void {
|
|
106
|
+
this.transcription = null
|
|
107
|
+
this.llmRuns = []
|
|
108
|
+
this.translationSource = null
|
|
109
|
+
this.refresh()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private translation(): OfflineTranslationActivity | null {
|
|
113
|
+
if (!this.transcription || !this.translationSource) return null
|
|
114
|
+
const pairs = this.translationSource()
|
|
115
|
+
if (pairs.length === 0) return null
|
|
116
|
+
return {
|
|
117
|
+
reason: pairs.some((p) => p.forceLocal) ? "force_local" : this.transcription.reason,
|
|
118
|
+
pairs: pairs.map(({source, target}) => ({source, target})),
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private llm(): OfflineLlmActivity | null {
|
|
123
|
+
const latest = this.llmRuns[this.llmRuns.length - 1]
|
|
124
|
+
if (!latest) return null
|
|
125
|
+
return {reason: latest.reason, model: latest.model, requests: this.llmRuns.length}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export {OfflineActivityTracker}
|
|
130
|
+
const offlineActivity = new OfflineActivityTracker()
|
|
131
|
+
export default offlineActivity
|
|
@@ -228,6 +228,12 @@ class STTModelManager {
|
|
|
228
228
|
return this.currentLanguage
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
currentModelLabel(): string {
|
|
232
|
+
const language = this.config(this.currentLanguage)
|
|
233
|
+
if (!language) return this.currentLanguage
|
|
234
|
+
return language.type === "apple" ? `Apple · ${language.displayName}` : language.displayName
|
|
235
|
+
}
|
|
236
|
+
|
|
231
237
|
setCurrentLanguage(code: string): void {
|
|
232
238
|
if (this.config(code)) {
|
|
233
239
|
this.currentLanguage = code
|
|
@@ -55,6 +55,7 @@ const INPUT_SURFACES: Readonly<Record<string, readonly InputSurface[]>> = {
|
|
|
55
55
|
[ControllerTypes.WEAR_OS]: [WATCH_SURFACE],
|
|
56
56
|
[ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],
|
|
57
57
|
[ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],
|
|
58
|
+
[ControllerTypes.ZERO2]: [GAMEBRICK_SURFACE],
|
|
58
59
|
[ControllerTypes.R1]: [],
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -61,6 +61,8 @@ function glassesCapabilities(model: DeviceTypes): Capabilities {
|
|
|
61
61
|
// Glassly CFW supports the complete vector contract, including SVG and rotation.
|
|
62
62
|
// Upstream g2flash publishes a raster canvas with sceneVector=false.
|
|
63
63
|
const vector = useGlassesStore.getState().sceneVector === true
|
|
64
|
+
// Depth is a disparity between the lenses; one panel (MemoMind One) draws every element flat.
|
|
65
|
+
const stereo = (base.display.count ?? 1) >= 2
|
|
64
66
|
return {
|
|
65
67
|
...(volumeGate ? withVolumeGate(base) : base),
|
|
66
68
|
hasNativeNavigation: resolveNativeNavigation(base.hasNativeNavigation, true, forceNativeNavigationOnCfw()),
|
|
@@ -81,7 +83,7 @@ function glassesCapabilities(model: DeviceTypes): Capabilities {
|
|
|
81
83
|
vector ? CFW_VECTOR_MAX_ELEMENTS : CFW_MAX_IMAGE_ELEMENTS,
|
|
82
84
|
),
|
|
83
85
|
...(vector
|
|
84
|
-
? {shapes: [...ALL_DISPLAY_SHAPES, "svg" as const], animation: true, rotation: true, depth:
|
|
86
|
+
? {shapes: [...ALL_DISPLAY_SHAPES, "svg" as const], animation: true, rotation: true, depth: stereo}
|
|
85
87
|
: {}),
|
|
86
88
|
},
|
|
87
89
|
}
|
package/src/stores/settings.ts
CHANGED
|
@@ -930,6 +930,13 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
930
930
|
saveOnServer: false,
|
|
931
931
|
persist: true,
|
|
932
932
|
},
|
|
933
|
+
home_offline_card: {
|
|
934
|
+
key: "home_offline_card",
|
|
935
|
+
defaultValue: () => true,
|
|
936
|
+
writable: true,
|
|
937
|
+
saveOnServer: false,
|
|
938
|
+
persist: true,
|
|
939
|
+
},
|
|
933
940
|
// Gesture-dots debug indicator: flash a glyph on the glasses when a touch
|
|
934
941
|
// gesture is received while the display is empty. Works on any
|
|
935
942
|
// scene-capable device, not only CFW. Device-local debug knob, default off.
|
|
@@ -19,10 +19,11 @@ export const rayneoIO: Capabilities = {
|
|
|
19
19
|
hasCamera: false,
|
|
20
20
|
camera: null,
|
|
21
21
|
|
|
22
|
-
// Display capabilities -
|
|
22
|
+
// Display capabilities - a monochrome panel per eye; the Glassly CFW keeps
|
|
23
|
+
// a scene per lens, so element depth is a real disparity here
|
|
23
24
|
hasDisplay: true,
|
|
24
25
|
display: {
|
|
25
|
-
count:
|
|
26
|
+
count: 2,
|
|
26
27
|
isColor: false,
|
|
27
28
|
color: "green",
|
|
28
29
|
// Bitmaps and positioned elements need the Glassly CFW; stock firmware
|