diff --git a/CHANGELOG.md b/CHANGELOG.md index 0212ab5..09f526e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * User view text to be more consistent +* User meal entry form to allow input of additional metadata and context clues ### Removed diff --git a/common/components/GeminiApiComponent.php b/common/components/GeminiApiComponent.php index 6725102..ede0646 100644 --- a/common/components/GeminiApiComponent.php +++ b/common/components/GeminiApiComponent.php @@ -3,6 +3,7 @@ namespace common\components; use common\models\Meal; +use common\models\MealForm; use Exception; use Yii; use yii\helpers\FileHelper; @@ -27,28 +28,19 @@ class GeminiApiComponent extends \yii\base\Component 'format' => Client::FORMAT_JSON ], ]); - } - public function mealInquiry($filePath) + public function mealInquiry(MealForm $model) { $data = [ "contents" => [ - [ - "role" => "user", - "parts" => [ - [ - "text" => "INSERT_INPUT_HERE" - ] - ] - ], [ "role" => "user", "parts" => [ [ "inline_data" => [ - "data" => base64_encode(file_get_contents($filePath)), - "mimeType" => FileHelper::getMimeType($filePath) + "data" => base64_encode(file_get_contents($model->filepath)), + "mimeType" => FileHelper::getMimeType($model->filepath) ] ] ] @@ -58,7 +50,10 @@ class GeminiApiComponent extends \yii\base\Component "role" => "user", "parts" => [ [ - "text" => "Provide a caloric and macro estimate for pictures I provide to you. Try to be as accurate as possible and always calculate the everything you see in the picture. Proivde a 3 or 4 word `food_name`" + "text" => "Provide a caloric and macro estimate for pictures I provide to you. Try to be as + accurate as possible and always calculate the everything you see in the picture. Provide a + 3 or 7 word `food_name` with no special characters. If the user provides context pay attention + as it may contain details about the calories or specifics details about the picture." ] ] ], @@ -102,6 +97,10 @@ class GeminiApiComponent extends \yii\base\Component ] ]; + $data['contents'][0]['parts'][] = [ + 'text' => !empty($model->context) ? 'Context: ' . $model->context : 'INSERT_TEXT_HERE' + ]; + $response = $this->client ->post([$this->model, 'key' => $this->apiKey]) ->setData($data) @@ -114,6 +113,9 @@ class GeminiApiComponent extends \yii\base\Component $meal = new Meal(); $gemini = json_decode($response->getContent(), true); $geminiMeal = json_decode($gemini['candidates'][0]['content']['parts'][0]['text'], true); + $meal->context = $model->context; + $meal->date = $model->date->format('Y-m-d H:i:s'); + $meal->type = $model->type; $meal->protein = $geminiMeal['protein']; $meal->calories = $geminiMeal['calories']; $meal->carbohydrates = $geminiMeal['carbohydrates']; @@ -122,8 +124,10 @@ class GeminiApiComponent extends \yii\base\Component $meal->food_name = $geminiMeal['food_name']; // @TODO if moved a job queue then this must be an object otherwise the queue is NOT aware of the user $meal->user_id = Yii::$app->user->id; - $meal->file_name = $filePath; + $meal->file_name = $model->filepath; Yii::debug($meal); + $meal->validate(); + $errors = $meal->getErrors(); $meal->save(); // @TODO catch unidentified pictures? diff --git a/common/config/main.php b/common/config/main.php index c66d6ca..2d15aa5 100644 --- a/common/config/main.php +++ b/common/config/main.php @@ -10,7 +10,7 @@ $params = array_merge( ); return [ - 'name' => $params['company_name'] . ' - ' . $params['product_name'], + 'name' => $params['product_name'], 'aliases' => [ '@bower' => '@vendor/bower-asset', '@npm' => '@vendor/npm-asset', diff --git a/common/models/Meal.php b/common/models/Meal.php index 149a64d..fb9bf5b 100644 --- a/common/models/Meal.php +++ b/common/models/Meal.php @@ -2,6 +2,7 @@ namespace common\models; +use DateTime; use Yii; use yii\behaviors\TimestampBehavior; use yii\db\ActiveRecord; @@ -13,6 +14,7 @@ use yii\web\UnauthorizedHttpException; * @property int $id * @property string $file_name * @property string $context + * @property DateTime $date * @property string $food_name * @property string $type * @property int $calories @@ -63,7 +65,6 @@ class Meal extends ActiveRecord return [ [['date', 'food_name', 'calories', 'protein', 'fat', 'carbohydrates', 'fiber', 'type'], 'required'], [['user_id', 'calories', 'protein', 'fat', 'carbohydrates', 'fiber', 'created_at', 'updated_at'], 'integer'], - [['date'], 'date'], [['type', 'context'], 'string'], [['type'], 'in', 'range' => [self::BREAKFAST, self::LUNCH, self::DINNER, self::OTHER]], [['file_name'], 'string', 'max' => 255], diff --git a/common/models/MealForm.php b/common/models/MealForm.php index 90a2c78..ed20164 100644 --- a/common/models/MealForm.php +++ b/common/models/MealForm.php @@ -2,6 +2,8 @@ namespace common\models; +use DateInterval; +use DateTime; use Ramsey\Uuid\Uuid; use Yii; use yii\base\Model; @@ -10,31 +12,85 @@ use yii\web\UploadedFile; class MealForm extends Model { + public $context; /** * @var UploadedFile */ public $picture; public string $filepath; + public $date; + public int $day = 0; + public $type = Meal::OTHER; // type of meal - default to other - public function rules() { + public function init() + { + // @todo get user timezone to determine - should depend on their location not their settings + $hour = (int) (new DateTime())->format('H'); + if ($hour >= 6 && $hour < 11) { // Breakfast time + $this->type = Meal::BREAKFAST; + } elseif ($hour >= 11 && $hour < 15) { // Lunch time + $this->type = Meal::LUNCH; + } elseif ($hour >= 15 && $hour < 21) { // Dinner time + $this->type = Meal::DINNER; + } + } + + + public function rules() + { return [ - [['picture'], 'file', 'skipOnEmpty' => false], - [['picture'], 'required'], + [['picture'], 'image', 'skipOnEmpty' => false], + [['picture', 'day', 'type'], 'required'], + [['type'], 'string'], + [['day'], 'integer'], + [['context'], 'string', 'length' => [0, 100]], + [['day'], 'in', 'range' => [0, -1, -2, -3, -4]], + [['day'], 'validateCreationDate'], + [['type'], 'in', 'range' => [Meal::BREAKFAST, Meal::LUNCH, Meal::DINNER, Meal::OTHER]], ]; } - public function newFileName() + /** + * How many days to subtract depending on the user selection + * + * @param $attribute + * @param $params + * @param $validator + * @param $current + * @return void + * @throws \DateInvalidOperationException + * @throws \DateMalformedIntervalStringException + */ + public function validateCreationDate($attribute, $params, $validator, $current) + { + $this->date = new DateTime(); + $this->date = $this->date->sub(new DateInterval('P' . abs($current) . 'D')); + } + + + public function newFileName(): void { $this->filepath = (string)'uploads/' . Yii::$app->user->id . '-' . Uuid::uuid4() . '.' . $this->picture->extension; } - public function upload() + public function getTypeList(): array + { + return [ + Meal::BREAKFAST => 'Breakfast', + Meal::LUNCH => 'Lunch', + Meal::DINNER => 'Dinner', + Meal::OTHER => '🤷' + ]; + } + + public function upload(): bool { if ($this->validate()) { $this->newFileName(); - $this->picture->saveAs('@frontend/web/'.$this->filepath); + $this->picture->saveAs('@frontend/web/' . $this->filepath); return true; } else { + $errors = $this->getErrors(); return false; } } diff --git a/frontend/views/meal/index.php b/frontend/views/meal/index.php index 7f10a42..b104967 100644 --- a/frontend/views/meal/index.php +++ b/frontend/views/meal/index.php @@ -24,14 +24,14 @@ $this->params['breadcrumbs'][] = $this->title; = GridView::widget([ 'dataProvider' => $dataProvider, 'columns' => [ - ['class' => 'yii\grid\SerialColumn'], 'food_name', + 'type', 'calories', 'protein', 'fat', 'carbohydrates', 'fiber', - 'created_at:datetime', + 'date:date', [ 'class' => ActionColumn::class, 'urlCreator' => function ($action, Meal $model, $key, $index, $column) { diff --git a/frontend/views/meal/upload.php b/frontend/views/meal/upload.php index 146924a..f9019c9 100644 --- a/frontend/views/meal/upload.php +++ b/frontend/views/meal/upload.php @@ -1,10 +1,11 @@ registerJS( }); " ); + +$this->registerCssFile('@web/css/upload.css'); ?>