mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-04 21:15:22 +02:00
feat: OpenAI Custom Headers/Params and Debug Page (#4227)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
parent
7c274de778
commit
ea1f727a8b
20 changed files with 277 additions and 17 deletions
|
@ -84,13 +84,12 @@
|
|||
<v-list-item-title>{{ nav.title }}</v-list-item-title>
|
||||
</template>
|
||||
|
||||
<v-list-item v-for="child in nav.children" :key="child.key || child.title" exact :to="child.to">
|
||||
<v-list-item v-for="child in nav.children" :key="child.key || child.title" exact :to="child.to" class="ml-2">
|
||||
<v-list-item-icon>
|
||||
<v-icon>{{ child.icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>{{ child.title }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-divider class="mb-4"></v-divider>
|
||||
</v-list-group>
|
||||
|
||||
<!-- Single Item -->
|
||||
|
|
|
@ -1246,7 +1246,11 @@
|
|||
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
|
||||
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
|
||||
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."
|
||||
}
|
||||
},
|
||||
"debug-openai-services": "Debug OpenAI Services",
|
||||
"debug-openai-services-description": "Use this page to debug OpenAI services. You can test your OpenAI connection and see the results here. If you have image services enabled, you can also provide an image.",
|
||||
"run-test": "Run Test",
|
||||
"test-results": "Test Results"
|
||||
},
|
||||
"profile": {
|
||||
"welcome-user": "👋 Welcome, {0}!",
|
||||
|
|
|
@ -92,10 +92,23 @@ export default defineComponent({
|
|||
restricted: true,
|
||||
},
|
||||
{
|
||||
icon: $globals.icons.slotMachine,
|
||||
to: "/admin/parser",
|
||||
title: i18n.tc("sidebar.parser"),
|
||||
icon: $globals.icons.robot,
|
||||
title: i18n.tc("recipe.debug"),
|
||||
restricted: true,
|
||||
children: [
|
||||
{
|
||||
icon: $globals.icons.robot,
|
||||
to: "/admin/debug/openai",
|
||||
title: i18n.tc("admin.openai"),
|
||||
restricted: true,
|
||||
},
|
||||
{
|
||||
icon: $globals.icons.slotMachine,
|
||||
to: "/admin/debug/parser",
|
||||
title: i18n.tc("sidebar.parser"),
|
||||
restricted: true,
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
|
|
21
frontend/lib/api/admin/admin-debug.ts
Normal file
21
frontend/lib/api/admin/admin-debug.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { BaseAPI } from "../base/base-clients";
|
||||
import { DebugResponse } from "~/lib/api/types/admin";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
openai: `${prefix}/admin/debug/openai`,
|
||||
};
|
||||
|
||||
export class AdminDebugAPI extends BaseAPI {
|
||||
async debugOpenAI(fileObject: Blob | File | undefined = undefined, fileName = "") {
|
||||
let formData: FormData | null = null;
|
||||
if (fileObject) {
|
||||
formData = new FormData();
|
||||
formData.append("image", fileObject);
|
||||
formData.append("extension", fileName.split(".").pop() ?? "");
|
||||
}
|
||||
|
||||
return await this.requests.post<DebugResponse>(routes.openai, formData);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import { AdminGroupsApi } from "./admin/admin-groups";
|
|||
import { AdminBackupsApi } from "./admin/admin-backups";
|
||||
import { AdminMaintenanceApi } from "./admin/admin-maintenance";
|
||||
import { AdminAnalyticsApi } from "./admin/admin-analytics";
|
||||
import { AdminDebugAPI } from "./admin/admin-debug";
|
||||
import { ApiRequestInstance } from "~/lib/api/types/non-generated";
|
||||
|
||||
export class AdminAPI {
|
||||
|
@ -15,6 +16,7 @@ export class AdminAPI {
|
|||
public backups: AdminBackupsApi;
|
||||
public maintenance: AdminMaintenanceApi;
|
||||
public analytics: AdminAnalyticsApi;
|
||||
public debug: AdminDebugAPI;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
this.about = new AdminAboutAPI(requests);
|
||||
|
@ -24,6 +26,7 @@ export class AdminAPI {
|
|||
this.backups = new AdminBackupsApi(requests);
|
||||
this.maintenance = new AdminMaintenanceApi(requests);
|
||||
this.analytics = new AdminAnalyticsApi(requests);
|
||||
this.debug = new AdminDebugAPI(requests);
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
|
|
@ -173,6 +173,10 @@ export interface CustomPageOut {
|
|||
categories?: RecipeCategoryResponse[];
|
||||
id: number;
|
||||
}
|
||||
export interface DebugResponse {
|
||||
success: boolean;
|
||||
response?: string | null;
|
||||
}
|
||||
export interface EmailReady {
|
||||
ready: boolean;
|
||||
}
|
||||
|
|
127
frontend/pages/admin/debug/openai.vue
Normal file
127
frontend/pages/admin/debug/openai.vue
Normal file
|
@ -0,0 +1,127 @@
|
|||
<template>
|
||||
<v-container class="pa-0">
|
||||
<v-container>
|
||||
<BaseCardSectionTitle :title="$tc('admin.debug-openai-services')">
|
||||
{{ $t('admin.debug-openai-services-description') }}
|
||||
<br />
|
||||
<DocLink class="mt-2" link="/documentation/getting-started/installation/open-ai" />
|
||||
</BaseCardSectionTitle>
|
||||
</v-container>
|
||||
<v-form ref="uploadForm" @submit.prevent="testOpenAI">
|
||||
<div>
|
||||
<v-card-text>
|
||||
<v-container class="pa-0">
|
||||
<v-row>
|
||||
<v-col cols="auto" align-self="center">
|
||||
<AppButtonUpload
|
||||
v-if="!uploadedImage"
|
||||
class="ml-auto"
|
||||
url="none"
|
||||
file-name="image"
|
||||
accept="image/*"
|
||||
:text="$i18n.tc('recipe.upload-image')"
|
||||
:text-btn="false"
|
||||
:post="false"
|
||||
@uploaded="uploadImage"
|
||||
/>
|
||||
<v-btn
|
||||
v-if="!!uploadedImage"
|
||||
color="error"
|
||||
@click="clearImage"
|
||||
>
|
||||
<v-icon left>{{ $globals.icons.close }}</v-icon>
|
||||
{{ $i18n.tc("recipe.remove-image") }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-spacer />
|
||||
</v-row>
|
||||
<v-row v-if="uploadedImage && uploadedImagePreviewUrl" style="max-width: 25%;">
|
||||
<v-spacer />
|
||||
<v-col cols="12">
|
||||
<v-img :src="uploadedImagePreviewUrl" />
|
||||
</v-col>
|
||||
<v-spacer />
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<BaseButton
|
||||
type="submit"
|
||||
:text="$i18n.tc('admin.run-test')"
|
||||
:icon="$globals.icons.check"
|
||||
:loading="loading"
|
||||
class="ml-auto"
|
||||
/>
|
||||
</v-card-actions>
|
||||
</div>
|
||||
</v-form>
|
||||
<v-divider v-if="response" class="mt-4" />
|
||||
<v-container v-if="response" class="ma-0 pa-0">
|
||||
<v-card-title> {{ $t('admin.test-results') }} </v-card-title>
|
||||
<v-card-text> {{ response }} </v-card-text>
|
||||
</v-container>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from "@nuxtjs/composition-api";
|
||||
import { useAdminApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { VForm } from "~/types/vuetify";
|
||||
|
||||
export default defineComponent({
|
||||
layout: "admin",
|
||||
setup() {
|
||||
const api = useAdminApi();
|
||||
const loading = ref(false);
|
||||
const response = ref("");
|
||||
|
||||
const uploadForm = ref<VForm | null>(null);
|
||||
const uploadedImage = ref<Blob | File>();
|
||||
const uploadedImageName = ref<string>("");
|
||||
const uploadedImagePreviewUrl = ref<string>();
|
||||
|
||||
function uploadImage(fileObject: File) {
|
||||
uploadedImage.value = fileObject;
|
||||
uploadedImageName.value = fileObject.name;
|
||||
uploadedImagePreviewUrl.value = URL.createObjectURL(fileObject);
|
||||
}
|
||||
|
||||
function clearImage() {
|
||||
uploadedImage.value = undefined;
|
||||
uploadedImageName.value = "";
|
||||
uploadedImagePreviewUrl.value = undefined;
|
||||
}
|
||||
|
||||
async function testOpenAI() {
|
||||
response.value = "";
|
||||
|
||||
loading.value = true;
|
||||
const { data } = await api.debug.debugOpenAI(uploadedImage.value);
|
||||
loading.value = false;
|
||||
|
||||
if (!data) {
|
||||
alert.error("Unable to test OpenAI services");
|
||||
} else {
|
||||
response.value = data.response || (data.success ? "Test Successful" : "Test Failed");
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loading,
|
||||
response,
|
||||
uploadForm,
|
||||
uploadedImage,
|
||||
uploadedImagePreviewUrl,
|
||||
uploadImage,
|
||||
clearImage,
|
||||
testOpenAI,
|
||||
};
|
||||
},
|
||||
head() {
|
||||
return {
|
||||
title: this.$t("admin.debug-openai-services"),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue