stable_diffusion_free 0.0.2
stable_diffusion_free: ^0.0.2 copied to clipboard
A simple Flutter package for generating AI images using Stable Diffusion API. Just provide a text prompt and get an image! Free to use with 5 requests per minute limit.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:stable_diffusion_free/stable_diffusion_free.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Stable Diffusion Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const ImageGeneratorScreen(),
);
}
}
class ImageGeneratorScreen extends StatefulWidget {
const ImageGeneratorScreen({super.key});
@override
State<ImageGeneratorScreen> createState() => _ImageGeneratorScreenState();
}
class _ImageGeneratorScreenState extends State<ImageGeneratorScreen> {
final _promptController = TextEditingController();
final _client = StableDiffusionClient();
String? _imageUrl;
bool _isLoading = false;
String? _error;
StableDiffusionModel _selectedModel = StableDiffusionModel.reproduction;
@override
void dispose() {
_promptController.dispose();
_client.dispose();
super.dispose();
}
Future<void> _generateImage() async {
if (_promptController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter a prompt')),
);
return;
}
setState(() {
_isLoading = true;
_imageUrl = null;
_error = null;
});
try {
final url = await _client.generateImage(
prompt: _promptController.text,
model: _selectedModel,
);
setState(() {
_imageUrl = url;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = e.toString();
_isLoading = false;
});
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error: $e'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 10),
action: SnackBarAction(
label: 'Dismiss',
textColor: Colors.white,
onPressed: () {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
},
),
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AI Image Generator'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
controller: _promptController,
decoration: const InputDecoration(
labelText: 'Describe the image you want',
border: OutlineInputBorder(),
hintText: 'E.g., A peaceful sunset over mountains',
),
maxLines: 3,
),
const SizedBox(height: 16),
DropdownButtonFormField<StableDiffusionModel>(
value: _selectedModel,
decoration: const InputDecoration(
labelText: 'Select Model',
border: OutlineInputBorder(),
),
items: StableDiffusionModel.values.map((model) {
return DropdownMenuItem(
value: model,
child: Text(model.name),
);
}).toList(),
onChanged: (model) {
if (model != null) {
setState(() => _selectedModel = model);
}
},
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _isLoading ? null : _generateImage,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Text(
_isLoading ? 'Generating...' : 'Generate Image',
style: const TextStyle(fontSize: 16),
),
),
),
if (_error != null) ...[
const SizedBox(height: 16),
Text(
'Error Details:\n$_error',
style: const TextStyle(color: Colors.red),
),
],
const SizedBox(height: 16),
if (_isLoading)
const Center(child: CircularProgressIndicator())
else if (_imageUrl != null)
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
_imageUrl!,
fit: BoxFit.contain,
loadingBuilder: (context, child, progress) {
if (progress == null) return child;
return Center(
child: CircularProgressIndicator(
value: progress.expectedTotalBytes != null
? progress.cumulativeBytesLoaded /
progress.expectedTotalBytes!
: null,
),
);
},
errorBuilder: (context, error, stackTrace) {
return Center(
child: Text(
'Failed to load image:\n$error',
style: const TextStyle(color: Colors.red),
textAlign: TextAlign.center,
),
);
},
),
),
),
],
),
),
);
}
}