+
diff --git a/servers/nextjs/app/(dashboard)/templates/components/TemplatePanel.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/templates/components/TemplatePanel.tsx
similarity index 80%
rename from servers/nextjs/app/(dashboard)/templates/components/TemplatePanel.tsx
rename to servers/nextjs/app/(presentation-generator)/(dashboard)/templates/components/TemplatePanel.tsx
index 270d0e10..7a972392 100644
--- a/servers/nextjs/app/(dashboard)/templates/components/TemplatePanel.tsx
+++ b/servers/nextjs/app/(presentation-generator)/(dashboard)/templates/components/TemplatePanel.tsx
@@ -28,23 +28,15 @@ export const CustomTemplateCard = React.memo(function CustomTemplateCard({ templ
return (
+
+
+
+ Layouts- {template.layoutCount}
+
-
-
- {template.name}
-
-
-
- {template.layoutCount}
-
-
-
-
-
-
{/* Layout previews */}
@@ -58,7 +50,7 @@ export const CustomTemplateCard = React.memo(function CustomTemplateCard({ templ
))
- ) : previewLayouts.length > 0 ? (
+ ) : previewLayouts.length > 0 && (
// Actual layout previews
previewLayouts.slice(0, 4).map((layout: CompiledLayout, index: number) => {
const LayoutComponent = layout.component;
@@ -77,21 +69,21 @@ export const CustomTemplateCard = React.memo(function CustomTemplateCard({ templ
);
})
- ) : (
- // Empty state placeholders
- [...Array(Math.min(4, template.layoutCount))].map((_, index) => (
-
- No preview
-
- ))
)}
+
+
+ {template.name}
+
+
+
+
+
+
+
);
}, (prev, next) => {
@@ -117,26 +109,14 @@ const InbuiltTemplateCard = React.memo(function InbuiltTemplateCard({
return (
+
+ Layouts- {template.layouts.length}
+
+
-
-
- {template.name}
-
-
-
- {template.layouts.length}
-
-
-
-
-
-
- {template.description}
-
-
{previewLayouts.map((layout: TemplateWithData, index: number) => {
const LayoutComponent = layout.component;
@@ -157,6 +137,21 @@ const InbuiltTemplateCard = React.memo(function InbuiltTemplateCard({
})}
+
+
+
+
+ {template.name}
+
+
+ {template.description}
+
+
+
+
+
+
+
);
});
diff --git a/servers/nextjs/app/(dashboard)/templates/loading.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/templates/loading.tsx
similarity index 100%
rename from servers/nextjs/app/(dashboard)/templates/loading.tsx
rename to servers/nextjs/app/(presentation-generator)/(dashboard)/templates/loading.tsx
diff --git a/servers/nextjs/app/(dashboard)/templates/page.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/templates/page.tsx
similarity index 100%
rename from servers/nextjs/app/(dashboard)/templates/page.tsx
rename to servers/nextjs/app/(presentation-generator)/(dashboard)/templates/page.tsx
diff --git a/servers/nextjs/app/(presentation-generator)/custom-template/components/APIKeyWarning.tsx b/servers/nextjs/app/(presentation-generator)/custom-template/components/APIKeyWarning.tsx
index 07977556..0a6447b2 100644
--- a/servers/nextjs/app/(presentation-generator)/custom-template/components/APIKeyWarning.tsx
+++ b/servers/nextjs/app/(presentation-generator)/custom-template/components/APIKeyWarning.tsx
@@ -1,5 +1,5 @@
import React from "react";
-import Header from "@/app/(dashboard)/dashboard/components/Header";
+import Header from "@/app/(presentation-generator)/(dashboard)/dashboard/components/Header";
export const APIKeyWarning: React.FC = () => {
return (
diff --git a/servers/nextjs/app/(presentation-generator)/custom-template/components/LoadingSpinner.tsx b/servers/nextjs/app/(presentation-generator)/custom-template/components/LoadingSpinner.tsx
index 6241110e..1e23494b 100644
--- a/servers/nextjs/app/(presentation-generator)/custom-template/components/LoadingSpinner.tsx
+++ b/servers/nextjs/app/(presentation-generator)/custom-template/components/LoadingSpinner.tsx
@@ -1,6 +1,6 @@
import React from "react";
import { Loader2 } from "lucide-react";
-import Header from "@/app/(dashboard)/dashboard/components/Header";
+import Header from "@/app/(presentation-generator)/(dashboard)/dashboard/components/Header";
interface LoadingSpinnerProps {
message: string;
diff --git a/servers/nextjs/app/(presentation-generator)/custom-template/page.tsx b/servers/nextjs/app/(presentation-generator)/custom-template/page.tsx
index dc8ee5e0..2cc41b71 100644
--- a/servers/nextjs/app/(presentation-generator)/custom-template/page.tsx
+++ b/servers/nextjs/app/(presentation-generator)/custom-template/page.tsx
@@ -2,7 +2,7 @@
import React, { useEffect } from "react";
import FontManager from "./components/FontManager";
-import Header from "../../(dashboard)/dashboard/components/Header";
+import Header from "../(dashboard)/dashboard/components/Header";
import { useCustomLayout } from "./hooks/useCustomLayout";
import { useFontManagement } from "./hooks/useFontManagement";
diff --git a/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx b/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx
index 8abd3492..edf2cad9 100644
--- a/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx
+++ b/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx
@@ -27,7 +27,7 @@ import MarkdownRenderer from "./MarkdownRenderer";
import { getIconFromFile } from "../../utils/others";
import { ChevronRight, PanelRightOpen, X } from "lucide-react";
import ToolTip from "@/components/ToolTip";
-import Header from "@/app/(dashboard)/dashboard/components/Header";
+import Header from "@/app/(presentation-generator)/(dashboard)/dashboard/components/Header";
import { trackEvent, MixpanelEvent } from "@/utils/mixpanel";
// Types
diff --git a/servers/nextjs/app/(presentation-generator)/outline/page.tsx b/servers/nextjs/app/(presentation-generator)/outline/page.tsx
index 54a2e4e8..fd8afd45 100644
--- a/servers/nextjs/app/(presentation-generator)/outline/page.tsx
+++ b/servers/nextjs/app/(presentation-generator)/outline/page.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import Header from '@/app/(dashboard)/dashboard/components/Header'
+import Header from '@/app/(presentation-generator)/(dashboard)/dashboard/components/Header'
import { Metadata } from 'next'
import OutlinePage from './components/OutlinePage'
export const metadata: Metadata = {
diff --git a/servers/nextjs/app/(presentation-generator)/template-preview/[slug]/page.tsx b/servers/nextjs/app/(presentation-generator)/template-preview/[slug]/page.tsx
index fb1ebb13..c661c623 100644
--- a/servers/nextjs/app/(presentation-generator)/template-preview/[slug]/page.tsx
+++ b/servers/nextjs/app/(presentation-generator)/template-preview/[slug]/page.tsx
@@ -8,7 +8,7 @@ import { ArrowLeft, Home, Loader2, Trash2 } from "lucide-react";
import { useFontLoader } from "../../hooks/useFontLoader";
import { MixpanelEvent, trackEvent } from "@/utils/mixpanel";
import TemplateService from "../../services/api/template";
-import Header from "../../../(dashboard)/dashboard/components/Header";
+import Header from "../../(dashboard)/dashboard/components/Header";
import { toast } from "sonner";
import { CustomTemplateLayout, useCustomTemplateDetails } from "@/app/hooks/useCustomTemplates";
import { templates as templateGroups, getTemplatesByTemplateName } from "@/app/presentation-templates";
diff --git a/servers/nextjs/app/(presentation-generator)/template-preview/page.tsx b/servers/nextjs/app/(presentation-generator)/template-preview/page.tsx
index fd9b585a..a7977a07 100644
--- a/servers/nextjs/app/(presentation-generator)/template-preview/page.tsx
+++ b/servers/nextjs/app/(presentation-generator)/template-preview/page.tsx
@@ -13,7 +13,7 @@ import {
CustomTemplates,
} from "@/app/hooks/useCustomTemplates";
import { CompiledLayout } from "@/app/hooks/compileLayout";
-import Header from "../../(dashboard)/dashboard/components/Header";
+import Header from "../(dashboard)/dashboard/components/Header";
// Component for rendering custom template card with lazy-loaded previews
const CustomTemplateCard = ({ template }: { template: CustomTemplates }) => {
diff --git a/servers/nextjs/app/(presentation-generator)/upload/loading.tsx b/servers/nextjs/app/(presentation-generator)/upload/loading.tsx
index 444832a0..e72f7258 100644
--- a/servers/nextjs/app/(presentation-generator)/upload/loading.tsx
+++ b/servers/nextjs/app/(presentation-generator)/upload/loading.tsx
@@ -1,4 +1,4 @@
-import Header from "@/app/(dashboard)/dashboard/components/Header";
+import Header from "@/app/(presentation-generator)/(dashboard)/dashboard/components/Header";
import { Skeleton } from "@/components/ui/skeleton";
import React from "react";
diff --git a/servers/nextjs/app/(presentation-generator)/upload/page.tsx b/servers/nextjs/app/(presentation-generator)/upload/page.tsx
index 5aaa5995..89595f95 100644
--- a/servers/nextjs/app/(presentation-generator)/upload/page.tsx
+++ b/servers/nextjs/app/(presentation-generator)/upload/page.tsx
@@ -1,7 +1,7 @@
import React from "react";
import UploadPage from "./components/UploadPage";
-import Header from "@/app/(dashboard)/dashboard/components/Header";
+import Header from "@/app/(presentation-generator)/(dashboard)/dashboard/components/Header";
import { Metadata } from "next";
export const metadata: Metadata = {
diff --git a/servers/nextjs/components/ImageSelectionConfig.tsx b/servers/nextjs/components/ImageSelectionConfig.tsx
new file mode 100644
index 00000000..0215bd31
--- /dev/null
+++ b/servers/nextjs/components/ImageSelectionConfig.tsx
@@ -0,0 +1,357 @@
+import React from 'react'
+import { Popover, PopoverContent, PopoverTrigger } from './ui/popover';
+import { Button } from './ui/button';
+import { Check, ChevronsUpDown } from 'lucide-react';
+import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './ui/command';
+import { LLMConfig } from '@/types/llm_config';
+import { IMAGE_PROVIDERS } from '@/utils/providerConstants';
+import { cn } from '@/lib/utils';
+import { Select, SelectItem, SelectContent, SelectTrigger, SelectValue } from './ui/select';
+
+const DALLE_3_QUALITY_OPTIONS = [
+ {
+ label: "Standard",
+ value: "standard",
+ description: "Faster generation with lower cost",
+ },
+ {
+ label: "HD",
+ value: "hd",
+ description: "Higher quality images with increased cost",
+ },
+];
+
+const GPT_IMAGE_1_5_QUALITY_OPTIONS = [
+ {
+ label: "Low",
+ value: "low",
+ description: "Fastest and most cost-effective",
+ },
+ {
+ label: "Medium",
+ value: "medium",
+ description: "Balanced quality and speed",
+ },
+ {
+ label: "High",
+ value: "high",
+ description: "Best quality with longer generation time",
+ },
+];
+const renderQualitySelector = (llmConfig: LLMConfig, input_field_changed: (value: string, field: string) => void) => {
+ if (llmConfig.IMAGE_PROVIDER === "dall-e-3") {
+ return (
+
+
+
+
+ {/* {DALLE_3_QUALITY_OPTIONS.map((option) => (
+
+ ))} */}
+
+
+ );
+ }
+
+ if (llmConfig.IMAGE_PROVIDER === "gpt-image-1.5") {
+ return (
+
+
+
+
+ {/* {GPT_IMAGE_1_5_QUALITY_OPTIONS.map((option) => (
+
+ ))} */}
+
+
+ );
+ }
+
+ return null;
+};
+
+const ImageSelectionConfig = ({ isImageGenerationDisabled, openImageProviderSelect, setOpenImageProviderSelect, llmConfig, input_field_changed, getApiKeyValue, handleApiKeyInputChange }: { isImageGenerationDisabled: boolean, openImageProviderSelect: boolean, setOpenImageProviderSelect: (open: boolean) => void, llmConfig: LLMConfig, input_field_changed: (value: string, field: string) => void, getApiKeyValue: (field: string) => string, handleApiKeyInputChange: (field: string, value: string) => void }) => {
+ return (
+
+
+
+
Image Generation Settings
+
+ Choosing where images come from.
+
+
+
+
+
+ {!isImageGenerationDisabled && (
+ <>
+ {/* Image Provider Selection */}
+
+
+
+
+
+
+
+
+
+
+
+ No provider found.
+
+ {Object.values(IMAGE_PROVIDERS).map(
+ (provider, index) => (
+ {
+ input_field_changed(value, "image_provider");
+ setOpenImageProviderSelect(false);
+ }}
+ >
+
+
+
+
+
+ {provider.label}
+
+
+
+ {provider.description}
+
+
+
+
+ )
+ )}
+
+
+
+
+
+
+
+
+ {renderQualitySelector(llmConfig, input_field_changed)}
+
+ {/* Dynamic API Key Input for Image Provider */}
+ {llmConfig.IMAGE_PROVIDER &&
+ IMAGE_PROVIDERS[llmConfig.IMAGE_PROVIDER] &&
+ (() => {
+ const provider = IMAGE_PROVIDERS[llmConfig.IMAGE_PROVIDER];
+
+ // Show info message when using same API key as main provider
+ if (
+ provider.value === "dall-e-3" &&
+ llmConfig.LLM === "openai"
+ ) {
+ return <>>;
+ }
+
+ if (
+ provider.value === "gpt-image-1.5" &&
+ llmConfig.LLM === "openai"
+ ) {
+ return <>>;
+ }
+
+ if (
+ provider.value === "gemini_flash" &&
+ llmConfig.LLM === "google"
+ ) {
+ return <>>;
+ }
+
+ if (
+ provider.value === "nanobanana_pro" &&
+ llmConfig.LLM === "google"
+ ) {
+ return <>>;
+ }
+
+ // Show ComfyUI configuration
+ if (provider.value === "comfyui") {
+ return (
+
+
+
+
+ {
+ input_field_changed(
+ e.target.value,
+ "comfyui_url"
+ );
+ }}
+ />
+
+
+
+ Use your machine IP address (not localhost) when
+ running in Docker
+
+
+
+
+
+
+
+ Export your workflow from ComfyUI using "Export
+ (API)" and paste the JSON here.
+
+
+
+ );
+ }
+
+ // Show API key input for other providers
+ return (
+
+
+
+
+ handleApiKeyInputChange(
+ provider.apiKeyField || "",
+ e.target.value
+ )
+ }
+ />
+
+
+
+ );
+ })()}
+ >
+ )}
+
+
+
+
+ )
+}
+
+export default ImageSelectionConfig
diff --git a/servers/nextjs/components/LLMSelection.tsx b/servers/nextjs/components/LLMSelection.tsx
index 602acec9..92c583ac 100644
--- a/servers/nextjs/components/LLMSelection.tsx
+++ b/servers/nextjs/components/LLMSelection.tsx
@@ -1,19 +1,5 @@
"use client";
import { useState, useEffect } from "react";
-import { Tabs, TabsList, TabsTrigger, TabsContent } from "./ui/tabs";
-import { Check, ChevronsUpDown, Info } from "lucide-react";
-import { Button } from "./ui/button";
-import { Switch } from "./ui/switch";
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
-} from "./ui/command";
-import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
-import { cn } from "@/lib/utils";
import OpenAIConfig from "./OpenAIConfig";
import GoogleConfig from "./GoogleConfig";
import AnthropicConfig from "./AnthropicConfig";
@@ -23,39 +9,11 @@ import {
updateLLMConfig,
changeProvider as changeProviderUtil,
} from "@/utils/providerUtils";
-import { IMAGE_PROVIDERS, LLM_PROVIDERS } from "@/utils/providerConstants";
import { LLMConfig } from "@/types/llm_config";
+import ImageSelectionConfig from "./ImageSelectionConfig";
+
-const DALLE_3_QUALITY_OPTIONS = [
- {
- label: "Standard",
- value: "standard",
- description: "Faster generation with lower cost",
- },
- {
- label: "HD",
- value: "hd",
- description: "Higher quality images with increased cost",
- },
-];
-const GPT_IMAGE_1_5_QUALITY_OPTIONS = [
- {
- label: "Low",
- value: "low",
- description: "Fastest and most cost-effective",
- },
- {
- label: "Medium",
- value: "medium",
- description: "Balanced quality and speed",
- },
- {
- label: "High",
- value: "high",
- description: "Best quality with longer generation time",
- },
-];
// Button state interface
interface ButtonState {
@@ -76,6 +34,28 @@ interface LLMProviderSelectionProps {
) => void;
}
+const LLM_TABS = [
+ {
+ label: 'OpenAI',
+ value: 'openai',
+ },
+ {
+ label: 'Google',
+ value: 'google',
+ },
+ {
+ label: 'Anthropic',
+ value: 'anthropic',
+ },
+ {
+ label: 'Ollama',
+ value: 'ollama',
+ },
+ {
+ label: 'Custom',
+ value: 'custom',
+ },
+];
export default function LLMProviderSelection({
initialLLMConfig,
onConfigChange,
@@ -84,7 +64,6 @@ export default function LLMProviderSelection({
const [llmConfig, setLlmConfig] = useState
(initialLLMConfig);
const [openImageProviderSelect, setOpenImageProviderSelect] = useState(false);
const isImageGenerationDisabled = llmConfig.DISABLE_IMAGE_GENERATION ?? false;
-
useEffect(() => {
onConfigChange(llmConfig);
}, [llmConfig]);
@@ -133,12 +112,12 @@ export default function LLMProviderSelection({
text: needsModelSelection
? "Please Select a Model"
: needsApiKey
- ? "Please Enter API Key"
- : needsOllamaUrl
- ? "Please Enter Ollama URL"
- : needsComfyUIConfig
- ? "Please Configure ComfyUI"
- : "Save Configuration",
+ ? "Please Enter API Key"
+ : needsOllamaUrl
+ ? "Please Enter Ollama URL"
+ : needsComfyUIConfig
+ ? "Please Configure ComfyUI"
+ : "Save Configuration",
showProgress: false,
});
}, [llmConfig]);
@@ -254,160 +233,96 @@ export default function LLMProviderSelection({
});
}, [llmConfig.IMAGE_PROVIDER]);
- const renderQualitySelector = () => {
- if (llmConfig.IMAGE_PROVIDER === "dall-e-3") {
- return (
-
-
-
- {DALLE_3_QUALITY_OPTIONS.map((option) => (
-
- ))}
-
-
- );
- }
- if (llmConfig.IMAGE_PROVIDER === "gpt-image-1.5") {
- return (
-
-
-
- {GPT_IMAGE_1_5_QUALITY_OPTIONS.map((option) => (
-
- ))}
-
-
- );
- }
-
- return null;
- };
return (
-
+
{/* Provider Selection - Fixed Header */}
-
-
-
- OpenAI
- Google
- Anthropic
- Ollama
- Custom
-
-
+
+
+ {LLM_TABS.map((tab) => (
+
+ ))}
+
+
+
{/* Scrollable Content */}
-
-
- {/* OpenAI Content */}
-
-
-
+
- {/* Google Content */}
-
-
-
+ {/* OpenAI Content */}
+ {llmConfig.LLM === "openai" &&
+
+
}
- {/* Anthropic Content */}
-
-
-
+ {/* Google Content */}
+ {llmConfig.LLM === "google" &&
+
+
}
- {/* Ollama Content */}
-
-
-
+ {/* Anthropic Content */}
+ {llmConfig.LLM === "anthropic" &&
}
+
+ {/* Ollama Content */}
+ {llmConfig.LLM === "ollama" &&
}
+
+ {/* Custom Content */}
+ {llmConfig.LLM === "custom" &&
+
+
}
- {/* Custom Content */}
-
-
-
-
{/* Image Generation Toggle */}
-
+
+ {/*
+
*/}
- {!isImageGenerationDisabled && (
- <>
- {/* Image Provider Selection */}
-
-
-
-
-
-
-
-
-
-
-
- No provider found.
-
- {Object.values(IMAGE_PROVIDERS).map(
- (provider, index) => (
- {
- input_field_changed(value, "image_provider");
- setOpenImageProviderSelect(false);
- }}
- >
-
-
-
-
-
- {provider.label}
-
-
-
- {provider.description}
-
-
-
-
- )
- )}
-
-
-
-
-
-
-
- {renderQualitySelector()}
-
- {/* Dynamic API Key Input for Image Provider */}
- {llmConfig.IMAGE_PROVIDER &&
- IMAGE_PROVIDERS[llmConfig.IMAGE_PROVIDER] &&
- (() => {
- const provider = IMAGE_PROVIDERS[llmConfig.IMAGE_PROVIDER];
-
- // Show info message when using same API key as main provider
- if (
- provider.value === "dall-e-3" &&
- llmConfig.LLM === "openai"
- ) {
- return <>>;
- }
-
- if (
- provider.value === "gpt-image-1.5" &&
- llmConfig.LLM === "openai"
- ) {
- return <>>;
- }
-
- if (
- provider.value === "gemini_flash" &&
- llmConfig.LLM === "google"
- ) {
- return <>>;
- }
-
- if (
- provider.value === "nanobanana_pro" &&
- llmConfig.LLM === "google"
- ) {
- return <>>;
- }
-
- // Show ComfyUI configuration
- if (provider.value === "comfyui") {
- return (
-
-
-
-
- {
- input_field_changed(
- e.target.value,
- "comfyui_url"
- );
- }}
- />
-
-
-
- Use your machine IP address (not localhost) when
- running in Docker
-
-
-
-
-
-
-
- Export your workflow from ComfyUI using "Export
- (API)" and paste the JSON here.
-
-
-
- );
- }
-
- // Show API key input for other providers
- return (
-
-
-
-
- handleApiKeyInputChange(
- provider.apiKeyField,
- e.target.value
- )
- }
- />
-
-
-
- API key for {provider.label} image generation
-
-
- );
- })()}
- >
- )}
{/* Model Information */}
-
+ {/*
@@ -645,14 +359,14 @@ export default function LLMProviderSelection({
{llmConfig.LLM === "ollama"
? llmConfig.OLLAMA_MODEL ?? "xxxxx"
: llmConfig.LLM === "custom"
- ? llmConfig.CUSTOM_MODEL ?? "xxxxx"
- : llmConfig.LLM === "anthropic"
- ? llmConfig.ANTHROPIC_MODEL ?? "xxxxx"
- : llmConfig.LLM === "google"
- ? llmConfig.GOOGLE_MODEL ?? "xxxxx"
- : llmConfig.LLM === "openai"
- ? llmConfig.OPENAI_MODEL ?? "xxxxx"
- : "xxxxx"}{" "}
+ ? llmConfig.CUSTOM_MODEL ?? "xxxxx"
+ : llmConfig.LLM === "anthropic"
+ ? llmConfig.ANTHROPIC_MODEL ?? "xxxxx"
+ : llmConfig.LLM === "google"
+ ? llmConfig.GOOGLE_MODEL ?? "xxxxx"
+ : llmConfig.LLM === "openai"
+ ? llmConfig.OPENAI_MODEL ?? "xxxxx"
+ : "xxxxx"}{" "}
for text generation{" "}
{isImageGenerationDisabled ? (
"and image generation is disabled."
@@ -660,7 +374,7 @@ export default function LLMProviderSelection({
<>
and{" "}
{llmConfig.IMAGE_PROVIDER &&
- IMAGE_PROVIDERS[llmConfig.IMAGE_PROVIDER]
+ IMAGE_PROVIDERS[llmConfig.IMAGE_PROVIDER]
? IMAGE_PROVIDERS[llmConfig.IMAGE_PROVIDER].label
: "xxxxx"}{" "}
for images
@@ -669,7 +383,28 @@ export default function LLMProviderSelection({
-
+
*/}
+ {/*
*/}
);
diff --git a/servers/nextjs/components/OpenAIConfig.tsx b/servers/nextjs/components/OpenAIConfig.tsx
index 7c465a99..b21f31df 100644
--- a/servers/nextjs/components/OpenAIConfig.tsx
+++ b/servers/nextjs/components/OpenAIConfig.tsx
@@ -14,25 +14,29 @@ import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { cn } from "@/lib/utils";
import { toast } from "sonner";
import { Switch } from "./ui/switch";
+import { LLMConfig } from "@/types/llm_config";
interface OpenAIConfigProps {
openaiApiKey: string;
openaiModel: string;
webGrounding?: boolean;
onInputChange: (value: string | boolean, field: string) => void;
+ llmConfig: LLMConfig;
}
export default function OpenAIConfig({
openaiApiKey,
openaiModel,
webGrounding,
- onInputChange
+ onInputChange,
+ llmConfig
}: OpenAIConfigProps) {
const [openModelSelect, setOpenModelSelect] = useState(false);
const [availableModels, setAvailableModels] = useState([]);
const [modelsLoading, setModelsLoading] = useState(false);
const [modelsChecked, setModelsChecked] = useState(false);
const [apiKey, setApiKey] = useState(openaiApiKey);
+ const isImageGenerationDisabled = llmConfig.DISABLE_IMAGE_GENERATION ?? false;
const openaiUrl = "https://api.openai.com/v1";
@@ -84,152 +88,189 @@ export default function OpenAIConfig({
};
return (
-
+
{/* API Key Input */}
-
-
-
- onApiKeyChange(e.target.value)}
- className="w-full px-4 py-2.5 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
- placeholder="Enter your API key"
- />
-
-
-
- Your API key will be stored locally and never shared
-
-
+
+
-
-
- {/* Check for available models button - show when no models checked or no models found */}
- {(!modelsChecked || (modelsChecked && availableModels.length === 0)) && (
-
-
-
- )}
-
- {/* Show message if no models found */}
- {modelsChecked && availableModels.length === 0 && (
-
-
- No models found. Please make sure your API key is valid and has access to OpenAI models.
+
OpenAI API key
+
+ Your API key will be stored locally and never shared
- )}
+
- {/* Model Selection - only show if models are available */}
- {modelsChecked && availableModels.length > 0 ? (
-
-
-
-
-
-
-
-
+
+
+
+ onApiKeyChange(e.target.value)}
+ className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
+ placeholder="Enter your API key"
+ />
+
+
+ {/* Check for available models button - show when no models checked or no models found */}
+
+ {(!modelsChecked || (modelsChecked && availableModels.length === 0)) && (
+
+
-
+ {modelsLoading ? (
+
+
+ Checking for models...
+
+ ) : (
+ "Check for available models"
+ )}
+
+
+ )}
+
+
+ {/* Show message if no models found */}
+ {modelsChecked && availableModels.length === 0 && (
+
+
+ No models found. Please make sure your API key is valid and has access to OpenAI models.
+
+
+ )}
+
+ {/* Model Selection - only show if models are available */}
+ {modelsChecked && availableModels.length > 0 ? (
+
+
+
+
+
+
+
+
+
+
+
+ No model found.
+
+ {availableModels.map((model, index) => (
+ {
+ onInputChange(value, "openai_model");
+ setOpenModelSelect(false);
+ }}
+ >
+
+
+
+ ))}
+
+
+
+
+
+
+
+ ) : null}
- ) : null}
+
+
+
+
+
+
{/* Web Grounding Toggle - show at the end, below models dropdown */}
-
-
-
-
onInputChange(checked, "web_grounding")}
- />
+
+
+
Model Controls
+
+
+ Configure web access, image generation, and advanced AI features.
+
-
-
- If enabled, the model can use web search grounding when available.
-
+
+
+
+
+ onInputChange(checked, "web_grounding")}
+ />
+
+
+
+ onInputChange(checked, "disable_image_generation")}
+ />
+
+
+
+
+
+
+
+
+
);
}
\ No newline at end of file