v1.2.8 premium diet generation endpoint
This commit is contained in:
parent
7a6dd693cb
commit
e3182c210c
@ -11,7 +11,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "com.aitrainer"
|
group = "com.aitrainer"
|
||||||
version = "1.2.7"
|
version = "1.2.8"
|
||||||
java.sourceCompatibility = JavaVersion.VERSION_17
|
java.sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
5
data/db/update_1_2_8.sql
Normal file
5
data/db/update_1_2_8.sql
Normal 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
|
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.model.diet.Diet
|
||||||
|
import com.aitrainer.api.openai.OpenAIService
|
||||||
import com.aitrainer.api.repository.diet.DietRepository
|
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.slf4j.LoggerFactory
|
||||||
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.web.bind.annotation.*
|
import org.springframework.web.bind.annotation.*
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -58,4 +71,56 @@ class DietController(private val dietRepository: DietRepository) {
|
|||||||
return if (list.isEmpty()) ResponseEntity.notFound().build() else
|
return if (list.isEmpty()) ResponseEntity.notFound().build() else
|
||||||
ResponseEntity.ok().body(list)
|
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(
|
val config = OpenAIConfig(
|
||||||
token = openaiKey,
|
token = openaiKey,
|
||||||
logLevel = LogLevel.All,
|
logLevel = LogLevel.All,
|
||||||
timeout = Timeout(socket = 300.seconds)
|
timeout = Timeout(socket = 600.seconds)
|
||||||
)
|
)
|
||||||
openAI = OpenAI(config)
|
openAI = OpenAI(config)
|
||||||
modelId = ModelId(modelName)
|
modelId = ModelId(modelName)
|
||||||
|
@ -16,7 +16,7 @@ logging.config=classpath:logback-spring.xml
|
|||||||
logging.file=logs
|
logging.file=logs
|
||||||
|
|
||||||
# if the database structure has been changed, increment this version number
|
# if the database structure has been changed, increment this version number
|
||||||
application.version=1.2.7
|
application.version=1.2.8
|
||||||
|
|
||||||
jwt.secret=aitrainer
|
jwt.secret=aitrainer
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ logging.config=classpath:logback-spring.xml
|
|||||||
logging.file=logs
|
logging.file=logs
|
||||||
|
|
||||||
# if the database structue has been changed, increment this version number
|
# if the database structue has been changed, increment this version number
|
||||||
application.version=1.2.7
|
application.version=1.2.8
|
||||||
|
|
||||||
jwt.secret=aitrainer
|
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
|
logging.file=logs
|
||||||
|
|
||||||
# if the database structue has been changed, increment this version number
|
# if the database structue has been changed, increment this version number
|
||||||
application.version=1.2.7
|
application.version=1.2.8
|
||||||
|
|
||||||
jwt.secret=aitrainer
|
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
|
|
@ -17,7 +17,7 @@ logging.config=classpath:logback-spring.xml
|
|||||||
logging.file=logs
|
logging.file=logs
|
||||||
|
|
||||||
# if the database structure has been changed, increment this version number
|
# if the database structure has been changed, increment this version number
|
||||||
application.version=1.2.7
|
application.version=1.2.8
|
||||||
|
|
||||||
jwt.secret=aitrainer
|
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.Diet
|
||||||
import com.aitrainer.api.model.diet.DietMeal
|
import com.aitrainer.api.model.diet.DietMeal
|
||||||
import com.aitrainer.api.repository.diet.DietRepository
|
import com.aitrainer.api.repository.diet.DietRepository
|
||||||
import com.aitrainer.api.repository.diet.MealRepository
|
|
||||||
import com.aitrainer.api.test.Tokenizer
|
import com.aitrainer.api.test.Tokenizer
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import org.junit.jupiter.api.BeforeAll
|
import org.junit.jupiter.api.BeforeAll
|
||||||
@ -158,14 +157,49 @@ class DietTest {
|
|||||||
.andExpect(jsonPath("$.premium").value(1))
|
.andExpect(jsonPath("$.premium").value(1))
|
||||||
.andReturn()
|
.andReturn()
|
||||||
|
|
||||||
val gson2= Gson()
|
|
||||||
val newDietJson2 = mvcResult2.response.contentAsString
|
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(newDiet)
|
||||||
dietRepository.delete(newDiet2)
|
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 {
|
private fun toJson(obj: Any): String {
|
||||||
return Gson().toJson(obj)
|
return Gson().toJson(obj)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user