-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New JavaScript api for TTS #8812
Conversation
First PR! 🚀 We sincerely appreciate that you have taken the time to propose a change to AnkiDroid! Please have patience with us as we are all volunteers - we will get to this as soon as possible. |
This features looks good. Can you add how to test it in It will be added after merge of this PR to https://github.com/ankidroid/Anki-Android/wiki/AnkiDroid-Javascript-API |
This is a sample template. {{FrontSide}}
<hr id=answer>
<div class='jsTts'>
{{BackSide}}
</div>
<script>
// Select the text for TTS.
const jsTts = document.querySelector(".jsTts");
const text = jsTts.textContent;
// Select TTS language
AnkiDroidJS.ankiTtsSetLanguage('en-US');
// Select the speed of TTS.
AnkiDroidJS.ankiTtsSetSpeechRate(1.5);
// Speak
AnkiDroidJS.ankiTtsSpeak(text);
// Change TTS pitch and speed.
AnkiDroidJS.ankiTtsSetPitch(1.1)
AnkiDroidJS.ankiTtsSetSpeechRate(0.8);
// Speak
// If you add "1" to the second argument, it will wait until the previous Speak ends before speaking.
AnkiDroidJS.ankiTtsSpeak(text,1);
// Restore the pitch and speed of the TTS.
AnkiDroidJS.ankiTtsSetSpeechRate(1);
AnkiDroidJS.ankiTtsSetPitch(1)
</script> |
Looks good to me. Wait for review from maintainers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT: This comment no longer applies
Hi, thanks for the PR, and sorry for the slow review.
JavaScript API changes are very delicate: if we make the wrong step, we'd be forced to break clients. We have three variables to worry about, and each of these can cause pain for the API clients if we don't handle them correctly:
- AnkiDroid version (under our control: defines the available APIs). Defined by both Android version (we do stop supporting old Androids) and user choice (users can downgrade and upgrade AnkiDroid).
- Deck API version (deck creators control this).
- Android version (user control, but typically immutable and not well informed WRT AnkiDroid).
This adds a dependency between Android version and Deck API version: there's a potential for breakage if we don't code this well, and a deck using an old API is used with a newer Android version.
I don't think we've introduced a dependency like this, and there'll be some discussion to ensure that we handle it with as much care for our downstream API clients as possible. "I upgraded my phone and AnkiDroid broke" is a terrible place to be in, especially if they depend on a deck which both uses JavaScript and isn't maintained
My main comment requires a second look from @mikehardy,
Most comments are quick nitpicks which can be solved quickly
AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java
Outdated
Show resolved
Hide resolved
AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java
Outdated
Show resolved
Hide resolved
Since it is unlikely that a beginner will handle this api, I moved the functions on the android side to JavaScript with as little modification as possible. Since the function conversion rules have been simplified, the api can be extended with consistent rules even if other TTS functions are needed on the JavaScript side in the future.
Moved the localeFromStringIgnoringScriptAndExtensions function to the LanguageUtils class.
I tried to modify the code according to the polite review comments. Regarding the practicality of the API, I have already imported it into my ankidroid and verified it, so I will give an example. In addition, since the introduction of the JS add-on to Ankidroid has been proposed, I feel that sooner or later an api that handles TTS on JS will be required. |
Fixed a problem that null may be passed as an argument when initializing JavaScriptTTS. Changed to refer to context from within the class instead of the argument when initializing JavaScriptTTS.
Amazing!!! can't wait for this to added!! thank you all for your great work! |
There was a tiny conflict from recent work in the codebase and the PR was not rebase-merge-able anyway, so I fixed the conflict to get a CI run in with current code |
OK - tagged this up for review, and unrelated to anything @mikunimaru I was looking at a different issue (hermes vm sort not stable, related to a react-native repo I manage) and if I'm not mistaken I saw you in there! Small world :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do it! Thanks @mikunimaru
@mikunimaru |
Hi there! Apologies for the delay, and if you're already submitted something to OpenCollective for PRs merged in August 2021, you may feel free to ignore this and it will be processed shortly Just a friendly notice that we try to process OpenCollective payments monthly - it's time for August 2021 submissions If you are interested in compensation for this work, the process with details is here: (I only post one comment per person to avoid spamming you, regardless of the number of PRs merged, but this note applies to all PRs merged for in the month of August) Thanks! |
I just want to say a big thank you to all of you for this feature! I subscribed to the beta to get it as soon as possible. For an unrelated problem, I had to install the alpha version AnkiDroid-2.16. Out of curiosity I tested the script given above and it worked! This is super giga top cool! |
Yeah, @infinyte7 has been doing great work on the JS APIs in general and then @mikunimaru stepped in here with this 💎 - it is pretty cool that any of this is possible in my opinion |
@mikunimaru thanks for you great work!!! Been waiting for this very long time , can you please simplify what to add in front and back card tempelate to get TTS work on ankidroid and ankidesktop ? |
@AbdelrahmanHamdy1998 The simplest TTS script is :
The "some text here" can be loaded from a variable that you retrieve from the HTML via regular javascript function like You don't need to set the pitch and the Speech rate. I don't know about ankidestop but I guess AnkiDroidJS would probably not work |
<script>
var jsTts = document.querySelector(".cloze");
var text = jsTts.textContent;
AnkiDroidJS.ankiTtsSpeak(text,1);
</script>
<div id="text_id">{{cloze:Text}}</div>
<script>
var text = document.getElementById("text_id").textContent;
AnkiDroidJS.ankiTtsSpeak(text,1);
</script> @mikunimaru |
@infinyte7 I'm not good at English, so the difficulty of creating a document is quite high. // Select TTS language
// https://developer.android.com/reference/android/speech/tts/TextToSpeech#setLanguage(java.util.Locale)
// @return
// 0 Denotes the language is available for the language by the locale, but not the country and variant.
// 1 Denotes the language is available for the language and country specified by the locale, but not the variant.
// 2 Denotes the language is available exactly as specified by the locale.
// -1 Denotes the language data is missing.
// -2 Denotes the language is not supported.
AnkiDroidJS.ankiTtsSetLanguage('en-US');
// Speak
// https://developer.android.com/reference/android/speech/tts/TextToSpeech#speak(java.lang.CharSequence,%20int,%20android.os.Bundle,%20java.lang.String)
// @return ERROR(-1) SUCCESS(0)
AnkiDroidJS.ankiTtsSpeak(text);
// If you add "1" to the second argument, it will wait until the previous Speak ends before speaking.
AnkiDroidJS.ankiTtsSpeak(text,1);
// Change TTS pitch and speed.
// https://developer.android.com/reference/android/speech/tts/TextToSpeech#setPitch(float)
// https://developer.android.com/reference/android/speech/tts/TextToSpeech#setSpeechRate(float)
// @return ERROR(-1) SUCCESS(0)
AnkiDroidJS.ankiTtsSetPitch(1.1);
AnkiDroidJS.ankiTtsSetSpeechRate(0.8);
// Int is also available
AnkiDroidJS.ankiTtsSetSpeechRate(1);
AnkiDroidJS.ankiTtsSetPitch(1)
// Whether the app is currently speaking (boolean)
// https://developer.android.com/reference/android/speech/tts/TextToSpeech#isSpeaking()
let isSpeaking = AnkiDroidJS.ankiTtsIsSpeaking();
// Stop speech
// https://developer.android.com/reference/android/speech/tts/TextToSpeech#stop()
// @return ERROR(-1) SUCCESS(0)
AnkiDroidJS.ankiTtsStop(); The above is a brief description of all the APIs implemented this time. Since the api has a one-to-one correspondence with the android tts api, I think it would be better to quote the android api page or paste a link for the exact operation explanation. For the time being, I have pasted the link to the corresponding android api in the above brief description. |
Thanks @mikunimaru To make cloze work on AnkiDesktop and AnkiDroid <div id="text_id">{{cloze:Text}}</div>
{{Extra}}
<div id="anki_tts">{{tts en_US voices=Apple_Samantha,Microsoft_Zira speed=1.0:cloze:Text}}</div>
<!-- play button -->
<a class="replaybutton" href="#" onclick="playAnkiDroidTts();"><span><svg viewBox="0 0 32 32"><polygon points="11,25 25,16 11,7"></polygon>Replay</svg></span></a>
<script>
if (document.documentElement.classList.contains("android")) {
document.getElementById("anki_tts").innerHTML = "";
document.querySelector(".replaybutton").style.display = "unset";
playAnkiDroidTts();
} else {
document.querySelector(".replaybutton").style.display = "none";
}
function playAnkiDroidTts() {
var text = document.getElementById("text_id").textContent;
AnkiDroidJS.ankiTtsSpeak(text,1);
}
</script> |
@infinyte7 , didn't you miss the second |
I have updated it. Thanks |
Getting on Android with AnkiDroid 2.15.6 downloaded from Google Play
|
@srghma , this is working for me:
|
|
@MagTun, Yes, Thanks it's available on 2.16alpha92 By the way I couldn't find |
It's working without having to enable the debugging (you just have to enable the USB debugging in your phone settings). |
Purpose / Description
New JavaScript api
Added an api that can call TTS from JavaScript.
Fixes
Fixes #8794
Approach
The following API has been added.
ankiTtsSpeak // Speak a string
ankiTtsSetLanguage // Set the language for speaking
ankiTtsSetPitch // Set the pitch when speaking
ankiTtsSetSpeechRate //Set the speed when speak
ankiTtsStop //Stop speaking
How Has This Been Tested?
Confirmed the operation of all apis on physical devices.
Checklist
Please, go through these checks before submitting the PR.
if
statements)