playing with AI import

This commit is contained in:
vabene1111
2025-01-20 09:40:22 +01:00
parent a56c7c29a6
commit e0b414d8e9
10 changed files with 234 additions and 1974 deletions

View File

@@ -1,7 +1,7 @@
import {useDjangoUrls} from "@/composables/useDjangoUrls";
import {ref} from "vue";
import {getCookie} from "@/utils/cookie";
import {RecipeImageFromJSON, UserFile, UserFileFromJSON} from "@/openapi";
import {RecipeFromJSON, RecipeFromSourceFromJSON, RecipeFromSourceResponseFromJSON, RecipeImageFromJSON, UserFile, UserFileFromJSON} from "@/openapi";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
/**
@@ -76,5 +76,28 @@ export function useFileApi() {
})
}
return {fileApiLoading, createOrUpdateUserFile, updateRecipeImage}
/**
* uploads the given file to the image recognition endpoint
* @param file file object to upload
*/
function convertImageToRecipe(file: File){
let formData = new FormData()
if (file != null) {
formData.append('image', file)
}
return fetch(getDjangoUrl(`api/image-to-recipe/`), {
method: 'POST',
headers: {'X-CSRFToken': getCookie('csrftoken')},
body: formData
}).then(r => {
return r.json().then(r => {
return RecipeFromSourceResponseFromJSON(r)
})
}).finally(() => {
fileApiLoading.value = false
})
}
return {fileApiLoading, createOrUpdateUserFile, updateRecipeImage, convertImageToRecipe}
}

View File

@@ -7,8 +7,6 @@ models/AccessToken.ts
models/AuthToken.ts
models/AutoMealPlan.ts
models/Automation.ts
models/AutomationTypeEnum.ts
models/BaseUnitEnum.ts
models/BookmarkletImport.ts
models/BookmarkletImportList.ts
models/ConnectorConfigConfig.ts
@@ -22,7 +20,6 @@ models/FoodInheritField.ts
models/FoodShoppingUpdate.ts
models/FoodSimple.ts
models/Group.ts
models/ImportImage.ts
models/ImportLog.ts
models/Ingredient.ts
models/IngredientString.ts
@@ -34,16 +31,6 @@ models/MealPlan.ts
models/MealType.ts
models/MethodEnum.ts
models/NutritionInformation.ts
models/OpenDataCategory.ts
models/OpenDataConversion.ts
models/OpenDataFood.ts
models/OpenDataFoodProperty.ts
models/OpenDataProperty.ts
models/OpenDataStore.ts
models/OpenDataStoreCategory.ts
models/OpenDataUnit.ts
models/OpenDataUnitTypeEnum.ts
models/OpenDataVersion.ts
models/PaginatedAutomationList.ts
models/PaginatedBookmarkletImportListList.ts
models/PaginatedCookLogList.ts
@@ -90,13 +77,6 @@ models/PatchedInviteLink.ts
models/PatchedKeyword.ts
models/PatchedMealPlan.ts
models/PatchedMealType.ts
models/PatchedOpenDataCategory.ts
models/PatchedOpenDataConversion.ts
models/PatchedOpenDataFood.ts
models/PatchedOpenDataProperty.ts
models/PatchedOpenDataStore.ts
models/PatchedOpenDataUnit.ts
models/PatchedOpenDataVersion.ts
models/PatchedProperty.ts
models/PatchedPropertyType.ts
models/PatchedRecipe.ts
@@ -156,6 +136,7 @@ models/SupermarketCategoryRelation.ts
models/Sync.ts
models/SyncLog.ts
models/ThemeEnum.ts
models/TypeEnum.ts
models/Unit.ts
models/UnitConversion.ts
models/User.ts

File diff suppressed because it is too large Load Diff

View File

@@ -13,13 +13,13 @@
*/
import { mapValues } from '../runtime';
import type { AutomationTypeEnum } from './AutomationTypeEnum';
import type { TypeEnum } from './TypeEnum';
import {
AutomationTypeEnumFromJSON,
AutomationTypeEnumFromJSONTyped,
AutomationTypeEnumToJSON,
AutomationTypeEnumToJSONTyped,
} from './AutomationTypeEnum';
TypeEnumFromJSON,
TypeEnumFromJSONTyped,
TypeEnumToJSON,
TypeEnumToJSONTyped,
} from './TypeEnum';
/**
*
@@ -35,10 +35,10 @@ export interface Automation {
id?: number;
/**
*
* @type {AutomationTypeEnum}
* @type {TypeEnum}
* @memberof Automation
*/
type: AutomationTypeEnum;
type: TypeEnum;
/**
*
* @type {string}
@@ -111,7 +111,7 @@ export function AutomationFromJSONTyped(json: any, ignoreDiscriminator: boolean)
return {
'id': json['id'] == null ? undefined : json['id'],
'type': AutomationTypeEnumFromJSON(json['type']),
'type': TypeEnumFromJSON(json['type']),
'name': json['name'] == null ? undefined : json['name'],
'description': json['description'] == null ? undefined : json['description'],
'param1': json['param_1'] == null ? undefined : json['param_1'],
@@ -135,7 +135,7 @@ export function AutomationToJSONTyped(value?: Omit<Automation, 'created_by'> | n
return {
'id': value['id'],
'type': AutomationTypeEnumToJSON(value['type']),
'type': TypeEnumToJSON(value['type']),
'name': value['name'],
'description': value['description'],
'param_1': value['param1'],

View File

@@ -13,13 +13,13 @@
*/
import { mapValues } from '../runtime';
import type { AutomationTypeEnum } from './AutomationTypeEnum';
import type { TypeEnum } from './TypeEnum';
import {
AutomationTypeEnumFromJSON,
AutomationTypeEnumFromJSONTyped,
AutomationTypeEnumToJSON,
AutomationTypeEnumToJSONTyped,
} from './AutomationTypeEnum';
TypeEnumFromJSON,
TypeEnumFromJSONTyped,
TypeEnumToJSON,
TypeEnumToJSONTyped,
} from './TypeEnum';
/**
*
@@ -35,10 +35,10 @@ export interface PatchedAutomation {
id?: number;
/**
*
* @type {AutomationTypeEnum}
* @type {TypeEnum}
* @memberof PatchedAutomation
*/
type?: AutomationTypeEnum;
type?: TypeEnum;
/**
*
* @type {string}
@@ -109,7 +109,7 @@ export function PatchedAutomationFromJSONTyped(json: any, ignoreDiscriminator: b
return {
'id': json['id'] == null ? undefined : json['id'],
'type': json['type'] == null ? undefined : AutomationTypeEnumFromJSON(json['type']),
'type': json['type'] == null ? undefined : TypeEnumFromJSON(json['type']),
'name': json['name'] == null ? undefined : json['name'],
'description': json['description'] == null ? undefined : json['description'],
'param1': json['param_1'] == null ? undefined : json['param_1'],
@@ -133,7 +133,7 @@ export function PatchedAutomationToJSONTyped(value?: Omit<PatchedAutomation, 'cr
return {
'id': value['id'],
'type': AutomationTypeEnumToJSON(value['type']),
'type': TypeEnumToJSON(value['type']),
'name': value['name'],
'description': value['description'],
'param_1': value['param1'],

View File

@@ -4,8 +4,6 @@ export * from './AccessToken';
export * from './AuthToken';
export * from './AutoMealPlan';
export * from './Automation';
export * from './AutomationTypeEnum';
export * from './BaseUnitEnum';
export * from './BookmarkletImport';
export * from './BookmarkletImportList';
export * from './ConnectorConfigConfig';
@@ -19,7 +17,6 @@ export * from './FoodInheritField';
export * from './FoodShoppingUpdate';
export * from './FoodSimple';
export * from './Group';
export * from './ImportImage';
export * from './ImportLog';
export * from './Ingredient';
export * from './IngredientString';
@@ -31,16 +28,6 @@ export * from './MealPlan';
export * from './MealType';
export * from './MethodEnum';
export * from './NutritionInformation';
export * from './OpenDataCategory';
export * from './OpenDataConversion';
export * from './OpenDataFood';
export * from './OpenDataFoodProperty';
export * from './OpenDataProperty';
export * from './OpenDataStore';
export * from './OpenDataStoreCategory';
export * from './OpenDataUnit';
export * from './OpenDataUnitTypeEnum';
export * from './OpenDataVersion';
export * from './PaginatedAutomationList';
export * from './PaginatedBookmarkletImportListList';
export * from './PaginatedCookLogList';
@@ -87,13 +74,6 @@ export * from './PatchedInviteLink';
export * from './PatchedKeyword';
export * from './PatchedMealPlan';
export * from './PatchedMealType';
export * from './PatchedOpenDataCategory';
export * from './PatchedOpenDataConversion';
export * from './PatchedOpenDataFood';
export * from './PatchedOpenDataProperty';
export * from './PatchedOpenDataStore';
export * from './PatchedOpenDataUnit';
export * from './PatchedOpenDataVersion';
export * from './PatchedProperty';
export * from './PatchedPropertyType';
export * from './PatchedRecipe';
@@ -153,6 +133,7 @@ export * from './SupermarketCategoryRelation';
export * from './Sync';
export * from './SyncLog';
export * from './ThemeEnum';
export * from './TypeEnum';
export * from './Unit';
export * from './UnitConversion';
export * from './User';

View File

@@ -27,6 +27,12 @@
</template>
</v-text-field>
<v-file-input v-model="image" :label="$t('Image')" @click="uploadAndConvertImage()">
<template #append>
<v-btn>AI Import</v-btn>
</template>
</v-file-input>
<!-- <v-textarea :placeholder="$t('paste_json')"></v-textarea> -->
<v-alert variant="tonal" v-if="importResponse.duplicates && importResponse.duplicates.length > 0">
@@ -220,13 +226,17 @@ import {useDisplay} from "vuetify";
const {mobile} = useDisplay()
const router = useRouter()
const {updateRecipeImage, fileApiLoading} = useFileApi()
const {updateRecipeImage, convertImageToRecipe, fileApiLoading} = useFileApi()
const stepper = ref("1")
const dialog = ref(false)
const loading = ref(false)
const importUrl = ref("")
const image = ref<null|File>(null)
const importResponse = ref({} as RecipeFromSourceResponse)
const keywordSelect = ref<null | SourceImportKeyword>(null)
const editingIngredient = ref({} as SourceImportIngredient)
@@ -246,6 +256,14 @@ function loadRecipeFromUrl() {
})
}
function uploadAndConvertImage(){
if(image.value != null){
convertImageToRecipe(image.value).then(r => {
importResponse.value = r
})
}
}
/**
* create recipe in database
*/

View File

@@ -12,66 +12,43 @@
<model-edit-dialog model="MealPlan" v-model="dialog" :item="defaultItem" :activator="activator"></model-edit-dialog>
</v-btn>
<v-divider></v-divider>
<template v-if="false">
<v-divider></v-divider>
<v-row>
<v-col>
<vue-draggable v-model="items1" group="test" handle=".drag-handle">
<v-row class="mt-5">
<v-col>
<v-text-field density="compact"></v-text-field>
<v-card v-for="i in items1" class="mt-1">
<v-card-text>
<v-icon icon="$dragHandle" class="drag-handle"></v-icon>
{{ i.name }}
</v-card-text>
</v-card>
</v-col>
<v-col>
<model-select model="Food" density="compact"></model-select>
</vue-draggable>
</v-col>
<v-col>
<vue-draggable v-model="items2" group="test" handle=".drag-handle" empty-insert-threshold="25">
<v-card v-for="i in items2" class="mt-1">
<v-card-text>
<v-icon icon="$dragHandle" class="drag-handle"></v-icon>
{{ i.name }}
</v-card-text>
</v-card>
</vue-draggable>
</v-col>
</v-row>
</v-col>
</v-row>
<v-row class="mt-5">
<v-col>
<v-text-field density="comfortable"></v-text-field>
<v-row class="mt-5">
<v-col>
<v-text-field density="compact"></v-text-field>
</v-col>
<v-col>
</v-col>
<v-col>
<model-select model="Food" density="compact"></model-select>
<model-select model="Food" density="comfortable"></model-select>
</v-col>
</v-row>
<v-row class="mt-5">
<v-col>
</v-col>
</v-row>
<v-row class="mt-5">
<v-col>
<model-select model="Food"></model-select>
<v-text-field></v-text-field>
</v-col>
<v-col>
<v-text-field density="comfortable"></v-text-field>
<model-select model="Food"></model-select>
</v-col>
</v-row>
</v-col>
<v-col>
<model-select model="Food" density="comfortable"></model-select>
</v-col>
</v-row>
<v-row class="mt-5">
<v-col>
<model-select model="Food"></model-select>
<v-text-field></v-text-field>
</v-col>
<v-col>
<model-select model="Food"></model-select>
</v-col>
</v-row>
</template>
</template>
@@ -85,8 +62,11 @@ import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
import {DateTime} from "luxon";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import {VueDraggable} from "vue-draggable-plus";
import {useFileApi} from "@/composables/useFileApi";
const image = ref(File)
const {convertImageToRecipe, fileApiLoading} = useFileApi()
const image = ref<null|File>(null)
const response = ref('')
const dialog = ref(false)
@@ -96,55 +76,11 @@ const defaultItem = ref({
fromDate: DateTime.now().plus({day: 2}).toJSDate()
} as MealPlan)
const items2 = ref([])
const items1 = ref([
{
"name": "Jean",
"id": "2"
},
{
"name": "Johanna-2",
"id": "3-2"
},
{
"name": "Joao-2",
"id": "1-2"
},
{
"name": "Juan",
"id": "4"
},
{
"name": "Joao",
"id": "1"
},
{
"name": "Jean-2",
"id": "2-2"
},
{
"name": "Johanna",
"id": "3"
},
{
"name": "Juan-2",
"id": "4-2"
}
])
function imageToRecipe() {
const api = new ApiApi()
const reader = new FileReader()
reader.readAsDataURL(image.value)
api.apiImageToRecipeCreate({image: image.value}).then(r => {
console.log(r)
response.value = r
}).catch(err => {
console.log(err)
response.value = err
})
if(image.value != null){
convertImageToRecipe(image.value)
}
}