Skip to content

Commit

Permalink
[fix] TTS failed in Android
Browse files Browse the repository at this point in the history
[optimize] Loading state of Recognition model
  • Loading branch information
TechQuery committed Oct 7, 2024
1 parent a8909ce commit fe8724c
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 41 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"dom-renderer": "^2.3.0",
"iterable-observer": "^1.1.0",
"mobx": "^6.13.3",
"mobx-restful": "^1.0.1",
"tesseract.js": "^5.1.1",
"web-cell": "^3.0.0",
"web-utility": "^4.4.0"
Expand Down
91 changes: 83 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions src/model/OCR.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { computed, observable } from 'mobx';
import { createWorker,ImageLike, LoggerMessage } from 'tesseract.js';
import { BaseModel, toggle } from 'mobx-restful';
import { createWorker, ImageLike, LoggerMessage } from 'tesseract.js';

export class OCRModel {
constructor(public language = 'chi_sim') {}
export class OCRModel extends BaseModel {
constructor(public language = 'chi_sim') {
super();
}

@observable
accessor currentProgress: LoggerMessage | undefined;
Expand All @@ -15,6 +18,7 @@ export class OCRModel {
@observable
accessor resultText: string | undefined;

@toggle('uploading')
async recognize(image: ImageLike) {
const worker = await createWorker(this.language, 1, {
logger: message => (this.currentProgress = message)
Expand Down
52 changes: 26 additions & 26 deletions src/model/TTS.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { observable } from 'mobx';
import { getVisibleText } from 'web-utility';
import { getVisibleText, sleep } from 'web-utility';

export enum TTSState {
Clear,
Expand All @@ -26,6 +26,8 @@ export class TTSModel {
return voices[0]
? Promise.resolve(voices)
: new Promise<SpeechSynthesisVoice[]>(resolve => {
sleep(1).then(() => resolve([]));

speechSynthesis.onvoiceschanged = () =>
resolve(speechSynthesis.getVoices());
});
Expand Down Expand Up @@ -81,36 +83,34 @@ export class TTSModel {
}
}

static getSelectedText(box: Element) {
static getSelectedText(box?: Element) {
const range = getSelection()?.getRangeAt(0);

if (
range &&
range + '' &&
(!box || box.contains(range.commonAncestorContainer))
)
return [...this.walk(range)]
.filter(({ nodeType, parentNode }) => {
if (nodeType !== 3) return;

const { width, height } = (
parentNode as Element
).getBoundingClientRect();

return width && height;
})
.map(({ nodeValue }, index, { length }) =>
nodeValue.slice(
index === 0 ? range.startOffset : 0,
index === length - 1 ? range.endOffset : Infinity
)
if (!range?.toString() || !box?.contains(range.commonAncestorContainer))
throw new RangeError('No text selected');

return [...this.walk(range)]
.filter(({ nodeType, parentNode }) => {
if (nodeType !== 3) return;

const { width, height } = (
parentNode as Element
).getBoundingClientRect();

return width && height;
})
.map(({ nodeValue }, index, { length }) =>
nodeValue.slice(
index === 0 ? range.startOffset : 0,
index === length - 1 ? range.endOffset : Infinity
)
.filter(text => text.trim())
.join('')
.trim();
)
.filter(text => text.trim())
.join('')
.trim();
}

static getReadableText(box: Element) {
static getReadableText(box?: Element) {
try {
return this.getSelectedText(box);
} catch {
Expand Down
9 changes: 5 additions & 4 deletions src/page/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, ProgressBar } from 'boot-cell';
import { Button, ProgressBar, SpinnerBox } from 'boot-cell';
import { observable } from 'mobx';
import { component, observer } from 'web-cell';
import { CustomElement } from 'web-utility';
Expand Down Expand Up @@ -38,11 +38,12 @@ export class HomePage extends HTMLElement implements CustomElement {

render() {
const { storeOCR, storeTTS, cameraOpened } = this;
const { currentPercent, resultText } = storeOCR,
const { uploading, currentPercent, resultText } = storeOCR;
const recognizing = uploading > 0,
speaking = storeTTS.state === TTSState.Speaking;

return (
<>
<SpinnerBox cover={recognizing}>
<header className="d-flex justify-content-around">
<Button
variant="danger"
Expand Down Expand Up @@ -75,7 +76,7 @@ export class HomePage extends HTMLElement implements CustomElement {
}
/>
<article>{resultText}</article>
</>
</SpinnerBox>
);
}
}

0 comments on commit fe8724c

Please sign in to comment.