選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

108 行
3.8KB

  1. import 'dart:convert';
  2. import 'package:http/http.dart' as http;
  3. /// Définit un contrat pour tout service capable de générer des idées de posts.
  4. abstract class PostCreationService {
  5. Future<List<String>> generatePostIdeas({
  6. required String base64Image,
  7. required String profession,
  8. required String tone,
  9. });
  10. }
  11. /// L'implémentation Ollama de ce service.
  12. class OllamaPostCreationService implements PostCreationService {
  13. final String _apiUrl = 'http://192.168.20.200:11434/api/generate';
  14. final String _visionModel = 'llava:7b';
  15. // --- DÉBUT DE L'UNIQUE ET CORRECTE MÉTHODE ---
  16. @override
  17. @override
  18. Future<List<String>> generatePostIdeas({
  19. required String base64Image,
  20. required String profession,
  21. required String tone,
  22. }) async {
  23. final requestPrompt = '''
  24. You are a social media expert.
  25. Act as a "$profession".
  26. Analyze the image.
  27. Generate 3 short and engaging social media post ideas in french with a "$tone" tone.
  28. IMPORTANT:
  29. Your output MUST be a valid JSON array of objects, where each object has a "text" key.
  30. - DO NOT add any markdown like ```json or ```.
  31. - DO NOT add any text before or after the JSON array.
  32. - Ensure all strings inside the JSON are properly escaped (especially newlines \n).
  33. Example of a perfect response:
  34. [{"text": "idée 1"}, {"text": "idée 2"}, {"text": "idée 3"}]
  35. ''';
  36. final requestBody = {
  37. 'model': _visionModel,
  38. 'prompt': requestPrompt,
  39. 'images': [base64Image],
  40. 'stream': false,
  41. 'format': 'json',
  42. };
  43. try {
  44. print('[OllamaPostCreationService] 🚀 Appel pour générer des idées...');
  45. final response = await http.post(
  46. Uri.parse(_apiUrl),
  47. headers: {'Content-Type': 'application/json'},
  48. body: jsonEncode(requestBody),
  49. ).timeout(const Duration(minutes: 3));
  50. if (response.statusCode == 200) {
  51. final responseData = jsonDecode(response.body);
  52. final rawResponse = (responseData['response'] as String? ?? '').trim();
  53. if (rawResponse.isEmpty) return ["Le modèle n'a retourné aucune réponse."];
  54. // La ligne "cleanedResponse" inutile a été supprimée ici.
  55. try {
  56. final startIndex = rawResponse.indexOf('[');
  57. final endIndex = rawResponse.lastIndexOf(']');
  58. if (startIndex != -1 && endIndex > startIndex) {
  59. final jsonArrayString = rawResponse.substring(startIndex, endIndex + 1);
  60. // On tente le parsing
  61. final jsonList = jsonDecode(jsonArrayString) as List;
  62. // Logique de parsing pour une liste d'objets
  63. return jsonList.map((item) {
  64. if (item is Map<String, dynamic> && item.containsKey('text')) {
  65. return item['text'].toString();
  66. }
  67. return 'Format de l\'idée inattendu';
  68. })
  69. .where((text) => text != 'Format de l\'idée inattendu')
  70. .toList();
  71. } else {
  72. // Le modèle a répondu mais sans tableau JSON
  73. throw const FormatException("Aucun tableau JSON '[]' trouvé dans la réponse.");
  74. }
  75. } catch (e) {
  76. // C'EST ICI QUE VOTRE ERREUR SE PRODUIT
  77. print('[OllamaPostCreationService] ❌ Erreur de parsing JSON.');
  78. // AJOUT : Logguer l'erreur spécifique pour savoir POURQUOI le JSON est invalide
  79. print('[OllamaPostCreationService] ❌ Erreur spécifique : ${e.toString()}');
  80. print('[OllamaPostCreationService] ❌ Réponse brute : "$rawResponse"');
  81. return ["Le format de la réponse de l'IA est inattendu."];
  82. }
  83. } else {
  84. throw Exception('Erreur Ollama (generatePostIdeas) ${response.statusCode}: ${response.body}');
  85. }
  86. } catch (e) {
  87. print('[OllamaPostCreationService] ❌ Exception : ${e.toString()}');
  88. rethrow;
  89. }
  90. }
  91. }