תארו לעצמכם: משתמש מקיש על כפתור המיקרופון, אומר שאילתה, אבל התמלול מופיע 10 שניות אחרי שהוא מסיים לדבר. או שהאפליקציה מבקשת הרשאת מיקרופון — ואז נשארת בשקט כי המפתח שכח לבדוק את authorizationStatus. אלה טעויות אינטגרציה אופייניות של חיפוש קולי שאנחנו מתקנים כמעט בכל פרויקט שני. במשך 5 שנים יישמנו 50+ פרויקטים עם קלט קולי — מאתרי מסחר אלקטרוני ועד אפליקציות עזר רפואיות. חיפוש קולי מאיץ את הזנת השאילתה פי 3 ומגביר את ההמרה בחיפוש ב-20%, אבל רק אם היישום נכון.
במאמר זה, נפרק בעזרת דוגמאות קונקרטיות כיצד לשלב כראוי את Speech API ב-iOS (Swift), אנדרואיד (Kotlin) ו-Flutter, אילו פתרונות עובדים בצורה אמינה, ואילו מובילים לאובדן משתמשים. אנו משתמשים בזיהוי סטרימינג עם תוצאות חלקיות — זה מספק משוב מיידי.
היכן היישומים נשברים לרוב
iOS: טיפול לא נכון ב-SFSpeechRecognizer
הטעות הנפוצה ביותר היא התחלת SFSpeechRecognitionTask ללא בדיקת הרשאות. המשתמש מקיש על הכפתור, אבל האפליקציה נשארת שקטה. הבעיה השנייה היא שימוש בבקשה מבוססת קבצים (SFSpeechURLRecognitionRequest) במקום בסטרימינג (SFSpeechAudioBufferRecognitionRequest). כתוצאה מכך, התמלול מופיע רק לאחר שההקלטה נעצרת.
הגישה הנכונה: השתמשו ב-AVAudioEngine עם SFSpeechAudioBufferRecognitionRequest והפעילו shouldReportPartialResults = true. זה מניב תוצאות חלקיות בזמן שהמשתמש מדבר — בדיוק כמו סירי המערכתית.
let request = SFSpeechAudioBufferRecognitionRequest()
request.shouldReportPartialResults = true
recognitionTask = speechRecognizer.recognitionTask(with: request) { result, error in
guard let result else { return }
self.searchBar.text = result.bestTranscription.formattedString
if result.isFinal {
self.submitSearch(query: result.bestTranscription.formattedString)
}
}
let inputNode = audioEngine.inputNode
let format = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: format) { buffer, _ in
request.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()אנדרואיד: בחירה בין SpeechRecognizer ל-RecognizerIntent
RecognizerIntent מפעיל דיאלוג מערכתי — מהיר, אבל נראה זר ולא תמיד תומך ב-EXTRA_PARTIAL_RESULTS. SpeechRecognizer נותן שליטה מלאה אבל דורש ניהול מחזור חיים קפדני: קריאה ל-destroy() ב-onDestroy() היא חובה. יישום SpeechRecognitionListener דרך ממשק RecognitionListener מספק גישה לתוצאות חלקיות.
לאינטגרציה פנימית אנו משתמשים ב-SpeechRecognizer עם Intent המכיל EXTRA_PARTIAL_RESULTS = true ומודל השפה.
val recognizer = SpeechRecognizer.createSpeechRecognizer(context)
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
putExtra(RecognizerIntent.EXTRA_LANGUAGE, "ru-RU")
}
recognizer.setRecognitionListener(object : RecognitionListener {
override fun onPartialResults(partialResults: Bundle) {
val partial = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
searchInput.setText(partial?.firstOrNull() ?: "")
}
override fun onResults(results: Bundle) {
val text = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)?.firstOrNull()
text?.let { submitSearch(it) }
}
// ... остальные коллбэки
})
recognizer.startListening(intent) Flutter: speech_to_text לעומת Platform Channels
החבילה speech_to_text מכסה 90% מהמשימות. הבעיה העיקרית היא תמיכה רב-לשונית: יש להעביר localeId במפורש, אחרת אנדרואיד משתמשת בשפת המערכת. בנוסף, החבילה אינה מספקת גישה לזרם האודיו, מה שמגביל התאמה אישית.
השוואת גישות לזיהוי דיבור
| קריטריון | API מקורי (iOS/אנדרואיד) | ASR ענני (Google, Whisper) |
|---|---|---|
| דיוק באוצר מילים פשוט | 80% | 95%+ |
| דיוק בטרמינולוגיה מורכבת | 60% | 95%+ |
| פעולה לא מקוונת | כן | לא |
| תוצאות חלקיות | כן (כמעט מיידי) | כן (עם עיכוב רשת) |
| עלות | חינם | לפי בקשה (~$0.006 / 15 שניות) |
ב-iOS, SFSpeechRecognizer משתלב באופן טבעי, עובד לא מקוון, ותומך בתוצאות חלקיות. הדיוק שלו בסביבה שקטה מגיע ל-80%, אבל יורד עם רעשי רקע. באנדרואיד, SpeechRecognizer מספק שליטה מלאה וגם עובד לא מקוון, אבל דורש ניהול מחזור חיים ידני ורגיש יותר לתאימות מכשירים. RecognizerIntent פשוט יותר, אבל הדיאלוג המערכתי שלו נראה זר ולא תומך בתוצאות חלקיות בכל המכשירים. לפרויקטים חוצי-פלטפורמות, החבילה speech_to_text נוחה, אבל הגמישות שלה מוגבלת.
אם נדרש דיוק גבוה בטרמינולוגיה ספציפית (רפואה, משפטים), ה-API המקורי לא עומד במשימה — הדיוק יורד ל-60%. במקרים כאלה, ASR ענני כמו Google Cloud Speech-to-Text, עם מודלים מאומנים בהתאמה אישית, מעלה את הדיוק ל-95%+. ASR ענני מדויק פי 1.5 מה-API המקורי באוצר מילים מורכב.
איך אנחנו עושים את זה בפועל
פעם בנינו חיפוש קולי לאפליקציית עזר רפואית. היא הייתה צריכה לזהות מונחים מורכבים: "לפרוסקופיה", "גסטרוסקופיה". ה-API הקולי המקורי סיפק דיוק של כ-60%. חיברנו את Google Cloud Speech-to-Text עם SpeechContext מותאם ואימנו את המודל על אוצר מילים של 5,000 מונחים. הדיוק קפץ ל-95%. זמן החיפוש קוצר פי שלושה — המשתמשים העריכו זאת. חיסכון בזמן עיבוד השאילתה הגיע ל-40% בהשוואה לאינטגרציה בסיסית, ועלויות תשתית ה-ASR החזירו את עצמן תוך 3 חודשים.
לרוב היישומים, ה-API המקורי מספיק. אם נדרש דיוק גבוה באוצר מילים ספציפי או פעולה בסביבות רועשות, אנו מחברים ASR ענני. אנימציית עוצמת הקול במהלך ההקלטה אינה דקורטיבית: ב-iOS אנו משתמשים ב-AVAudioRecorder.averagePower, באנדרואיד — MediaRecorder.getMaxAmplitude. זה נותן למשתמש תחושה שהמיקרופון עובד.
למה טיפול נכון בתוצאות חלקיות חשוב
תוצאות חלקיות הן המפתח לחוויית משתמש טובה. בלעדיהן, המשתמש מדבר אל הריק, לא יודע אם האפליקציה שומעת אותו. ב-iOS, הדגל shouldReportPartialResults = true פותר את הבעיה. באנדרואיד — EXTRA_PARTIAL_RESULTS. אנחנו תמיד מפעילים את אלה בפרויקטים — זה מגביר את ההמרה בחיפוש ב-20% ומפחית את שיעור השאילתות הלא שלמות פי 1.5.
מתי לחבר ASR ענני במקום API מקורי
ASR ענני (Google, Whisper) נחוץ כשהדיוק של ה-API המקורי יורד מתחת ל-70%: זה קורה עם טרמינולוגיה מורכבת, סביבות רועשות, או תמיכה רב-לשונית. אנו משתמשים בו ביישומים רפואיים, משפטיים וטכניים. העלות לכל בקשה מינימלית, והתוצאה היא דיוק של 95%+. זמן האינטגרציה גדל ב-3–5 ימים, אבל משתלם דרך האיכות.
דוגמה לאינטגרציה מורכבת: זיהוי לא מקוון על המכשיר
ליישומים ללא אינטרנט אנו משתמשים במודלים מקומיים (למשל, Vosk או PicoVoice). האינטגרציה אורכת 2–3 שבועות, הדיוק מגיע עד 85% באוצר מילים פשוט. דורש אופטימיזציה של גודל המודל וניהול זיכרון.מה כלול בעבודה
- תיעוד לאינטגרציית Speech API (עם דוגמאות קוד)
- קוד מקור של מודול הקלט הקולי לפלטפורמות היעד
- הגדרת תוצאות חלקיות ונורמליזציה של שאילתות
- אנימציית מיקרופון עם חיווי עוצמת קול
- אינטגרציה עם הקצה האחורי של החיפוש
- בדיקות על 10+ מכשירים אמיתיים עם מבטאים שונים
- חודש אחריות ותמיכה לאחר ההשקה
תהליך העבודה
- ניתוח — קביעת שפות, סוג תוכן (פקודות או דיבור חופשי), והאם נדרשת פעולה לא מקוונת.
- פיתוח — בקשת הרשאות, אינטגרציית Speech API, טיפול בתוצאות חלקיות, אנימציית מיקרופון.
- נורמליזציה — המרת טקסט לשאילתת חיפוש, הסרת רעשים.
- בדיקות — בדיקה ב-iOS (דגמים שונים) ואנדרואיד (גרסאות 6+), תיקון באגים.
- השקה — פרסום ב-App Store וב-Google Play, ניטור משוב.
הערכות זמנים
| שלב | משך |
|---|---|
| אינטגרציית API מקורי בסיסית | 2–3 ימים |
| רב-לשוני + ASR ענני | 1–1.5 שבועות |
| מצב לא מקוון באמצעות מודל מקומי | 2–3 שבועות |
רשימת בדיקה לאינטגרציה מוצלחת
- [ ] בדיקת הרשאות מיקרופון וזיהוי דיבור
- [ ] בחירת API מתאים (מקורי/ענני)
- [ ] הפעלת תוצאות חלקיות בכל הפלטפורמות
- [ ] יישום נורמליזציה של שאילתות
- [ ] בדיקות על 10+ מכשירים עם מבטאים שונים
- [ ] הגדרת אנימציית עוצמת קול
קבלו ייעוץ לפרויקט שלכם — נעריך את המשימה ביום אחד. הזמינו יישום חיפוש קולי במפתח — המהנדסים שלנו עם ניסיון של מעל 5 שנים מבטיחים תוצאות. צרו קשר להערכת פרויקט.







