I am trying to make an app that uses Google Vertex AI API to import images onto a dataset using a service account. I got images importing onto the dataset perfectly working, but no matter what I do i cannot label them. anyone can help me with that?
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;
import 'package:googleapis_auth/auth_io.dart';
import 'package:mime/mime.dart';
const String projectId = "Project_ID"; // Your Google Cloud Project ID
const String datasetId = "Dataset_ID"; // Your Vertex AI Dataset ID
const String storageBucket = "Bucket_Name"; // Your GCS Bucket
const String region = "us-central1"; // Your Vertex AI Region
const String serviceAccountPath = "assets/computeservice.json"; // Path to service account JSON
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ImageUploader(),
);
}
}
class ImageUploader extends StatefulWidget {
@override
_ImageUploaderState createState() => _ImageUploaderState();
}
class _ImageUploaderState extends State<ImageUploader> {
File? _image;
String _status = "Select an image to upload";
bool _isUploading = false;
Future<void> _pickImage() async {
final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_image = File(pickedFile.path);
});
}
}
Future<AuthClient> _authenticate() async {
final String jsonString = await rootBundle.loadString(serviceAccountPath);
final credentials = ServiceAccountCredentials.fromJson(jsonString);
print("🔑 Authenticated as: ${credentials.email}");
return await clientViaServiceAccount(credentials, ["https://www.googleapis.com/auth/cloud-platform"]);
}
Future<String?> _uploadToGCS(File image, AuthClient client) async {
final fileName = "uploads/${DateTime.now().millisecondsSinceEpoch}_${image.uri.pathSegments.last}";
final storageUrl = "https://storage.googleapis.com/upload/storage/v1/b/$storageBucket/o?uploadType=media&name=$fileName";
final mimeType = lookupMimeType(image.path) ?? 'application/octet-stream';
final response = await client.post(
Uri.parse(storageUrl),
headers: {
"Content-Type": mimeType,
"Authorization": "Bearer ${(client as AutoRefreshingAuthClient).credentials.accessToken.data}",
},
body: image.readAsBytesSync(),
);
if (response.statusCode == 200) {
print("✅ Image uploaded successfully: $fileName");
return fileName;
} else {
print("🚨 Error uploading image: ${response.body}");
return null;
}
}
Future<void> _importToVertexAI(String gcsFileName, String accessToken) async {
const String importSchemaUri =
"gs://google-cloud-aiplatform/schema/dataset/ioformat/image_classification_single_label_io_format_1.0.0.yaml";
final String gcsFilePath = "gs://$storageBucket/$gcsFileName";
final String datasetImportUrl =
"https://$region-aiplatform.googleapis.com/v1/projects/$projectId-p0/locations/$region/datasets/$datasetId:import";
final requestBody = jsonEncode({
"importConfigs": [
{
"gcsSource": {
"uris": [gcsFilePath]
},
"importSchemaUri": importSchemaUri,
"annotationLabels": {
"label": "your_label_name"
}
}
]
});
print("📤 DEBUG: Import Request Body:\n$requestBody");
try {
final response = await http.post(
Uri.parse(datasetImportUrl),
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $accessToken",
},
body: requestBody,
);
print("🚨 DEBUG: Full Response Body:\n${response.body}");
setState(() {
if (response.statusCode == 200) {
_status = "✅ Image successfully imported to Vertex AI!";
} else {
_status = "❌ Failed to import: ${response.body}";
}
});
} catch (e) {
setState(() {
_status = "🚨 Error during import: ${e.toString()}";
});
}
}
Future<void> _uploadAndTrain() async {
if (_image == null) {
setState(() {
_status = "⚠ Please select an image first.";
});
return;
}
setState(() {
_isUploading = true;
_status = "🔑 Authenticating...";
});
try {
final client = await _authenticate();
setState(() {
_status = "📤 Uploading image to Google Cloud Storage...";
});
final gcsFileName = await _uploadToGCS(_image!, client);
if (gcsFileName == null) throw Exception("Upload failed.");
setState(() {
_status = "📥 Importing image to Vertex AI dataset...";
});
final accessToken = (client as AutoRefreshingAuthClient).credentials.accessToken.data;
await _importToVertexAI(gcsFileName, accessToken);
} catch (e) {
setState(() {
_status = "🚨 Error: ${e.toString()}";
});
} finally {
setState(() {
_isUploading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Vertex AI Image Uploader")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_image != null ? Image.file(_image!, height: 200) : Icon(Icons.image, size: 100),
SizedBox(height: 20),
ElevatedButton(onPressed: _pickImage, child: Text("Pick Image")),
SizedBox(height: 10),
ElevatedButton(
onPressed: _isUploading ? null : _uploadAndTrain,
child: _isUploading ? CircularProgressIndicator() : Text("Upload to Dataset"),
),
SizedBox(height: 20),
Text(_status),
],
),
),
);
}
}