diff --git a/README.md b/README.md index c583d3c..027a3c3 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,46 @@ Workout Test and Diet 4 You Common Util Functions +Version 1.0.13 +OpenAI chat completion extension + Version 1.0.12 - CustomerProperty and CustomerMembership fromJson +CustomerProperty and CustomerMembership fromJson Version 1.0.11 - No FCM on Web +No FCM on Web Version 1.0.11 - Sentry and logging only in debugMode - +Sentry and logging only in debugMode + Version 1.0.10 - Firebase FCM for web +Firebase FCM for web Version 1.0.9 - Firebase web config +Firebase web config Version 1.0.8 - mombership model error fix +mombership model error fix Version 1.0.7 - openai with model name and temperature +openai with model name and temperature Version 1.0.6 - membership, customer_membership +membership, customer_membership Version 1.0.5 - number picker widget +number picker widget Version 1.0.4 - webapi client fixes +webapi client fixes Version 1.0.3 - Warning fixes, webapi client +Warning fixes, webapi client Version 1.0.2 - Open AI API support +Open AI API support Version 1.0.1 - changes from aitrainer_app 1.1.29 working copy +changes from aitrainer_app 1.1.29 working copy Version 1.0.0 - outsourced from aitrainer_app 1.1.28 \ No newline at end of file +outsourced from aitrainer_app 1.1.28 diff --git a/lib/model/cache.dart b/lib/model/cache.dart index a970eb2..4f7e367 100644 --- a/lib/model/cache.dart +++ b/lib/model/cache.dart @@ -119,6 +119,8 @@ class Cache with Logging { static String baseUrlLive = 'https://api.workouttest.org/api/'; static String baseUrlTest = 'https://apitest.workouttest.org/api/'; + static String baseUrlDiet = 'https://api.diet4you.eu/api/'; + static String baseUrlDietTest = 'https://apitest.diet4you.eu/api/'; static String baseUrlLocal = 'http://localhost:8443/api/'; late String baseUrl; static const String mediaUrl = 'https://admin.workouttest.org/media/'; @@ -200,7 +202,7 @@ class Cache with Logging { if (testEnv == "1") { baseUrl = baseUrlTest; liveServer = false; - } else if ( testEnv == "2") { + } else if (testEnv == "2") { baseUrl = baseUrlLocal; liveServer = false; } @@ -214,9 +216,17 @@ class Cache with Logging { baseUrl = baseUrlTest; } + void setDietTestBaseUrl() { + baseUrl = baseUrlDietTest; + } + + void setDietBaseUrl() { + baseUrl = baseUrlDiet; + } + void setLocalBaseUrl() { baseUrl = baseUrlLocal; - } + } String getAuthToken() { return authToken; @@ -374,7 +384,7 @@ class Cache with Logging { baseUrl = baseUrlTest; log("TestEnv $baseUrl"); return; - } else if ( testEnvironment == "2") { + } else if (testEnvironment == "2") { baseUrl = baseUrlLocal; log("TestEnv $baseUrl"); return; @@ -563,8 +573,7 @@ class Cache with Logging { ExercisePlan? getMyExercisePlan() => _myExercisePlan; - void setMyExercisePlanDetails(LinkedHashMap listExercisePlanDetail) => - _myExercisesPlanDetails = listExercisePlanDetail; + void setMyExercisePlanDetails(LinkedHashMap listExercisePlanDetail) => _myExercisesPlanDetails = listExercisePlanDetail; void addToMyExercisePlanDetails(ExercisePlanDetail detail) => _myExercisesPlanDetails[detail.exerciseTypeId] = detail; @@ -578,8 +587,7 @@ class Cache with Logging { void deleteMyExercisePlanDetail(ExercisePlanDetail detail) => deleteMyExercisePlanDetailByExerciseTypeId(detail.exerciseTypeId); - void deletedMyExercisePlanDetail(ExercisePlanDetail detail) => - _myExercisesPlanDetails[detail.exerciseTypeId]!.change = ModelChange.deleted; + void deletedMyExercisePlanDetail(ExercisePlanDetail detail) => _myExercisesPlanDetails[detail.exerciseTypeId]!.change = ModelChange.deleted; void deleteMyExercisePlanDetailByExerciseTypeId(int exerciseTypeId) { _myExercisesPlanDetails[exerciseTypeId]!.change = ModelChange.delete; diff --git a/lib/model/openai_chat.dart b/lib/model/openai_chat.dart new file mode 100644 index 0000000..5460efe --- /dev/null +++ b/lib/model/openai_chat.dart @@ -0,0 +1,25 @@ +class OpenAIChat { + int id = 0; + late String messages; // JSON of ChatMessage + String modelName = "gpt-3.5-turbo"; + double temperature = 0.1; + + OpenAIChat(this.messages, {String? modelName, double? temperature}); + + OpenAIChat.fromJson(Map json) { + id = json["id"]; + messages = json['messages']; + modelName = json['modelName']; + temperature = json['temperature']; + } + + Map toJson() => { + "id": id, + "messages": messages, + "modelName": modelName, + "temperature": temperature, + }; + + @override + String toString() => toJson().toString(); +} diff --git a/lib/model/openai_chat_message.dart b/lib/model/openai_chat_message.dart new file mode 100644 index 0000000..3bd6e28 --- /dev/null +++ b/lib/model/openai_chat_message.dart @@ -0,0 +1,41 @@ +enum ChatRole { user, assistant, system } + +extension ChatRoleExt on ChatRole { + String enumToStr() => toString().split(".").last; + bool equalsTo(ChatRole role) => toString() == role.toString(); + bool equalsStringTo(String role) => enumToStr() == role; +} + +class OpenAIChatMessage { + late ChatRole role; // JSON of ChatMessage + late String content; + String? name; + + OpenAIChatMessage(this.role, this.content, {String? name}); + + OpenAIChatMessage.fromJson(Map json) { + role = toChatRole(json['role']); + content = json['content']; + name = json['name'] ?? ""; + } + + ChatRole toChatRole(String strRole) { + ChatRole role = ChatRole.user; + for (ChatRole chatRole in ChatRole.values) { + if (chatRole.equalsStringTo(strRole)) { + role = chatRole; + break; + } + } + return role; + } + + Map toJson() => { + "role": role.enumToStr(), + "content": content, + "name": name, + }; + + @override + String toString() => toJson().toString(); +} diff --git a/lib/service/openai_service.dart b/lib/service/openai_service.dart index 3231f8f..4cc687f 100644 --- a/lib/service/openai_service.dart +++ b/lib/service/openai_service.dart @@ -2,10 +2,10 @@ import 'dart:async'; import 'dart:convert'; import 'package:workouttest_util/model/openai.dart'; +import 'package:workouttest_util/model/openai_chat.dart'; import 'package:workouttest_util/service/api.dart'; import 'package:workouttest_util/util/logging.dart'; - class OpenAIApi with Logging { final APIClient _client = APIClient(); @@ -13,12 +13,12 @@ class OpenAIApi with Logging { String? response; try { final body = await _client.post("openai/completion", question); - response = body; + response = body; } on TimeoutException catch (_) { log("Timeout from OpenAI"); } on Exception catch (e) { log(e.toString()); - } + } return response ?? ""; } @@ -31,7 +31,20 @@ class OpenAIApi with Logging { log("Timeout from OpenAI"); } on Exception catch (e) { log(e.toString()); - } + } return response ?? ""; } -} \ No newline at end of file + + Future getOpenAIChatCompletion(OpenAIChat openai) async { + String? response; + try { + String body = const JsonEncoder().convert(openai.toJson()); + response = await _client.post("openai/chat_completion", body); + } on TimeoutException catch (_) { + log("Timeout from OpenAI"); + } on Exception catch (e) { + log(e.toString()); + } + return response ?? ""; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 629343a..d270bba 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: workouttest_util description: Workout Test app and web functions. -version: 1.0.12 +version: 1.0.13 environment: sdk: ">=2.18.6 <3.0.0" diff --git a/test/openai_test.dart b/test/openai_test.dart index e835925..5b1f1e7 100644 --- a/test/openai_test.dart +++ b/test/openai_test.dart @@ -1,8 +1,10 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:workouttest_util/model/cache.dart'; import 'package:workouttest_util/model/openai.dart'; +import 'package:workouttest_util/model/openai_chat.dart'; +import 'package:workouttest_util/model/openai_chat_message.dart'; import 'package:workouttest_util/service/openai_service.dart'; - +import 'dart:convert'; void main() { setUp(() { @@ -13,15 +15,44 @@ void main() { var api = OpenAIApi(); String response = await api.getOpenAICompletion("Who wrote the song 'yellow submarine'?"); print(response); - expect(response, matches(RegExp(r'Beatles') )); + expect(response, matches(RegExp(r'Beatles'))); }); test('openai with model response succesful', () async { var api = OpenAIApi(); - String question = "Készíts egy heti egészséges és változatos étrendet egy új felhasználónak az alábbi adatok alapján: férfi, 51 éves. Célja: Le szeretnék fogyni, heti mozgás: Hetente 3-4 alkalom, BMI: 24.784257517393772, BMR: 1723.75. A neve Tibi. Az egyes étkezések különbözőek legyenek, és add meg hozzájuk a mennyiséget és a kalóriatartalmat is. Vedd figyelembe, hogy a napi összes kalóriaérték 200-400 kCal-val kevesebb legyen, mint 1723.75 kCal"; + String question = + "Készíts egy heti egészséges és változatos étrendet egy új felhasználónak az alábbi adatok alapján: férfi, 51 éves. Célja: Le szeretnék fogyni, heti mozgás: Hetente 3-4 alkalom, BMI: 24.784257517393772, BMR: 1723.75. A neve Tibi. Az egyes étkezések különbözőek legyenek, és add meg hozzájuk a mennyiséget és a kalóriatartalmat is. Vedd figyelembe, hogy a napi összes kalóriaérték 200-400 kCal-val kevesebb legyen, mint 1723.75 kCal"; var openai = OpenAI(question, "text-davinci-003", 0.5); String response = await api.getOpenAICompletionWithModel(openai); print(response); - expect(response, matches(RegExp(r'Tibi') )); + expect(response, matches(RegExp(r'Tibi'))); + }); + + test('openai chat completion response succesful', () async { + var api = OpenAIApi(); + + String content = + "Te a Diet4You applikáció asszisztense vagy. Add meg ennek az ételnek a kalória és tápanyagadatait: 'Hortobágyi palacsinta'. A válasz ez az objektum JSON alakított formája legyen: Meal [mealName: string, cal: double, ch: double, fat: double, protein: double, sugar: double, portion: double, unit: string]. A portion paraméter azt tartalmazza, hogy ebből az ételből hány gramm v. ml az átlagos adag. A unit paraméter a 'portion' mennyiségi egyésge"; + OpenAIChatMessage message = OpenAIChatMessage(ChatRole.user, content); + String json = jsonEncode([message]); + var openai = OpenAIChat(json); + + String response = await api.getOpenAIChatCompletion(openai); + print(response); + expect(response, matches(RegExp(r'mealName'))); + }); + + test('openai chat completion response succesful 2', () async { + var api = OpenAIApi(); + + String content = + "Te a Diet4You applikáció asszisztense vagy. Add meg ennek az ételnek a kalória és tápanyagadatait: 'Szegedi halászlé'. A válasz ez az objektum JSON alakított formája legyen: Meal [mealName: string, cal: double, ch: double, fat: double, protein: double, sugar: double, portion: double, unit: string]. A portion paraméter azt tartalmazza, hogy ebből az ételből hány gramm v. ml az átlagos adag. A unit paraméter a 'portion' mennyiségi egyésge"; + OpenAIChatMessage message = OpenAIChatMessage(ChatRole.user, content); + String json = jsonEncode([message]); + var openai = OpenAIChat(json); + + String response = await api.getOpenAIChatCompletion(openai); + print(response); + expect(response, matches(RegExp(r'mealName'))); }); }