fix: gemini key validation
Signed-off-by: Varun Raj <varun@skcript.com>
This commit is contained in:
@@ -32,7 +32,7 @@ export default function FindInput({ onSearch }: FindInputProps) {
|
||||
control: 'w-full border border-gray-200 rounded-md p-2',
|
||||
input: 'w-full border border-gray-200 rounded-md p-2 w-full',
|
||||
}}
|
||||
placeholder='Search for people or tags'
|
||||
placeholder='Search for photos, use @ to search for people'
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
onSearch(query);
|
||||
|
||||
@@ -23,6 +23,7 @@ import Head from "next/head";
|
||||
import { sidebarNavs } from "@/config/constants/sidebarNavs";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useRouter } from "next/router";
|
||||
import clsx from "clsx";
|
||||
|
||||
interface IProps {
|
||||
leftComponent?: React.ReactNode | string;
|
||||
@@ -62,7 +63,9 @@ export default function Header({ leftComponent, rightComponent, title }: IProps)
|
||||
<title>{pageTitle} - Immich Power Tools</title>
|
||||
</Head>
|
||||
)}
|
||||
<header key="header" className="sticky z-10 top-0 w-full flex h-14 items-center gap-4 border-b bg-white dark:bg-black px-4 lg:h-[60px] lg:px-6">
|
||||
<header key="header" className={
|
||||
clsx("sticky z-10 top-0 w-full flex h-14 items-center gap-4 border-b bg-white dark:bg-black px-4 lg:h-[60px] lg:px-6")
|
||||
}>
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="outline" size="icon" className="shrink-0 md:hidden">
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { Album, GalleryHorizontal, GalleryVerticalEnd, Home, Image, LocateOff, MapPinX, Search, User } from "lucide-react";
|
||||
|
||||
export const sidebarNavs = [
|
||||
{
|
||||
title: "Find",
|
||||
link: "/find",
|
||||
icon: <Search className="h-4 w-4" />,
|
||||
},
|
||||
{
|
||||
title: "Manage People",
|
||||
link: "/",
|
||||
@@ -26,9 +31,5 @@ export const sidebarNavs = [
|
||||
link: "/albums",
|
||||
icon: <GalleryHorizontal className="h-4 w-4" />,
|
||||
},
|
||||
{
|
||||
title: "Find",
|
||||
link: "/find",
|
||||
icon: <Search className="h-4 w-4" />,
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
interface ConfigContextType {
|
||||
export interface ConfigContextType {
|
||||
immichURL: string;
|
||||
exImmichUrl: string;
|
||||
version?: string;
|
||||
geminiEnabled: boolean;
|
||||
}
|
||||
|
||||
const ConfigContext = createContext<ConfigContextType>({
|
||||
immichURL: "",
|
||||
exImmichUrl: "",
|
||||
version: "",
|
||||
geminiEnabled: false,
|
||||
});
|
||||
|
||||
export default ConfigContext;
|
||||
|
||||
+4
-7
@@ -3,14 +3,10 @@ import "@/styles/globals.scss";
|
||||
import type { AppProps } from "next/app";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { ENV } from "@/config/environment";
|
||||
import ConfigContext from "@/contexts/ConfigContext";
|
||||
import ConfigContext, { ConfigContextType } from "@/contexts/ConfigContext";
|
||||
import { useRef } from "react";
|
||||
interface AppPropsWithProps extends AppProps {
|
||||
props: {
|
||||
immichURL: string;
|
||||
exImmichUrl: string;
|
||||
version?: string;
|
||||
};
|
||||
props: ConfigContextType;
|
||||
}
|
||||
const App = ({ Component, pageProps, ...props }: AppPropsWithProps) => {
|
||||
const intialData = useRef(props.props);
|
||||
@@ -32,7 +28,8 @@ App.getInitialProps = async () => {
|
||||
props: {
|
||||
exImmichUrl: ENV.EXTERNAL_IMMICH_URL,
|
||||
immichURL: ENV.IMMICH_URL,
|
||||
version: ENV.VERSION
|
||||
version: ENV.VERSION,
|
||||
geminiEnabled: !!ENV.GEMINI_API_KEY?.length,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,16 +3,22 @@ import PageLayout from '@/components/layouts/PageLayout';
|
||||
import Header from '@/components/shared/Header';
|
||||
import Loader from '@/components/ui/loader';
|
||||
import { ASSET_THUMBNAIL_PATH } from '@/config/routes';
|
||||
import { useConfig } from '@/contexts/ConfigContext';
|
||||
import { findAssets } from '@/handlers/api/asset.handler';
|
||||
import { IAsset } from '@/types/asset';
|
||||
import { Search, TriangleAlert, WandSparkles } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
import React, { useState } from 'react'
|
||||
|
||||
|
||||
export default function FindPage() {
|
||||
const { geminiEnabled } = useConfig();
|
||||
const [query, setQuery] = useState('');
|
||||
const [assets, setAssets] = useState<IAsset[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSearch = (query: string) => {
|
||||
setQuery(query);
|
||||
setLoading(true);
|
||||
findAssets(query)
|
||||
.then(({ assets }) => {
|
||||
@@ -24,16 +30,25 @@ export default function FindPage() {
|
||||
}
|
||||
|
||||
const renderContent = () => {
|
||||
if (assets.length === 0) {
|
||||
return <div className="flex justify-center items-center h-full">
|
||||
No results found
|
||||
</div>
|
||||
}
|
||||
else if (loading) {
|
||||
if (loading) {
|
||||
return <div className="flex justify-center items-center h-full">
|
||||
<Loader />
|
||||
</div>
|
||||
}
|
||||
else if (query.length === 0) {
|
||||
return <div className="flex justify-center flex-col gap-2 items-center h-full">
|
||||
<Search className='w-10 h-10 text-muted-foreground' />
|
||||
<p className='text-lg font-bold'>Search for photos in natural language</p>
|
||||
<p className='text-sm text-muted-foreground'>
|
||||
Example: Sunset photos from last week. Use <kbd className='bg-zinc-200 text-black dark:text-white px-1 py-0.5 rounded-md dark:bg-zinc-500'>@</kbd> to search for photos of a specific person.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else if (assets.length === 0) {
|
||||
return <div className="flex justify-center items-center h-full">
|
||||
No results found
|
||||
</div>
|
||||
}
|
||||
return (
|
||||
<div className="grid grid-cols-5 gap-4 p-2">
|
||||
{assets.map((asset) => (
|
||||
@@ -58,10 +73,29 @@ export default function FindPage() {
|
||||
return (
|
||||
<PageLayout>
|
||||
<Header leftComponent="Find" />
|
||||
<div className="flex flex-col gap-4 p-2">
|
||||
<FindInput onSearch={handleSearch} />
|
||||
{geminiEnabled ? (
|
||||
<div>
|
||||
<div className="flex flex-col gap-4 p-2">
|
||||
<FindInput onSearch={handleSearch} />
|
||||
</div>
|
||||
{renderContent()}
|
||||
</div>
|
||||
{renderContent()}
|
||||
) : (
|
||||
<div className="flex justify-center py-10 items-center h-full flex-col gap-2">
|
||||
<WandSparkles className='w-10 h-10 text-muted-foreground' />
|
||||
<p className='text-lg font-semibold'>Google Gemini is not enabled</p>
|
||||
<p className='text-sm text-muted-foreground max-w-md text-center'>
|
||||
Currently, the Power Tools Find is relying on Google Gemini for parsing the query.
|
||||
Please enable Gemini by adding <kbd className='bg-zinc-200 text-black dark:text-white px-1 py-0.5 rounded-md dark:bg-zinc-500'>GEMINI_API_KEY</kbd> in the <kbd className='bg-zinc-200 text-black dark:text-white px-1 py-0.5 rounded-md dark:bg-zinc-500'>.env</kbd> file.
|
||||
</p>
|
||||
<div className="border border-l-4 border-zinc-200 dark:border-zinc-500 rounded-md p-2">
|
||||
<p className='text-sm text-muted-foreground text-center flex gap-1 items-center'>
|
||||
<TriangleAlert className='w-4 h-4' />
|
||||
<span>Power tools uses Gemini only for parsing your query. None of your data is sent to Gemini.</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</PageLayout>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user