test
This commit is contained in:
107
app/src/main/java/com/example/scanwich/Utils.kt
Normal file
107
app/src/main/java/com/example/scanwich/Utils.kt
Normal file
@@ -0,0 +1,107 @@
|
||||
package com.example.scanwich
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.util.Base64
|
||||
import com.google.firebase.Firebase
|
||||
import com.google.firebase.functions.functions
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
fun Float.format(digits: Int) = "%.${digits}f".format(this)
|
||||
|
||||
fun getOptimizedImageBase64(bitmap: Bitmap): String {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
val width = bitmap.width
|
||||
val height = bitmap.height
|
||||
val maxSize = 1024
|
||||
val (newWidth, newHeight) = if (width > maxSize || height > maxSize) {
|
||||
val ratio = width.toFloat() / height.toFloat()
|
||||
if (width > height) {
|
||||
maxSize to (maxSize / ratio).toInt()
|
||||
} else {
|
||||
(maxSize * ratio).toInt() to maxSize
|
||||
}
|
||||
} else {
|
||||
width to height
|
||||
}
|
||||
val resized = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true)
|
||||
resized.compress(Bitmap.CompressFormat.JPEG, 70, outputStream)
|
||||
return Base64.encodeToString(outputStream.toByteArray(), Base64.NO_WRAP)
|
||||
}
|
||||
|
||||
fun parseStravaDate(dateStr: String): Long {
|
||||
return try {
|
||||
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
|
||||
inputFormat.timeZone = TimeZone.getTimeZone("UTC")
|
||||
inputFormat.parse(dateStr)?.time ?: 0L
|
||||
} catch (_: Exception) { 0L }
|
||||
}
|
||||
|
||||
fun estimateCaloriesFromDb(activity: SportActivity, weightKg: Double): Int {
|
||||
if (activity.calories != null && activity.calories > 0) return activity.calories.toInt()
|
||||
val met = when (activity.type.lowercase()) {
|
||||
"run" -> 10.0
|
||||
"ride" -> 8.0
|
||||
"walk" -> 3.5
|
||||
"hike" -> 6.0
|
||||
"swim" -> 7.0
|
||||
"weighttraining" -> 5.0
|
||||
"workout" -> 4.5
|
||||
else -> 5.0
|
||||
}
|
||||
val durationHours = activity.movingTime / 3600.0
|
||||
return (met * weightKg * durationHours).toInt()
|
||||
}
|
||||
|
||||
fun analyzeImage(
|
||||
bitmap: Bitmap?,
|
||||
textDescription: String?,
|
||||
setAnalyzing: (Boolean) -> Unit,
|
||||
onResult: (Triple<String, String, List<Int>>?, String?) -> Unit,
|
||||
scope: CoroutineScope
|
||||
) {
|
||||
setAnalyzing(true)
|
||||
scope.launch {
|
||||
try {
|
||||
val base64 = withContext(Dispatchers.Default) {
|
||||
bitmap?.let { getOptimizedImageBase64(it) }
|
||||
}
|
||||
|
||||
val data = hashMapOf("imageBase64" to base64, "mealName" to textDescription)
|
||||
|
||||
Firebase.functions("us-central1")
|
||||
.getHttpsCallable("analyzeMealProxy")
|
||||
.call(data)
|
||||
.addOnSuccessListener { result ->
|
||||
try {
|
||||
val responseData = result.data as? Map<*, *>
|
||||
if (responseData != null) {
|
||||
onResult(Triple(
|
||||
(responseData["name"] as? String) ?: textDescription ?: "Repas",
|
||||
(responseData["description"] as? String) ?: "Analyse réussie",
|
||||
listOf(
|
||||
(responseData["calories"] as? Number)?.toInt() ?: 0,
|
||||
(responseData["carbs"] as? Number)?.toInt() ?: 0,
|
||||
(responseData["protein"] as? Number)?.toInt() ?: 0,
|
||||
(responseData["fat"] as? Number)?.toInt() ?: 0
|
||||
)
|
||||
), null)
|
||||
} else { onResult(null, "Format invalide") }
|
||||
} catch (e: Exception) { onResult(null, e.message) }
|
||||
setAnalyzing(false)
|
||||
}
|
||||
.addOnFailureListener { e ->
|
||||
onResult(null, e.message)
|
||||
setAnalyzing(false)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
onResult(null, e.localizedMessage)
|
||||
setAnalyzing(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user