From 01463442ba3f3554a02b0066089493729bbb5dff Mon Sep 17 00:00:00 2001 From: pablodanswer Date: Sun, 27 Oct 2024 13:08:18 -0700 Subject: [PATCH 1/2] avoid image generation tool confusion --- .../danswer/server/features/persona/api.py | 11 +++ .../danswer/server/features/persona/models.py | 4 + .../app/admin/assistants/AssistantEditor.tsx | 75 +++++-------------- .../components/context/AssistantsContext.tsx | 69 +++++++++-------- 4 files changed, 70 insertions(+), 89 deletions(-) diff --git a/backend/danswer/server/features/persona/api.py b/backend/danswer/server/features/persona/api.py index 8c0e19438..1e0e84a58 100644 --- a/backend/danswer/server/features/persona/api.py +++ b/backend/danswer/server/features/persona/api.py @@ -30,6 +30,7 @@ from danswer.file_store.file_store import get_default_file_store from danswer.file_store.models import ChatFileType from danswer.llm.answering.prompts.utils import build_dummy_prompt from danswer.server.features.persona.models import CreatePersonaRequest +from danswer.server.features.persona.models import ImageGenerationToolStatus from danswer.server.features.persona.models import PersonaSharedNotificationData from danswer.server.features.persona.models import PersonaSnapshot from danswer.server.features.persona.models import PromptTemplateResponse @@ -227,6 +228,16 @@ def delete_persona( ) +@basic_router.get("/image-generation-tool") +def get_image_generation_tool( + _: User + | None = Depends(current_user), # User param not used but kept for consistency + db_session: Session = Depends(get_session), +) -> ImageGenerationToolStatus: # Use bool instead of str for boolean values + is_available = is_image_generation_available(db_session=db_session) + return ImageGenerationToolStatus(is_available=is_available) + + @basic_router.get("") def list_personas( user: User | None = Depends(current_user), diff --git a/backend/danswer/server/features/persona/models.py b/backend/danswer/server/features/persona/models.py index 866d70f11..0e69777a0 100644 --- a/backend/danswer/server/features/persona/models.py +++ b/backend/danswer/server/features/persona/models.py @@ -124,3 +124,7 @@ class PromptTemplateResponse(BaseModel): class PersonaSharedNotificationData(BaseModel): persona_id: int + + +class ImageGenerationToolStatus(BaseModel): + is_available: bool diff --git a/web/src/app/admin/assistants/AssistantEditor.tsx b/web/src/app/admin/assistants/AssistantEditor.tsx index 2eec9632c..131cbf593 100644 --- a/web/src/app/admin/assistants/AssistantEditor.tsx +++ b/web/src/app/admin/assistants/AssistantEditor.tsx @@ -45,12 +45,7 @@ import { FullLLMProvider } from "../configuration/llm/interfaces"; import CollapsibleSection from "./CollapsibleSection"; import { SuccessfulPersonaUpdateRedirectType } from "./enums"; import { Persona, StarterMessage } from "./interfaces"; -import { - buildFinalPrompt, - createPersona, - providersContainImageGeneratingSupport, - updatePersona, -} from "./lib"; +import { buildFinalPrompt, createPersona, updatePersona } from "./lib"; import { Popover } from "@/components/popover/Popover"; import { CameraIcon, @@ -106,7 +101,7 @@ export function AssistantEditor({ shouldAddAssistantToUserPreferences?: boolean; admin?: boolean; }) { - const { refreshAssistants } = useAssistants(); + const { refreshAssistants, isImageGenerationAvailable } = useAssistants(); const router = useRouter(); const { popup, setPopup } = usePopup(); @@ -138,38 +133,10 @@ export function AssistantEditor({ const [isIconDropdownOpen, setIsIconDropdownOpen] = useState(false); - const [finalPrompt, setFinalPrompt] = useState(""); - const [finalPromptError, setFinalPromptError] = useState(""); const [removePersonaImage, setRemovePersonaImage] = useState(false); - const triggerFinalPromptUpdate = async ( - systemPrompt: string, - taskPrompt: string, - retrievalDisabled: boolean - ) => { - const response = await buildFinalPrompt( - systemPrompt, - taskPrompt, - retrievalDisabled - ); - if (response.ok) { - setFinalPrompt((await response.json()).final_prompt_template); - } - }; - const isUpdate = existingPersona !== undefined && existingPersona !== null; const existingPrompt = existingPersona?.prompts[0] ?? null; - - useEffect(() => { - if (isUpdate && existingPrompt) { - triggerFinalPromptUpdate( - existingPrompt.system_prompt, - existingPrompt.task_prompt, - existingPersona.num_chunks === 0 - ); - } - }, [isUpdate, existingPrompt, existingPersona?.num_chunks]); - const defaultProvider = llmProviders.find( (llmProvider) => llmProvider.is_default_provider ); @@ -314,14 +281,6 @@ export function AssistantEditor({ } )} onSubmit={async (values, formikHelpers) => { - if (finalPromptError) { - setPopup({ - type: "error", - message: "Cannot submit while there are errors in the form", - }); - return; - } - if ( values.llm_model_provider_override && !values.llm_model_version_override @@ -642,13 +601,7 @@ export function AssistantEditor({ placeholder="e.g. 'You are a professional email writing assistant that always uses a polite enthusiastic tone, emphasizes action items, and leaves blanks for the human to fill in when you have unknowns'" onChange={(e) => { setFieldValue("system_prompt", e.target.value); - triggerFinalPromptUpdate( - e.target.value, - values.task_prompt, - searchToolEnabled() - ); }} - error={finalPromptError} />
@@ -775,7 +728,8 @@ export function AssistantEditor({
{ toggleToolInValues(imageGenerationTool.id); }} - disabled={!currentLLMSupportsImageOutput} + disabled={ + !currentLLMSupportsImageOutput || + !isImageGenerationAvailable + } />
- {!currentLLMSupportsImageOutput && ( + {!currentLLMSupportsImageOutput ? (

To use Image Generation, select GPT-4o or another @@ -799,6 +756,15 @@ export function AssistantEditor({ this Assistant.

+ ) : ( + !isImageGenerationAvailable && ( + +

+ Image Generation requires an OpenAI or Azure + Dalle configuration. +

+
+ ) )} @@ -1024,11 +990,6 @@ export function AssistantEditor({ placeholder="e.g. 'Remember to reference all of the points mentioned in my message to you and focus on identifying action items that can move things forward'" onChange={(e) => { setFieldValue("task_prompt", e.target.value); - triggerFinalPromptUpdate( - values.system_prompt, - e.target.value, - searchToolEnabled() - ); }} explanationText="Learn about prompting in our docs!" explanationLink="https://docs.danswer.dev/guides/assistants" diff --git a/web/src/components/context/AssistantsContext.tsx b/web/src/components/context/AssistantsContext.tsx index 821429e10..f6787f564 100644 --- a/web/src/components/context/AssistantsContext.tsx +++ b/web/src/components/context/AssistantsContext.tsx @@ -21,6 +21,7 @@ interface AssistantsContextProps { finalAssistants: Persona[]; ownedButHiddenAssistants: Persona[]; refreshAssistants: () => Promise; + isImageGenerationAvailable: boolean; // Admin only editablePersonas: Persona[]; @@ -47,51 +48,54 @@ export const AssistantsProvider: React.FC<{ ); const { user, isLoadingUser, isAdmin } = useUser(); const [editablePersonas, setEditablePersonas] = useState([]); - - useEffect(() => { - const fetchEditablePersonas = async () => { - if (!isAdmin) { - return; - } - - try { - const response = await fetch("/api/admin/persona?get_editable=true"); - if (!response.ok) { - console.error("Failed to fetch editable personas"); - return; - } - const personas = await response.json(); - setEditablePersonas(personas); - } catch (error) { - console.error("Error fetching editable personas:", error); - } - }; - - fetchEditablePersonas(); - }, [isAdmin]); - const [allAssistants, setAllAssistants] = useState([]); + const [isImageGenerationAvailable, setIsImageGenerationAvailable] = + useState(false); + useEffect(() => { - const fetchAllAssistants = async () => { + const checkImageGenerationAvailability = async () => { + try { + const response = await fetch("/api/persona/image-generation-tool"); + if (response.ok) { + const { is_available } = await response.json(); + setIsImageGenerationAvailable(is_available); + } + } catch (error) { + console.error("Error checking image generation availability:", error); + } + }; + + checkImageGenerationAvailability(); + }, []); + + useEffect(() => { + const fetchPersonas = async () => { if (!isAdmin) { return; } try { - const response = await fetch("/api/admin/persona"); - if (!response.ok) { - console.error("Failed to fetch all personas"); - return; + const [editableResponse, allResponse] = await Promise.all([ + fetch("/api/admin/persona?get_editable=true"), + fetch("/api/admin/persona"), + ]); + + if (editableResponse.ok) { + const editablePersonas = await editableResponse.json(); + setEditablePersonas(editablePersonas); + } + + if (allResponse.ok) { + const allPersonas = await allResponse.json(); + setAllAssistants(allPersonas); } - const personas = await response.json(); - setAllAssistants(personas); } catch (error) { - console.error("Error fetching all personas:", error); + console.error("Error fetching personas:", error); } }; - fetchAllAssistants(); + fetchPersonas(); }, [isAdmin]); const refreshAssistants = async () => { @@ -162,6 +166,7 @@ export const AssistantsProvider: React.FC<{ refreshAssistants, editablePersonas, allAssistants, + isImageGenerationAvailable, }} > {children} From 31a518a9d15978bdd7b555b4cc9ca9e46853b232 Mon Sep 17 00:00:00 2001 From: pablodanswer Date: Sun, 27 Oct 2024 13:09:13 -0700 Subject: [PATCH 2/2] nit --- web/src/app/admin/assistants/AssistantEditor.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/web/src/app/admin/assistants/AssistantEditor.tsx b/web/src/app/admin/assistants/AssistantEditor.tsx index 131cbf593..9637e7402 100644 --- a/web/src/app/admin/assistants/AssistantEditor.tsx +++ b/web/src/app/admin/assistants/AssistantEditor.tsx @@ -140,7 +140,6 @@ export function AssistantEditor({ const defaultProvider = llmProviders.find( (llmProvider) => llmProvider.is_default_provider ); - const defaultProviderName = defaultProvider?.provider; const defaultModelName = defaultProvider?.default_model_name; const providerDisplayNameToProviderName = new Map(); llmProviders.forEach((llmProvider) => {