update for whisper
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "mobile-voice",
|
||||
"name": "Control",
|
||||
"slug": "mobile-voice",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
@@ -10,6 +10,9 @@
|
||||
"ios": {
|
||||
"icon": "./assets/images/icon.png",
|
||||
"bundleIdentifier": "com.anomalyco.mobilevoice",
|
||||
"entitlements": {
|
||||
"com.apple.developer.kernel.extended-virtual-addressing": true
|
||||
},
|
||||
"infoPlist": {
|
||||
"NSMicrophoneUsageDescription": "This app needs microphone access for live speech-to-text dictation.",
|
||||
"NSAppTransportSecurity": {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"lint": "expo lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fugood/react-native-audio-pcm-stream": "1.1.4",
|
||||
"@react-navigation/bottom-tabs": "^7.15.5",
|
||||
"@react-navigation/elements": "^2.9.10",
|
||||
"@react-navigation/native": "^7.1.33",
|
||||
@@ -41,14 +42,13 @@
|
||||
"react-dom": "19.2.0",
|
||||
"react-native": "0.83.4",
|
||||
"react-native-audio-api": "^0.11.7",
|
||||
"react-native-executorch": "^0.8.0",
|
||||
"react-native-executorch-expo-resource-fetcher": "^0.8.0",
|
||||
"react-native-gesture-handler": "~2.30.0",
|
||||
"react-native-reanimated": "4.2.1",
|
||||
"react-native-safe-area-context": "~5.6.2",
|
||||
"react-native-screens": "~4.23.0",
|
||||
"react-native-web": "~0.21.0",
|
||||
"react-native-worklets": "0.7.2"
|
||||
"react-native-worklets": "0.7.2",
|
||||
"whisper.rn": "0.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "~19.2.2",
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
import React from 'react';
|
||||
import { Slot } from 'expo-router';
|
||||
import { LogBox } from 'react-native';
|
||||
import { initExecutorch } from 'react-native-executorch';
|
||||
import { ExpoResourceFetcher } from 'react-native-executorch-expo-resource-fetcher';
|
||||
import React from "react"
|
||||
import { Slot } from "expo-router"
|
||||
import { LogBox } from "react-native"
|
||||
import {
|
||||
configureNotificationBehavior,
|
||||
registerBackgroundNotificationTask,
|
||||
} from '@/notifications/monitoring-notifications';
|
||||
|
||||
// Initialize the ExecuTorch resource fetcher before any model hooks run
|
||||
initExecutorch({ resourceFetcher: ExpoResourceFetcher });
|
||||
} from "@/notifications/monitoring-notifications"
|
||||
|
||||
// Suppress known non-actionable warnings from third-party libs.
|
||||
LogBox.ignoreLogs([
|
||||
'RecordingNotificationManager is not implemented on iOS',
|
||||
'[React Native ExecuTorch] No content-length header',
|
||||
]);
|
||||
"RecordingNotificationManager is not implemented on iOS",
|
||||
"`transcribeRealtime` is deprecated, use `RealtimeTranscriber` instead",
|
||||
])
|
||||
|
||||
configureNotificationBehavior();
|
||||
registerBackgroundNotificationTask().catch(() => {});
|
||||
configureNotificationBehavior()
|
||||
registerBackgroundNotificationTask().catch(() => {})
|
||||
|
||||
export default function RootLayout() {
|
||||
return <Slot />;
|
||||
return <Slot />
|
||||
}
|
||||
|
||||
+1187
-273
File diff suppressed because it is too large
Load Diff
+138
@@ -0,0 +1,138 @@
|
||||
declare module "whisper.rn" {
|
||||
export type TranscribeOptions = {
|
||||
language?: string
|
||||
translate?: boolean
|
||||
maxLen?: number
|
||||
prompt?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type TranscribeResult = {
|
||||
result: string
|
||||
language: string
|
||||
segments: {
|
||||
text: string
|
||||
t0: number
|
||||
t1: number
|
||||
}[]
|
||||
isAborted?: boolean
|
||||
}
|
||||
|
||||
export type TranscribeRealtimeEvent = {
|
||||
contextId: number
|
||||
jobId: number
|
||||
isCapturing: boolean
|
||||
isStoppedByAction?: boolean
|
||||
code: number
|
||||
data?: TranscribeResult
|
||||
error?: string
|
||||
processTime: number
|
||||
recordingTime: number
|
||||
}
|
||||
|
||||
export type TranscribeRealtimeOptions = TranscribeOptions & {
|
||||
realtimeAudioSec?: number
|
||||
realtimeAudioSliceSec?: number
|
||||
realtimeAudioMinSec?: number
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type WhisperContext = {
|
||||
id: number
|
||||
gpu: boolean
|
||||
reasonNoGPU: string
|
||||
transcribeRealtime(options?: TranscribeRealtimeOptions): Promise<{
|
||||
stop: () => Promise<void>
|
||||
subscribe: (callback: (event: TranscribeRealtimeEvent) => void) => void
|
||||
}>
|
||||
transcribeData(
|
||||
data: ArrayBuffer,
|
||||
options?: TranscribeOptions,
|
||||
): {
|
||||
stop: () => Promise<void>
|
||||
promise: Promise<TranscribeResult>
|
||||
}
|
||||
release(): Promise<void>
|
||||
}
|
||||
|
||||
export type ContextOptions = {
|
||||
filePath: string | number
|
||||
useGpu?: boolean
|
||||
useCoreMLIos?: boolean
|
||||
useFlashAttn?: boolean
|
||||
}
|
||||
|
||||
export function initWhisper(options: ContextOptions): Promise<WhisperContext>
|
||||
export function releaseAllWhisper(): Promise<void>
|
||||
}
|
||||
|
||||
declare module "whisper.rn/realtime-transcription/index" {
|
||||
import type { TranscribeOptions, TranscribeResult, WhisperContext } from "whisper.rn"
|
||||
|
||||
export type RealtimeTranscribeEvent = {
|
||||
type: "start" | "transcribe" | "end" | "error"
|
||||
sliceIndex: number
|
||||
data?: TranscribeResult
|
||||
isCapturing: boolean
|
||||
processTime: number
|
||||
recordingTime: number
|
||||
}
|
||||
|
||||
export type RealtimeOptions = {
|
||||
audioSliceSec?: number
|
||||
audioMinSec?: number
|
||||
maxSlicesInMemory?: number
|
||||
transcribeOptions?: TranscribeOptions
|
||||
logger?: (message: string) => void
|
||||
}
|
||||
|
||||
export type RealtimeTranscriberCallbacks = {
|
||||
onTranscribe?: (event: RealtimeTranscribeEvent) => void
|
||||
onError?: (error: string) => void
|
||||
onStatusChange?: (isActive: boolean) => void
|
||||
}
|
||||
|
||||
export type RealtimeTranscriberDependencies = {
|
||||
whisperContext: WhisperContext
|
||||
audioStream: unknown
|
||||
vadContext?: unknown
|
||||
fs?: unknown
|
||||
}
|
||||
|
||||
export class RealtimeTranscriber {
|
||||
constructor(
|
||||
dependencies: RealtimeTranscriberDependencies,
|
||||
options?: RealtimeOptions,
|
||||
callbacks?: RealtimeTranscriberCallbacks,
|
||||
)
|
||||
start(): Promise<void>
|
||||
stop(): Promise<void>
|
||||
release(): Promise<void>
|
||||
updateCallbacks(callbacks: Partial<RealtimeTranscriberCallbacks>): void
|
||||
}
|
||||
}
|
||||
|
||||
declare module "whisper.rn/realtime-transcription" {
|
||||
export * from "whisper.rn/realtime-transcription/index"
|
||||
}
|
||||
|
||||
declare module "whisper.rn/src/realtime-transcription" {
|
||||
export * from "whisper.rn/realtime-transcription/index"
|
||||
}
|
||||
|
||||
declare module "whisper.rn/realtime-transcription/adapters/AudioPcmStreamAdapter" {
|
||||
export class AudioPcmStreamAdapter {
|
||||
initialize(config: Record<string, unknown>): Promise<void>
|
||||
start(): Promise<void>
|
||||
stop(): Promise<void>
|
||||
isRecording(): boolean
|
||||
onData(callback: (data: unknown) => void): void
|
||||
onError(callback: (error: string) => void): void
|
||||
onStatusChange(callback: (isRecording: boolean) => void): void
|
||||
release(): Promise<void>
|
||||
}
|
||||
}
|
||||
|
||||
declare module "whisper.rn/src/realtime-transcription/adapters/AudioPcmStreamAdapter" {
|
||||
export * from "whisper.rn/realtime-transcription/adapters/AudioPcmStreamAdapter"
|
||||
}
|
||||
@@ -139,8 +139,8 @@ async function notify(input: { type: Type; sessionID: string }): Promise<Notify>
|
||||
const session = await Session.get(sessionID)
|
||||
out.title = session.title
|
||||
|
||||
let latestUser: string | undefined
|
||||
for await (const msg of MessageV2.stream(sessionID)) {
|
||||
if (msg.info.role !== "user") continue
|
||||
const body = msg.parts
|
||||
.map((part) => {
|
||||
if (part.type !== "text") return ""
|
||||
@@ -151,8 +151,19 @@ async function notify(input: { type: Type; sessionID: string }): Promise<Notify>
|
||||
.join(" ")
|
||||
const next = words(body)
|
||||
if (!next) continue
|
||||
out.body = next
|
||||
break
|
||||
|
||||
if (msg.info.role === "assistant") {
|
||||
out.body = next
|
||||
break
|
||||
}
|
||||
|
||||
if (!latestUser && msg.info.role === "user") {
|
||||
latestUser = next
|
||||
}
|
||||
}
|
||||
|
||||
if (!out.body) {
|
||||
out.body = latestUser
|
||||
}
|
||||
} catch (error) {
|
||||
log.info("notification metadata unavailable", {
|
||||
|
||||
Reference in New Issue
Block a user