openai service
This commit is contained in:
@@ -1,12 +1,115 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:google_generative_ai/google_generative_ai.dart';
|
||||
import '../models/models.dart';
|
||||
|
||||
class GeminiService {
|
||||
GeminiService({required String apiKey});
|
||||
final String apiKey;
|
||||
late final GenerativeModel _model;
|
||||
|
||||
Future<Book?> analyzeBookCover(String base64Image) async {
|
||||
// Placeholder - Gemini API integration would go here
|
||||
// Would use google_generative_ai package to send the image
|
||||
// and extract book metadata via structured JSON output
|
||||
return null;
|
||||
GeminiService({required this.apiKey}) {
|
||||
_model = GenerativeModel(model: 'gemini-1.5-flash', apiKey: apiKey);
|
||||
}
|
||||
|
||||
Future<Book?> analyzeBookCover(String imagePath) async {
|
||||
try {
|
||||
// Read the image file
|
||||
final imageFile = File(imagePath);
|
||||
final imageBytes = await imageFile.readAsBytes();
|
||||
final base64Image = base64Encode(imageBytes);
|
||||
|
||||
// Create the prompt for book analysis
|
||||
const prompt = '''
|
||||
Analyze this book cover image and extract the following information in JSON format:
|
||||
{
|
||||
"title": "book title (required)",
|
||||
"author": "author name (required)",
|
||||
"genre": "fiction/fantasy/science/detective/biography/other",
|
||||
"annotation": "brief description or summary if visible, otherwise generate a generic one"
|
||||
}
|
||||
|
||||
Rules:
|
||||
- Extract exact text from the cover
|
||||
- If genre is unclear, choose the most appropriate one
|
||||
- If annotation is not visible, create a brief generic description
|
||||
- Return ONLY valid JSON, no additional text
|
||||
- Ensure all required fields are present
|
||||
''';
|
||||
|
||||
// Create the image part for the model
|
||||
final imagePart = Content.data('image/jpeg', imageBytes);
|
||||
|
||||
// Generate content with both text and image
|
||||
final response = await _model.generateContent([
|
||||
Content.text(prompt),
|
||||
imagePart,
|
||||
]);
|
||||
|
||||
final responseText = response.text?.trim();
|
||||
|
||||
if (responseText == null || responseText.isEmpty) {
|
||||
print('Empty response from Gemini');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract JSON from response (handle potential markdown formatting)
|
||||
String jsonString = responseText;
|
||||
if (jsonString.contains('```json')) {
|
||||
jsonString = jsonString.split('```json')[1].split('```')[0].trim();
|
||||
} else if (jsonString.contains('```')) {
|
||||
jsonString = jsonString.split('```')[1].split('```')[0].trim();
|
||||
}
|
||||
|
||||
// Parse JSON response
|
||||
final Map<String, dynamic> jsonData = json.decode(jsonString);
|
||||
|
||||
// Create Book object with extracted data
|
||||
final Book book = (
|
||||
id: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
title: jsonData['title']?.toString() ?? 'Неизвестная книга',
|
||||
author: jsonData['author']?.toString() ?? 'Неизвестный автор',
|
||||
genre: _normalizeGenre(jsonData['genre']?.toString()),
|
||||
annotation: jsonData['annotation']?.toString() ?? 'Нет описания',
|
||||
coverUrl: null, // Will be set by the caller
|
||||
pages: null,
|
||||
language: 'Russian',
|
||||
publishedYear: DateTime.now().year,
|
||||
rating: 5.0,
|
||||
status: 'want_to_read',
|
||||
progress: null,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
return book;
|
||||
} catch (e) {
|
||||
print('Error analyzing book cover: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String _normalizeGenre(String? genre) {
|
||||
if (genre == null || genre.isEmpty) return 'other';
|
||||
|
||||
final normalized = genre.toLowerCase().trim();
|
||||
|
||||
// Map various genre names to our standard genres
|
||||
final genreMap = {
|
||||
'фантастика': 'fiction',
|
||||
'fantasy': 'fantasy',
|
||||
'фэнтези': 'fantasy',
|
||||
'science': 'science',
|
||||
'научпоп': 'science',
|
||||
'научная': 'science',
|
||||
'biography': 'biography',
|
||||
'биография': 'biography',
|
||||
'detective': 'detective',
|
||||
'детектив': 'detective',
|
||||
'роман': 'other',
|
||||
'novel': 'other',
|
||||
'poetry': 'other',
|
||||
'поэзия': 'other',
|
||||
};
|
||||
|
||||
return genreMap[normalized] ?? normalized;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user