gemini_tts_wrapper 0.1.0 copy "gemini_tts_wrapper: ^0.1.0" to clipboard
gemini_tts_wrapper: ^0.1.0 copied to clipboard

One-shot Gemini TTS REST client for Flutter that returns audio bytes (Uint8List) and includes an in-memory just_audio source.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:gemini_tts_wrapper/gemini_tts_wrapper.dart';
import 'package:just_audio/just_audio.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Gemini One-shot TTS',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _player = AudioPlayer();

  final _apiKeyController = TextEditingController();
  final _textController = TextEditingController(text: 'Merhaba dunya!');
  final _modelController = TextEditingController(
    text: 'gemini-3.1-flash-tts-preview',
  );

  static const _voices = <String>['aoide', 'charon', 'puck'];

  var _voice = _voices.first;
  var _isBusy = false;
  String? _lastError;

  @override
  void dispose() {
    _player.dispose();
    _apiKeyController.dispose();
    _textController.dispose();
    _modelController.dispose();
    super.dispose();
  }

  Future<void> _generateAndPlay() async {
    final apiKey = _apiKeyController.text.trim();
    final text = _textController.text.trim();
    final model = _modelController.text.trim();

    if (apiKey.isEmpty || text.isEmpty || model.isEmpty) {
      setState(() {
        _lastError = 'API key, model, and text are required.';
      });
      return;
    }

    setState(() {
      _isBusy = true;
      _lastError = null;
    });

    try {
      final tts = GeminiTts(apiKey: apiKey, model: model);
      final bytes = await tts.generate(text: text, voice: _voice);

      await _player.setAudioSource(
        Uint8ListAudioSource(bytes, contentType: 'audio/wav'),
      );
      await _player.play();
    } catch (e) {
      setState(() {
        _lastError = e.toString();
      });
    } finally {
      if (mounted) {
        setState(() {
          _isBusy = false;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Gemini One-shot TTS'),
      ),
      body: SafeArea(
        child: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            TextField(
              controller: _apiKeyController,
              decoration: const InputDecoration(
                labelText: 'Gemini API key',
                border: OutlineInputBorder(),
              ),
              obscureText: true,
              enableSuggestions: false,
              autocorrect: false,
            ),
            const SizedBox(height: 12),
            TextField(
              controller: _modelController,
              decoration: const InputDecoration(
                labelText: 'Model',
                helperText: 'Example: gemini-3.1-flash-tts-preview',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 12),
            DropdownButtonFormField<String>(
              initialValue: _voice,
              items: [
                for (final v in _voices)
                  DropdownMenuItem(value: v, child: Text(v)),
              ],
              onChanged: _isBusy ? null : (v) => setState(() => _voice = v!),
              decoration: const InputDecoration(
                labelText: 'Voice',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 12),
            TextField(
              controller: _textController,
              decoration: const InputDecoration(
                labelText: 'Text',
                border: OutlineInputBorder(),
              ),
              maxLines: 4,
            ),
            const SizedBox(height: 12),
            FilledButton(
              onPressed: _isBusy ? null : _generateAndPlay,
              child: _isBusy
                  ? const SizedBox(
                      height: 18,
                      width: 18,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Text('Generate and play'),
            ),
            if (_lastError != null) ...[
              const SizedBox(height: 12),
              Text(
                _lastError!,
                style: TextStyle(color: Theme.of(context).colorScheme.error),
              ),
            ],
            const SizedBox(height: 12),
            Text(
              'Security: Don\'t ship long-lived API keys in production apps. '
              'Use a server-side proxy.',
              style: Theme.of(context).textTheme.bodySmall,
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
150
points
253
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

One-shot Gemini TTS REST client for Flutter that returns audio bytes (Uint8List) and includes an in-memory just_audio source.

Repository (GitHub)
View/report issues

Topics

#tts #gemini #audio #google #flutter

License

MIT (license)

Dependencies

dio, flutter, just_audio

More

Packages that depend on gemini_tts_wrapper