diff --git a/build.gradle.kts b/build.gradle.kts index 96e0866..48cc1e8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "com.aitrainer" -version = "1.2.7" +version = "1.2.8" java.sourceCompatibility = JavaVersion.VERSION_17 repositories { diff --git a/data/db/update_1_2_8.sql b/data/db/update_1_2_8.sql new file mode 100644 index 0000000..e4e1b51 --- /dev/null +++ b/data/db/update_1_2_8.sql @@ -0,0 +1,5 @@ +START TRANSACTION; + +UPDATE configuration set config_value = "1.2.8", date_change=CURRENT_DATE WHERE config_key = "db_version"; + +COMMIT; \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/controller/diet/DietController.kt b/src/main/kotlin/com/aitrainer/api/controller/diet/DietController.kt index e3f1d71..97f5998 100644 --- a/src/main/kotlin/com/aitrainer/api/controller/diet/DietController.kt +++ b/src/main/kotlin/com/aitrainer/api/controller/diet/DietController.kt @@ -1,11 +1,24 @@ package com.aitrainer.api.controller.diet +import com.aallam.openai.api.BetaOpenAI +import com.aallam.openai.api.chat.ChatMessage +import com.aallam.openai.api.chat.ChatRole +import com.aitrainer.api.model.OpenAIChat import com.aitrainer.api.model.diet.Diet +import com.aitrainer.api.openai.OpenAIService import com.aitrainer.api.repository.diet.DietRepository +import com.google.gson.Gson +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value import org.springframework.http.MediaType import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter import java.util.* @RestController @@ -58,4 +71,56 @@ class DietController(private val dietRepository: DietRepository) { return if (list.isEmpty()) ResponseEntity.notFound().build() else ResponseEntity.ok().body(list) } + + @OptIn(BetaOpenAI::class, DelicateCoroutinesApi::class) + @PostMapping("/diet/generate_premium/{dietUserId}", produces = [MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"]) + fun generatePremiumDiet(@PathVariable dietUserId: Long, @RequestBody input: String, @Value("\${openai.key}") openaiKey: String): ResponseEntity<*> { + val systemMsg = ChatMessage( + role = ChatRole.System, + content = "Te egy táplálkozási szakértő vagy" + ) + val userMsg = ChatMessage( + role = ChatRole.User, + content = input + ) + val listMessages: MutableList = mutableListOf() + listMessages.add(systemMsg) + listMessages.add(userMsg) + val gson = Gson() + val messages = gson.toJson(listMessages) + + val openai = OpenAIChat( + messages = messages, + modelName = "gpt-4", + temperature = 0.9 + ) + + var result: String? = null + val openAIService = OpenAIService(openaiKey, openai.modelName, openai.temperature) + val deferred = GlobalScope.async { + println(openai.messages) + openAIService.chatCompletion(openai.messages) + } + runBlocking { + try { + result = deferred.await().toString() + } catch (exception: Exception) { + println("Timeout for diet generation $dietUserId") + } + + } + if ( result == null ) { + return ResponseEntity.badRequest().build() + } + val now = LocalDateTime.now() + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + val todayString = now.format(formatter) + val diet: Diet = Diet( + dietUserId = dietUserId, + dietText = result!!, + startDate = todayString, + premium = 1 + ) + return ResponseEntity.ok().body(dietRepository.save(diet)) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/aitrainer/api/openai/OpenAIService.kt b/src/main/kotlin/com/aitrainer/api/openai/OpenAIService.kt index ba932d3..f0f814e 100644 --- a/src/main/kotlin/com/aitrainer/api/openai/OpenAIService.kt +++ b/src/main/kotlin/com/aitrainer/api/openai/OpenAIService.kt @@ -30,7 +30,7 @@ class OpenAIService(@Value("\${openai.key}") private val openaiKey: String, priv val config = OpenAIConfig( token = openaiKey, logLevel = LogLevel.All, - timeout = Timeout(socket = 300.seconds) + timeout = Timeout(socket = 600.seconds) ) openAI = OpenAI(config) modelId = ModelId(modelName) diff --git a/src/main/resources/application-diet.properties b/src/main/resources/application-diet.properties index 6ecf468..5ed4dd4 100644 --- a/src/main/resources/application-diet.properties +++ b/src/main/resources/application-diet.properties @@ -16,7 +16,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structure has been changed, increment this version number -application.version=1.2.7 +application.version=1.2.8 jwt.secret=aitrainer diff --git a/src/main/resources/application-dietprod.properties b/src/main/resources/application-dietprod.properties index 0490de5..89c9242 100644 --- a/src/main/resources/application-dietprod.properties +++ b/src/main/resources/application-dietprod.properties @@ -14,7 +14,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structue has been changed, increment this version number -application.version=1.2.7 +application.version=1.2.8 jwt.secret=aitrainer diff --git a/src/main/resources/application-dietwsl.properties b/src/main/resources/application-dietwsl.properties deleted file mode 100644 index a421c79..0000000 --- a/src/main/resources/application-dietwsl.properties +++ /dev/null @@ -1,7 +0,0 @@ -#spring.config.activate.on-profile=dev,test,prod,prodtest -spring.config.use-legacy-processing = true -## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) -spring.datasource.url = jdbc:mysql://192.168.100.98:3306/diet4you?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true -spring.datasource.username = aitrainer -spring.datasource.password = ENC(WZplPYr8WmrLHshesY4T6oXplK3MlUVJ) -spring.http.encoding.charset=UTF-8 \ No newline at end of file diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 5cc5804..8920ca5 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -14,7 +14,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structue has been changed, increment this version number -application.version=1.2.7 +application.version=1.2.8 jwt.secret=aitrainer diff --git a/src/main/resources/application-testmac.properties b/src/main/resources/application-testmac.properties deleted file mode 100644 index d289a25..0000000 --- a/src/main/resources/application-testmac.properties +++ /dev/null @@ -1,14 +0,0 @@ -spring.config.activate.on-profile=testmac -spring.config.use-legacy-processing = true -## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) -#spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false -spring.datasource.url = jdbc:mysql://127.0.0.1:3306/aitrainer2?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&allowMultiQueries=true -spring.datasource.username = root -spring.datasource.password = ENC(WZplPYr8WmrLHshesY4T6oXplK3MlUVJ) - - -## Hibernate Properties - - -# The SQL dialect makes Hibernate generate better SQL for the chosen database -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index af6bc10..df4e456 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -17,7 +17,7 @@ logging.config=classpath:logback-spring.xml logging.file=logs # if the database structure has been changed, increment this version number -application.version=1.2.7 +application.version=1.2.8 jwt.secret=aitrainer diff --git a/src/test/kotlin/com/aitrainer/api/test/diet/DietTest.kt b/src/test/kotlin/com/aitrainer/api/test/diet/DietTest.kt index d192bca..05ca766 100644 --- a/src/test/kotlin/com/aitrainer/api/test/diet/DietTest.kt +++ b/src/test/kotlin/com/aitrainer/api/test/diet/DietTest.kt @@ -3,7 +3,6 @@ package com.aitrainer.api.test.diet import com.aitrainer.api.model.diet.Diet import com.aitrainer.api.model.diet.DietMeal import com.aitrainer.api.repository.diet.DietRepository -import com.aitrainer.api.repository.diet.MealRepository import com.aitrainer.api.test.Tokenizer import com.google.gson.Gson import org.junit.jupiter.api.BeforeAll @@ -158,14 +157,49 @@ class DietTest { .andExpect(jsonPath("$.premium").value(1)) .andReturn() - val gson2= Gson() val newDietJson2 = mvcResult2.response.contentAsString - val newDiet2 = gson.fromJson(newDietJson, Diet::class.java) + val newDiet2 = gson.fromJson(newDietJson2, Diet::class.java) dietRepository.delete(newDiet) dietRepository.delete(newDiet2) } + //@Test + fun `generate premium diet successfully`() { + + val input = "Készíts egy személyre szabott heti étrendet ezekkel a paraméterekkel:\n" + + "Férfi, 50 éves, 120kg, 170 magas, célja fogyás.\n" + + "- Speciális étrend: ketogén\n" + + "- Allergiák: olajos magvak\n" + + "- Preferált ételek: magyar konyha\n" + + "- Ezek az ételek nem szerepelhetnek az étrendben: főzelékek\n" + + "- napi kalóriacél: 2100 kCal\n" + + "- Étel frekvencia: reggeli, ebéd, uzsonna, vacsora\n" + + "- Ebéd és vacsora megegyezik. \n" + + "- ne legyen ismétlődés az ételeknél\n" + + "\n" + + "A választ ebben a formátumban add meg:\n" + + "{ \"DIET\": [\n" + + "{\"nameDay\": enum\n" + + "\"mealTime\":enum\n" + + "\"meals\":[],\n" + + "\"quantities\":[],\n" + + "\"calories\":[],\n" + + "}, \"sumCal\":double\n" + + "]}" + + mockMvc.perform( + MockMvcRequestBuilders.post("/api/diet/generate_premium/2") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer $authToken") + .content(input) + ) + .andExpect(status().isOk) + .andExpect(jsonPath("$.dietUserId").value(2)) + .andExpect(jsonPath("$.premium").value(1)) + + } + private fun toJson(obj: Any): String { return Gson().toJson(obj) }