For the complete documentation index, see llms.txt. This page is also available as Markdown.

Food analysis

user.foodAnalysis turns a meal photo or a typed or spoken description into foods with portions and nutrition. The native food scanner, JanuaryFoodScanner, wraps photo analysis and barcode lookup in a full-screen Compose camera UI. These examples use user, the scoped client from User identity and timezone.

An analysis can take tens of seconds, so the SDK waits at least 120 seconds for the answer. Show progress while it runs, and don't wrap the call in a shorter withTimeout.

Analyze a photo

PhotoScanImage.dataUri corrects EXIF orientation, scales the longest edge down to 1,000 pixels, and compresses to JPEG quality 70. It works on the calling thread, so run it on Dispatchers.Default:

import ai.january.partner.photos.PhotoScanImage
import ai.january.partner.photos.ScanFoodPhotoRequest
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

val image = withContext(Dispatchers.Default) { PhotoScanImage.dataUri(photoBytes) }
val scan = user.foodAnalysis.analyzePhoto(ScanFoodPhotoRequest(image))

The photo can show a meal or a packaged product: the front of the pack, the ingredient list, or the Nutrition Facts panel. Nutrition read from a label can be incomplete, so check it before relying on it. A photo of only a barcode is rejected; use foods.lookupBarcode instead.

Analyze a description

import ai.january.partner.foods.SearchFoodsByNaturalLanguageRequest

val scan = user.foodAnalysis.analyzeDescription(
    SearchFoodsByNaturalLanguageRequest("two scrambled eggs and a slice of toast"),
)

A description can be typed or come from voice capture. Its result has no mealName.

Correct a result

Send the complete prior result back, unchanged, with a plain-language instruction:

Log the result

Each detection's food has its catalog id, the selected serving, and the quantity eaten, ready for a food log. detections is empty when nothing was recognized.

Native food scanner

The scanner has photo and barcode modes. Pass it the scoped client:

The scanner asks for the camera permission and shows its own permission, progress, and error states; an error offers Try Again and Close, and Close calls onCancel. It doesn't close itself after a result: navigate away in onResult.

Test permission denial (including "Don't ask again"), a camera that fails to start, a failed scan, and cancellation.

Last updated

Was this helpful?