v1.2.8 premium diet generation endpoint

This commit is contained in:
bossanyit
2023-05-11 15:37:52 +02:00
parent 7a6dd693cb
commit e3182c210c
11 changed files with 113 additions and 30 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ plugins {
}
group = "com.aitrainer"
version = "1.2.7"
version = "1.2.8"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
+5
View File
@@ -0,0 +1,5 @@
START TRANSACTION;
UPDATE configuration set config_value = "1.2.8", date_change=CURRENT_DATE WHERE config_key = "db_version";
COMMIT;
@@ -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<ChatMessage> = 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<String>()
}
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))
}
}
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
+1 -1
View File
@@ -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
@@ -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<monday, tuesday, wednesday...>\n" +
"\"mealTime\":enum<breakfast, lunch+dinner, snack>\n" +
"\"meals\":[<mealNames in Hungarian>],\n" +
"\"quantities\":[<quantities for each mealName in gramms>],\n" +
"\"calories\":[<calorie values for each mealName>],\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)
}