שילוב Whisper API לתמלול במובייל

מקליטים אודיו ארוך באפליקציה הניידת שלכם ונתקלים בשגיאות בשליחתו ל-Whisper API? אנחנו משלבים תמלול עבור iOS ו-Android, תוך התחשבות במגבלות של OpenAI באמצעות חלוקה לקטעים וכיוונון פרמטרים. הצוות שלנו מספק פרויקטים סוהריים—מביקורת ועד תמיכה—ומבטיח ביצועים אמינים ותמלול רב-לשוני.

פיתוח ותמיכה בכל סוגי היישומים הניידים:

יישומים ניידים למידע ובידור
אפליקציות חדשות, משחקים, מדריכים, קטלוגים מקוונים, אפליקציות מזג אוויר, אפליקציות כושר ובריאות, אפליקציות נסיעות, אפליקציות חינוכיות, רשתות חברתיות ומסנג'רים, חידונים, בלוגים ופודקאסטים, פורומים, אגרגטורים
יישומים ניידים למסחר אלקטרוני
חנויות מקוונות, אפליקציות B2B, מרקטפלייסים, בורסות מקוונות, שירותי קאשבק, בורסות, פלטפורמות דרופשיפינג, תוכניות נאמנות, משלוחי מזון ומוצרים, מערכות תשלום.
יישומים ניידים לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, ניהול פרויקטים, כלים לצוותי מכירות, ניהול פיננסי, ניהול ייצור, ניהול לוגיסטיקה ומשלוחים, ניהול משאבי אנוש, מערכות ניטור נתונים
יישומים ניידים לשירותים אלקטרוניים
פלטפורמות מודעות מסווגות, בתי ספר מקוונים, בתי קולנוע מקוונים, פלטפורמות שירות אלקטרוניות, פלטפורמות קאשבק, אירוח וידאו, פורטלים נושאיים, פלטפורמות הזמנות ותזמון מקוונות, פלטפורמות מסחר מקוונות

אלה הם רק חלק מסוגי היישומים הניידים שאנו עובדים איתם, ולכל אחד מהם עשויים להיות מאפיינים ופונקציונליות ספציפיים משלו, המותאמים לצרכים ולמטרות הספציפיות של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 1734 השירותים
שילוב Whisper API לתמלול במובייל
פשוט
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית מובייל עבור FEEDME
    פיתוח אפליקציית מובייל עבור FEEDME
    971
  • פיתוח אפליקציית מובייל עבור XOOMER
    פיתוח אפליקציית מובייל עבור XOOMER
    869
  • פיתוח אפליקציית מובייל עבור RHL
    פיתוח אפליקציית מובייל עבור RHL
    1289
  • פיתוח אפליקציית מובייל עבור ZIPPY
    פיתוח אפליקציית מובייל עבור ZIPPY
    1143
  • פיתוח אפליקציית מובייל עבור Affhome
    פיתוח אפליקציית מובייל עבור Affhome
    1076
  • פיתוח אפליקציית מובייל עבור חברת FLAVORS
    פיתוח אפליקציית מובייל עבור חברת FLAVORS
    677

אתה מקליט אודיו באפליקציה ניידת, שולח אותו ל-OpenAI Whisper API — ומקבל שגיאה 413 Request Entity Too Large או SocketTimeoutException עקב מגבלת 25 MB ועיבוד איטי. הפתרון הוא חלוקה לקטעים וכיוונון פרמטרים נכון. המהנדסים שלנו, המוסמכים על ידי Apple ו-Google, עם ניסיון של 5+ שנים ולמעלה מ-50 פרויקטים, חידדו את התהליך עבור iOS (Swift) ו-Android (Kotlin): מחיתוך אודיו ועד תמלול רב-לשוני עם חותמות זמן. Whisper API — Whisper (מערכת זיהוי דיבור) — הוא מודל פתוח של OpenAI הזמין דרך REST API. הדיוק שלו ברוסית מגיע ל-94% (WER ~6%), קרוב לרמה אנושית. עם זאת, אינטגרציה דורשת טיפול במגבלות ספציפיות לפלטפורמה: עבודה עם זרמי אודיו, פורמטים ומשימות רקע היא בסיסית.

עקיפת מגבלת 25 MB

המגבלה של POST /v1/audio/transcriptions היא 25 MB. דקה אחת של MP3 ב-128 kbps היא ~1 MB, כך שקטע יכול להיות עד 25 דקות. להקלטות ארוכות יותר, נדרשת חיתוך. בפרויקט קודם עם הקלטות אודיו של הרצאות, חלוקה לקטעים הפחיתה את זמן התמלול הכולל מ-15 ל-4 דקות.

iOS: AVAssetExportSession עם timeRange. דוגמה:

let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A)
exportSession?.timeRange = CMTimeRange(start: startTime, duration: chunkDuration)

Android: let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) exportSession?.timeRange = CMTimeRange(start: startTime, duration: chunkDuration) + MediaExtractor — חיתוך ללא קידוד מחדש אם ה-codec של המקור תואם (AAC ב-MP4). עבור codec אחרים — המרה דרך MediaCodec ל-PCM → WAV.

Whisper API מחזיר 503 בעומס יתר. Exponential backoff עם 3 ניסיונות חוזרים פותר את הבעיה ב-99% מהמקרים. ב-Android השתמש ב-OkHttp עם interceptor לניסיונות חוזרים, ב-iOS — URLSession עם delegate.

פורמטי אודיו והמרה

הפורמטים האופטימליים הם MP3 ו-M4A (AAC). ודא שה-codec בתוך ה-container נתמך: אחרי MediaMuxer עם preset AVAssetExportSession זה תמיד AAC, ב-Android עדיף להמיר ל-WAV. הפרמטר AppleM4A מחזיר טקסט עם חותמות זמן — חיוני לסנכרון.

אילו פרמטרים משפרים דיוק?

פרמטר המלצה השפעה
prompt עד 224 tokens של הקשר (למשל, מונחי תחום) מפחית WER על מילים מיוחדות
temperature 0 פלט דטרמיניסטי
language ציין במפורש (למשל, "ru") מאיץ עיבוד

השוואה עם חלופות: Whisper API זול פי 3 ממודל ביתי עם איכות דומה, וחוסך עד 40% בעלויות ענן בהשוואה ל-Google Speech-to-Text.

למה חלוקה לקטעים קריטית לתמלול נייד?

ללא חלוקה, לא ניתן לעבד הקלטות ארוכות — הרצאות, ראיונות, הערות קוליות. חיתוך לקטעים של 25 MB עם חפיפה של 1–2 שניות מבטיח שאף מילה לא תאבד בגבולות. אנו משתמשים בשליחה מקבילה של קטעים עם response_format=verbose_json ב-iOS ו-DispatchGroup ב-Android, ומפחיתים את זמן התמלול הכולל ב-30%.

פלטפורמה כלי חיתוך חפיפה
iOS AVAssetExportSession עם timeRange שנייה אחת
Android MediaExtractor + MediaMuxer 2 שניות (תלוי ב-codec)

מה כלול באינטגרציה

  • תכנון ארכיטקטורת הקלטה ושליחה
  • יישום ב-iOS (Swift) ו-Android (Kotlin)
  • טיפול בשגיאות, ניסיונות חוזרים, חלוקה לקטעים
  • הגדרת שפה, prompt, פורמט verbose_json
  • תיעוד וסקירת קוד
  • בדיקות עומס

שלבי עבודה

  1. ניתוח דרישות — קביעת מקרי שימוש, תדירות תמלול, גודל אודיו.
  2. אב-טיפוס — יישום אינטגרציה בסיסית בפלטפורמה אחת תוך 2–3 ימים.
  3. אינטגרציה ובדיקות — הוספת חלוקה, ניסיונות חוזרים, טיפול בשגיאות, תמיכה רב-לשונית.
  4. פריסה וניטור — הגדרת לוגים, התראות על ירידת דיוק, עדכון prompts.

יישום ב-iOS (Swift)

struct WhisperService {
    private let apiKey: String
    private let session = URLSession.shared

    func transcribe(audioURL: URL, language: String = "ru") async throws -> String {
        var request = URLRequest(url: URL(string: "https://api.openai.com/v1/audio/transcriptions")!)
        request.httpMethod = "POST"
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")

        let boundary = UUID().uuidString
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

        var body = Data()
        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        body.append("Content-Disposition: form-data; name=\"file\"; filename=\"audio.m4a\"\r\n".data(using: .utf8)!)
        body.append("Content-Type: audio/m4a\r\n\r\n".data(using: .utf8)!)
        body.append(try Data(contentsOf: audioURL))
        body.append("\r\n".data(using: .utf8)!)

        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        body.append("Content-Disposition: form-data; name=\"model\"\r\n\r\nwhisper-1\r\n".data(using: .utf8)!)

        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        body.append("Content-Disposition: form-data; name=\"language\"\r\n\r\n\(language)\r\n".data(using: .utf8)!)

        body.append("--\(boundary)--\r\n".data(using: .utf8)!)
        request.httpBody = body

        let (data, _) = try await session.data(for: request)
        let response = try JSONDecoder().decode(TranscriptionResponse.self, from: data)
        return response.text
    }
}

יישום ב-Android (Kotlin)

suspend fun transcribe(file: File, language: String = "ru"): String {
    val client = OkHttpClient.Builder()
        .readTimeout(120, TimeUnit.SECONDS)
        .build()
    val requestBody = MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", file.name, file.asRequestBody("audio/mp4".toMediaType()))
        .addFormDataPart("model", "whisper-1")
        .addFormDataPart("language", language)
        .build()
    val request = Request.Builder()
        .url("https://api.openai.com/v1/audio/transcriptions")
        .header("Authorization", "Bearer $apiKey")
        .post(requestBody)
        .build()
    return withContext(Dispatchers.IO) {
        client.newCall(request).execute().use { response ->
            val json = response.body!!.string()
            JSONObject(json).getString("text")
        }
    }
}

טעויות אינטגרציה נפוצות

טעינת CoroutineScope כולו לזיכרון — בקובץ של 100 MB זה גורם ל-OOM במכשירי Android תקציביים. השתמש ב-struct WhisperService { private let apiKey: String private let session = URLSession.shared func transcribe(audioURL: URL, language: String = "ru") async throws -> String { var request = URLRequest(url: URL(string: "https://api.openai.com/v1/audio/transcriptions")!) request.httpMethod = "POST" request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") let boundary = UUID().uuidString request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") var body = Data() body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"file\"; filename=\"audio.m4a\"\r\n".data(using: .utf8)!) body.append("Content-Type: audio/m4a\r\n\r\n".data(using: .utf8)!) body.append(try Data(contentsOf: audioURL)) body.append("\r\n".data(using: .utf8)!) body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"model\"\r\n\r\nwhisper-1\r\n".data(using: .utf8)!) body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"language\"\r\n\r\n\(language)\r\n".data(using: .utf8)!) body.append("--\(boundary)--\r\n".data(using: .utf8)!) request.httpBody = body let (data, _) = try await session.data(for: request) let response = try JSONDecoder().decode(TranscriptionResponse.self, from: data) return response.text } } ב-OkHttp או העלאה מבוססת InputStream ב-iOS. חוסר לוגיקת ניסיונות חוזרים: Whisper API מחזיר מדי פעם 503 — exponential backoff עם 3 ניסיונות פותר זאת. אחסון מפתח API בצד הלקוח — יש להעביר את המפתח דרך backend.

לוחות זמנים ותהליך

אינטגרציה בסיסית בפלטפורמה אחת — 3–5 ימים. עם חלוקה, verbose_json וניסיונות חוזרים — 8–13 ימים. תמיכה רב-לשונית היא שלב נפרד. צור קשר להערכת הפרויקט שלך — נתכנן ארכיטקטורה אופטימלית תוך יום אחד. קבל ייעוץ על אינטגרציית Whisper API עוד היום.

עיבוד אודיו ברקע

להקלטות ארוכות, חשוב להריץ תמלול ברקע. ב-iOS השתמש ב-suspend fun transcribe(file: File, language: String = "ru"): String { val client = OkHttpClient.Builder() .readTimeout(120, TimeUnit.SECONDS) .build() val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("file", file.name, file.asRequestBody("audio/mp4".toMediaType())) .addFormDataPart("model", "whisper-1") .addFormDataPart("language", language) .build() val request = Request.Builder() .url("https://api.openai.com/v1/audio/transcriptions") .header("Authorization", "Bearer $apiKey") .post(requestBody) .build() return withContext(Dispatchers.IO) { client.newCall(request).execute().use { response -> val json = response.body!!.string() JSONObject(json).getString("text") } } } , ב-Android — Data(contentsOf:). זה מאפשר למשתמשים למזער את האפליקציה ללא אובדן נתונים. אנו מבטיחים פעולה יציבה גם באינטרנט חלש — אם בקשה נכשלת, אנו חוזרים אוטומטית עם exponential backoff ומודיעים למשתמש על התקדמות. כדי להתחיל פיילוט, צור קשר — נספק גישת API לבדיקה ונעזור להגדיר את הארכיטקטורה לתרחיש שלך.