carsa_api / EMERGENCY_FLUTTER_FIX.md
athmontech's picture
Remove Hausa language support - model discontinued
130ce6d

🚨 EMERGENCY Flutter Fix - 404 & Microphone Issues

⚑ QUICK FIX 1: API URL (404 Error)

Your Hugging Face Space URL format is incorrect. Try these URLs in order:

Option A: Try this URL format:

static const String baseUrl = 'https://carsaai-carsa-api.hf.space';

Option B: If Option A fails, try:

static const String baseUrl = 'https://carsaai-carsa-api.hf.space:7860';

Option C: If both fail, use direct Space URL:

static const String baseUrl = 'https://huggingface.co/spaces/CarsaAI/carsa_api/proxy';

⚑ QUICK FIX 2: Microphone Crash

Step 1: Update pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  http: ^1.1.0
  # ADD THESE IMMEDIATELY:
  permission_handler: ^11.0.1
  flutter_sound: ^9.2.13
  path_provider: ^2.1.1

Step 2: Run this command:

flutter pub get

Step 3: Update AndroidManifest.xml

File: android/app/src/main/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- ADD THESE PERMISSIONS -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    <application
        android:label="carsa_ai"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <!-- Your existing app configuration -->
    </application>
</manifest>

Step 4: Create Simple Audio Service

Create lib/services/simple_audio_service.dart:

import 'dart:io';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:permission_handler.dart';
import 'package:path_provider/path_provider.dart';

class SimpleAudioService {
  static FlutterSoundRecorder? _recorder;
  static bool _isInitialized = false;

  static Future<void> init() async {
    if (_isInitialized) return;
    
    _recorder = FlutterSoundRecorder();
    await _recorder!.openRecorder();
    _isInitialized = true;
    print('βœ… Audio service initialized');
  }

  static Future<bool> checkPermissions() async {
    var status = await Permission.microphone.status;
    if (!status.isGranted) {
      status = await Permission.microphone.request();
    }
    print('🎀 Microphone permission: ${status.isGranted}');
    return status.isGranted;
  }

  static Future<String?> startRecording() async {
    try {
      await init();
      
      if (!await checkPermissions()) {
        throw Exception('Microphone permission denied');
      }

      final directory = await getTemporaryDirectory();
      final filePath = '${directory.path}/recording.wav';

      await _recorder!.startRecorder(
        toFile: filePath,
        codec: Codec.pcm16WAV,
      );

      print('πŸ”΄ Recording started: $filePath');
      return filePath;
    } catch (e) {
      print('❌ Recording error: $e');
      return null;
    }
  }

  static Future<String?> stopRecording() async {
    try {
      final path = await _recorder!.stopRecorder();
      print('⏹️ Recording stopped: $path');
      return path;
    } catch (e) {
      print('❌ Stop recording error: $e');
      return null;
    }
  }
}

Step 5: Update Your UI (Quick Version)

import 'package:flutter/material.dart';
import 'services/api_service.dart';
import 'services/simple_audio_service.dart';

class QuickFixScreen extends StatefulWidget {
  @override
  _QuickFixScreenState createState() => _QuickFixScreenState();
}

class _QuickFixScreenState extends State<QuickFixScreen> {
  bool isRecording = false;
  bool isLoading = false;
  String result = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Carsa AI - Emergency Fix')),
      body: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // Test Translation Button
            ElevatedButton(
              onPressed: isLoading ? null : _testTranslation,
              child: Text('Test Translation'),
            ),
            
            SizedBox(height: 20),
            
            // Recording Button
            GestureDetector(
              onTap: isLoading ? null : (isRecording ? _stopRecording : _startRecording),
              child: Container(
                width: 100,
                height: 100,
                decoration: BoxDecoration(
                  color: isRecording ? Colors.red : Colors.blue,
                  shape: BoxShape.circle,
                ),
                child: Icon(
                  isRecording ? Icons.stop : Icons.mic,
                  color: Colors.white,
                  size: 50,
                ),
              ),
            ),
            
            SizedBox(height: 20),
            
            if (isLoading)
              CircularProgressIndicator(),
            
            SizedBox(height: 20),
            
            Text(
              result,
              style: TextStyle(fontSize: 16),
              textAlign: TextAlign.center,
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _testTranslation() async {
    setState(() {
      isLoading = true;
      result = 'Testing translation...';
    });

    try {
      final response = await ApiService.translateText('Hello', 'twi');
      setState(() {
        result = 'Translation SUCCESS: ${response['translated_text']}';
      });
    } catch (e) {
      setState(() {
        result = 'Translation ERROR: $e';
      });
    } finally {
      setState(() => isLoading = false);
    }
  }

  Future<void> _startRecording() async {
    setState(() {
      isLoading = true;
      result = 'Starting recording...';
    });

    try {
      final path = await SimpleAudioService.startRecording();
      if (path != null) {
        setState(() {
          isRecording = true;
          result = 'Recording... Tap to stop';
        });
      } else {
        throw Exception('Failed to start recording');
      }
    } catch (e) {
      setState(() {
        result = 'Recording ERROR: $e';
      });
    } finally {
      setState(() => isLoading = false);
    }
  }

  Future<void> _stopRecording() async {
    setState(() {
      isLoading = true;
      result = 'Stopping recording...';
    });

    try {
      final path = await SimpleAudioService.stopRecording();
      setState(() => isRecording = false);
      
      if (path != null) {
        // Try speech to text
        final response = await ApiService.speechToText(path);
        setState(() {
          result = 'Speech-to-Text SUCCESS: ${response['transcribed_text']}';
        });
      }
    } catch (e) {
      setState(() {
        isRecording = false;
        result = 'Speech-to-Text ERROR: $e';
      });
    } finally {
      setState(() => isLoading = false);
    }
  }
}

🎯 IMMEDIATE ACTION:

  1. Try URL Option A first in your API service
  2. Add the dependencies to pubspec.yaml
  3. Run flutter pub get
  4. Add permissions to AndroidManifest.xml
  5. Test the quick fix screen

If Option A doesn't work, try Option B, then Option C.

This should fix both your 404 and microphone crashes immediately! πŸš€