diff --git a/create-app.ts b/create-app.ts
index 25c47dbd0bcd72a01625c2fadd0b04fda7da22be..05186ed410c03e8689a112734be3089507f33d03 100644
--- a/create-app.ts
+++ b/create-app.ts
@@ -12,6 +12,14 @@ import terminalLink from "terminal-link";
 import type { InstallTemplateArgs } from "./templates";
 import { installTemplate } from "./templates";
 
+export type InstallAppArgs = Omit<
+  InstallTemplateArgs,
+  "appName" | "root" | "isOnline" | "customApiPath"
+> & {
+  appPath: string;
+  frontend: boolean;
+};
+
 export async function createApp({
   template,
   framework,
@@ -22,13 +30,8 @@ export async function createApp({
   eslint,
   frontend,
   openAIKey,
-}: Omit<
-  InstallTemplateArgs,
-  "appName" | "root" | "isOnline" | "customApiPath"
-> & {
-  appPath: string;
-  frontend: boolean;
-}): Promise<void> {
+  model,
+}: InstallAppArgs): Promise<void> {
   const root = path.resolve(appPath);
 
   if (!(await isWriteable(path.dirname(root)))) {
@@ -65,6 +68,7 @@ export async function createApp({
     isOnline,
     eslint,
     openAIKey,
+    model,
   };
 
   if (frontend) {
diff --git a/index.ts b/index.ts
index 14571b74b651992c937279a5a0cff365d33de6c3..67a0f53cee61859280f5729ed73c1f5e81e22238 100644
--- a/index.ts
+++ b/index.ts
@@ -8,7 +8,7 @@ import path from "path";
 import { blue, bold, cyan, green, red, yellow } from "picocolors";
 import prompts from "prompts";
 import checkForUpdate from "update-check";
-import { createApp } from "./create-app";
+import { InstallAppArgs, createApp } from "./create-app";
 import { getPkgManager } from "./helpers/get-pkg-manager";
 import { isFolderEmpty } from "./helpers/is-folder-empty";
 import { validateNpmName } from "./helpers/validate-pkg";
@@ -155,21 +155,22 @@ async function run(): Promise<void> {
     process.exit(1);
   }
 
-  const preferences = (conf.get("preferences") || {}) as Record<
-    string,
-    boolean | string
-  >;
+  // TODO: use Args also for program
+  type Args = Omit<InstallAppArgs, "appPath" | "packageManager">;
 
-  const defaults: typeof preferences = {
-    template: "simple",
+  const preferences = (conf.get("preferences") || {}) as Args;
+
+  const defaults: Args = {
+    template: "streaming",
     framework: "nextjs",
     engine: "simple",
     ui: "html",
     eslint: true,
     frontend: false,
     openAIKey: "",
+    model: "gpt-3.5-turbo",
   };
-  const getPrefOrDefault = (field: string) =>
+  const getPrefOrDefault = (field: keyof Args) =>
     preferences[field] ?? defaults[field];
 
   const handlers = {
@@ -179,48 +180,51 @@ async function run(): Promise<void> {
     },
   };
 
-  if (!program.template) {
+  if (!program.framework) {
     if (ciInfo.isCI) {
-      program.template = getPrefOrDefault("template");
+      program.framework = getPrefOrDefault("framework");
     } else {
-      const { template } = await prompts(
+      const { framework } = await prompts(
         {
           type: "select",
-          name: "template",
-          message: "Which template would you like to use?",
+          name: "framework",
+          message: "Which framework would you like to use?",
           choices: [
-            { title: "Chat without streaming", value: "simple" },
-            { title: "Chat with streaming", value: "streaming" },
+            { title: "NextJS", value: "nextjs" },
+            { title: "Express", value: "express" },
+            { title: "FastAPI (Python)", value: "fastapi" },
           ],
-          initial: 1,
+          initial: 0,
         },
         handlers,
       );
-      program.template = template;
-      preferences.template = template;
+      program.framework = framework;
+      preferences.framework = framework;
     }
   }
 
-  if (!program.framework) {
+  if (program.framework === "nextjs") {
+    program.template = "streaming";
+  }
+  if (!program.template) {
     if (ciInfo.isCI) {
-      program.framework = getPrefOrDefault("framework");
+      program.template = getPrefOrDefault("template");
     } else {
-      const { framework } = await prompts(
+      const { template } = await prompts(
         {
           type: "select",
-          name: "framework",
-          message: "Which framework would you like to use?",
+          name: "template",
+          message: "Which template would you like to use?",
           choices: [
-            { title: "NextJS", value: "nextjs" },
-            { title: "Express", value: "express" },
-            { title: "FastAPI (Python)", value: "fastapi" },
+            { title: "Chat without streaming", value: "simple" },
+            { title: "Chat with streaming", value: "streaming" },
           ],
-          initial: 0,
+          initial: 1,
         },
         handlers,
       );
-      program.framework = framework;
-      preferences.framework = framework;
+      program.template = template;
+      preferences.template = template;
     }
   }
 
@@ -277,6 +281,32 @@ async function run(): Promise<void> {
     }
   }
 
+  if (program.framework === "nextjs") {
+    if (!program.model) {
+      if (ciInfo.isCI) {
+        program.model = getPrefOrDefault("model");
+      } else {
+        const { model } = await prompts(
+          {
+            type: "select",
+            name: "model",
+            message: "Which model would you like to use?",
+            choices: [
+              { title: "gpt-3.5-turbo", value: "gpt-3.5-turbo" },
+              { title: "gpt-4", value: "gpt-4" },
+              { title: "gpt-4-1106-preview", value: "gpt-4-1106-preview" },
+              { title: "gpt-4-vision-preview", value: "gpt-4-vision-preview" },
+            ],
+            initial: 0,
+          },
+          handlers,
+        );
+        program.model = model;
+        preferences.model = model;
+      }
+    }
+  }
+
   if (program.framework === "express" || program.framework === "nextjs") {
     if (!program.engine) {
       if (ciInfo.isCI) {
@@ -350,6 +380,7 @@ async function run(): Promise<void> {
     eslint: program.eslint,
     frontend: program.frontend,
     openAIKey: program.openAIKey,
+    model: program.model,
   });
   conf.set("preferences", preferences);
 }
diff --git a/templates/components/ui/shadcn/chat/chat-input.tsx b/templates/components/ui/shadcn/chat/chat-input.tsx
index 1a0cc3e0cc6d92178bafce5e8d573586e024e3f6..435637e5ec94fdb9fe03faa3c3e1791a0be584bb 100644
--- a/templates/components/ui/shadcn/chat/chat-input.tsx
+++ b/templates/components/ui/shadcn/chat/chat-input.tsx
@@ -1,29 +1,84 @@
+import { useState } from "react";
 import { Button } from "../button";
+import FileUploader from "../file-uploader";
 import { Input } from "../input";
+import UploadImagePreview from "../upload-image-preview";
 import { ChatHandler } from "./chat.interface";
 
 export default function ChatInput(
   props: Pick<
     ChatHandler,
-    "isLoading" | "handleSubmit" | "handleInputChange" | "input"
-  >,
+    | "isLoading"
+    | "input"
+    | "onFileUpload"
+    | "onFileError"
+    | "handleSubmit"
+    | "handleInputChange"
+  > & {
+    multiModal?: boolean;
+  },
 ) {
+  const [imageUrl, setImageUrl] = useState<string | null>(null);
+
+  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
+    if (imageUrl) {
+      props.handleSubmit(e, {
+        data: { imageUrl: imageUrl },
+      });
+      setImageUrl(null);
+      return;
+    }
+    props.handleSubmit(e);
+  };
+
+  const onRemovePreviewImage = () => setImageUrl(null);
+
+  const handleUploadImageFile = async (file: File) => {
+    const base64 = await new Promise<string>((resolve, reject) => {
+      const reader = new FileReader();
+      reader.readAsDataURL(file);
+      reader.onload = () => resolve(reader.result as string);
+      reader.onerror = (error) => reject(error);
+    });
+    setImageUrl(base64);
+  };
+
+  const handleUploadFile = async (file: File) => {
+    try {
+      if (props.multiModal && file.type.startsWith("image/")) {
+        return await handleUploadImageFile(file);
+      }
+      props.onFileUpload?.(file);
+    } catch (error: any) {
+      props.onFileError?.(error.message);
+    }
+  };
+
   return (
     <form
-      onSubmit={props.handleSubmit}
-      className="flex w-full items-start justify-between gap-4 rounded-xl bg-white p-4 shadow-xl"
+      onSubmit={onSubmit}
+      className="rounded-xl bg-white p-4 shadow-xl space-y-4"
     >
-      <Input
-        autoFocus
-        name="message"
-        placeholder="Type a message"
-        className="flex-1"
-        value={props.input}
-        onChange={props.handleInputChange}
-      />
-      <Button type="submit" disabled={props.isLoading}>
-        Send message
-      </Button>
+      {imageUrl && (
+        <UploadImagePreview url={imageUrl} onRemove={onRemovePreviewImage} />
+      )}
+      <div className="flex w-full items-start justify-between gap-4 ">
+        <Input
+          autoFocus
+          name="message"
+          placeholder="Type a message"
+          className="flex-1"
+          value={props.input}
+          onChange={props.handleInputChange}
+        />
+        <FileUploader
+          onFileUpload={handleUploadFile}
+          onFileError={props.onFileError}
+        />
+        <Button type="submit" disabled={props.isLoading}>
+          Send message
+        </Button>
+      </div>
     </form>
   );
 }
diff --git a/templates/components/ui/shadcn/chat/chat.interface.ts b/templates/components/ui/shadcn/chat/chat.interface.ts
index 3256f7f031b42114f192f3375632654dc21f78d8..584a63f7333b86531148dd7849c3233c82fdbf16 100644
--- a/templates/components/ui/shadcn/chat/chat.interface.ts
+++ b/templates/components/ui/shadcn/chat/chat.interface.ts
@@ -8,8 +8,15 @@ export interface ChatHandler {
   messages: Message[];
   input: string;
   isLoading: boolean;
-  handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
+  handleSubmit: (
+    e: React.FormEvent<HTMLFormElement>,
+    ops?: {
+      data?: any;
+    },
+  ) => void;
   handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
   reload?: () => void;
   stop?: () => void;
+  onFileUpload?: (file: File) => Promise<void>;
+  onFileError?: (errMsg: string) => void;
 }
diff --git a/templates/components/ui/shadcn/file-uploader.tsx b/templates/components/ui/shadcn/file-uploader.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e42a267d18cbe76391d1decad0acca8fdf4dc295
--- /dev/null
+++ b/templates/components/ui/shadcn/file-uploader.tsx
@@ -0,0 +1,105 @@
+"use client";
+
+import { Loader2, Paperclip } from "lucide-react";
+import { ChangeEvent, useState } from "react";
+import { buttonVariants } from "./button";
+import { cn } from "./lib/utils";
+
+export interface FileUploaderProps {
+  config?: {
+    inputId?: string;
+    fileSizeLimit?: number;
+    allowedExtensions?: string[];
+    checkExtension?: (extension: string) => string | null;
+    disabled: boolean;
+  };
+  onFileUpload: (file: File) => Promise<void>;
+  onFileError?: (errMsg: string) => void;
+}
+
+const DEFAULT_INPUT_ID = "fileInput";
+const DEFAULT_FILE_SIZE_LIMIT = 1024 * 1024 * 50; // 50 MB
+
+export default function FileUploader({
+  config,
+  onFileUpload,
+  onFileError,
+}: FileUploaderProps) {
+  const [uploading, setUploading] = useState(false);
+
+  const inputId = config?.inputId || DEFAULT_INPUT_ID;
+  const fileSizeLimit = config?.fileSizeLimit || DEFAULT_FILE_SIZE_LIMIT;
+  const allowedExtensions = config?.allowedExtensions;
+  const defaultCheckExtension = (extension: string) => {
+    if (allowedExtensions && !allowedExtensions.includes(extension)) {
+      return `Invalid file type. Please select a file with one of these formats: ${allowedExtensions!.join(
+        ",",
+      )}`;
+    }
+    return null;
+  };
+  const checkExtension = config?.checkExtension ?? defaultCheckExtension;
+
+  const isFileSizeExceeded = (file: File) => {
+    return file.size > fileSizeLimit;
+  };
+
+  const resetInput = () => {
+    const fileInput = document.getElementById(inputId) as HTMLInputElement;
+    fileInput.value = "";
+  };
+
+  const onFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
+    const file = e.target.files?.[0];
+    if (!file) return;
+
+    setUploading(true);
+    await handleUpload(file);
+    resetInput();
+    setUploading(false);
+  };
+
+  const handleUpload = async (file: File) => {
+    const onFileUploadError = onFileError || window.alert;
+    const fileExtension = file.name.split(".").pop() || "";
+    const extensionFileError = checkExtension(fileExtension);
+    if (extensionFileError) {
+      return onFileUploadError(extensionFileError);
+    }
+
+    if (isFileSizeExceeded(file)) {
+      return onFileUploadError(
+        `File size exceeded. Limit is ${fileSizeLimit / 1024 / 1024} MB`,
+      );
+    }
+
+    await onFileUpload(file);
+  };
+
+  return (
+    <div className="self-stretch">
+      <input
+        type="file"
+        id={inputId}
+        style={{ display: "none" }}
+        onChange={onFileChange}
+        accept={allowedExtensions?.join(",")}
+        disabled={config?.disabled || uploading}
+      />
+      <label
+        htmlFor={inputId}
+        className={cn(
+          buttonVariants({ variant: "secondary", size: "icon" }),
+          "cursor-pointer",
+          uploading && "opacity-50",
+        )}
+      >
+        {uploading ? (
+          <Loader2 className="h-4 w-4 animate-spin" />
+        ) : (
+          <Paperclip className="-rotate-45 w-4 h-4" />
+        )}
+      </label>
+    </div>
+  );
+}
diff --git a/templates/components/ui/shadcn/upload-image-preview.tsx b/templates/components/ui/shadcn/upload-image-preview.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..55ef6e9c2793ef4eb935422a9eedbfdb611a2304
--- /dev/null
+++ b/templates/components/ui/shadcn/upload-image-preview.tsx
@@ -0,0 +1,32 @@
+import { XCircleIcon } from "lucide-react";
+import Image from "next/image";
+import { cn } from "./lib/utils";
+
+export default function UploadImagePreview({
+  url,
+  onRemove,
+}: {
+  url: string;
+  onRemove: () => void;
+}) {
+  return (
+    <div className="relative w-20 h-20 group">
+      <Image
+        src={url}
+        alt="Uploaded image"
+        fill
+        className="object-cover w-full h-full rounded-xl hover:brightness-75"
+      />
+      <div
+        className={cn(
+          "absolute -top-2 -right-2 w-6 h-6 z-10 bg-gray-500 text-white rounded-full hidden group-hover:block",
+        )}
+      >
+        <XCircleIcon
+          className="w-6 h-6 bg-gray-500 text-white rounded-full"
+          onClick={onRemove}
+        />
+      </div>
+    </div>
+  );
+}
diff --git a/templates/index.ts b/templates/index.ts
index 2c1f8737706d9f58afb7a269d15c743f2f8f2bc3..fd5377d87115361e4e7c609569928ac4da7686fd 100644
--- a/templates/index.ts
+++ b/templates/index.ts
@@ -101,6 +101,7 @@ const installTSTemplate = async ({
   eslint,
   customApiPath,
   forBackend,
+  model,
 }: InstallTemplateArgs) => {
   console.log(bold(`Using ${packageManager}.`));
 
@@ -173,6 +174,14 @@ const installTSTemplate = async ({
     });
   }
 
+  if (framework === "nextjs") {
+    await fs.writeFile(
+      path.join(root, "constants.ts"),
+      `export const MODEL = "${model || "gpt-3.5-turbo"}";\n`,
+    );
+    console.log("\nUsing OpenAI model: ", model || "gpt-3.5-turbo", "\n");
+  }
+
   /**
    * Update the package.json scripts.
    */
diff --git a/templates/types.ts b/templates/types.ts
index 926dddd5d97899e0886f6c2fc788906d168363e4..f6af4de02e21cbd018b2b82cf7473ce54e1caa6e 100644
--- a/templates/types.ts
+++ b/templates/types.ts
@@ -18,4 +18,5 @@ export interface InstallTemplateArgs {
   customApiPath?: string;
   openAIKey?: string;
   forBackend?: string;
+  model: string;
 }
diff --git a/templates/types/simple/nextjs/.env.example b/templates/types/simple/nextjs/.env.example
deleted file mode 100644
index 7ac0a01551a65a68003c2615d510269b5d6a77f6..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/.env.example
+++ /dev/null
@@ -1,3 +0,0 @@
-# Rename this file to `.env.local` to use environment variables locally with `next dev`
-# https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
-MY_HOST="example.com"
diff --git a/templates/types/simple/nextjs/README-template.md b/templates/types/simple/nextjs/README-template.md
deleted file mode 100644
index 1509ded7c3be489d369b94d6d6a286d496f488d8..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/README-template.md
+++ /dev/null
@@ -1,30 +0,0 @@
-This is a [LlamaIndex](https://www.llamaindex.ai/) project using [Next.js](https://nextjs.org/) bootstrapped with [`create-llama`](https://github.com/run-llama/LlamaIndexTS/tree/main/packages/create-llama).
-
-## Getting Started
-
-First, install the dependencies:
-
-```
-npm install
-```
-
-Second, run the development server:
-
-```
-npm run dev
-```
-
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
-
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
-
-This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
-
-## Learn More
-
-To learn more about LlamaIndex, take a look at the following resources:
-
-- [LlamaIndex Documentation](https://docs.llamaindex.ai) - learn about LlamaIndex (Python features).
-- [LlamaIndexTS Documentation](https://ts.llamaindex.ai) - learn about LlamaIndex (Typescript features).
-
-You can check out [the LlamaIndexTS GitHub repository](https://github.com/run-llama/LlamaIndexTS) - your feedback and contributions are welcome!
diff --git a/templates/types/simple/nextjs/app/api/chat/engine/index.ts b/templates/types/simple/nextjs/app/api/chat/engine/index.ts
deleted file mode 100644
index abb02e90cd2ce91096791bf10c4665afcbe11d38..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/api/chat/engine/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { LLM, SimpleChatEngine } from "llamaindex";
-
-export async function createChatEngine(llm: LLM) {
-  return new SimpleChatEngine({
-    llm,
-  });
-}
diff --git a/templates/types/simple/nextjs/app/api/chat/route.ts b/templates/types/simple/nextjs/app/api/chat/route.ts
deleted file mode 100644
index 097341ab43922058b9d06b53c215feb16a2a7e23..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/api/chat/route.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { ChatMessage, OpenAI } from "llamaindex";
-import { NextRequest, NextResponse } from "next/server";
-import { createChatEngine } from "./engine";
-
-export const runtime = "nodejs";
-export const dynamic = "force-dynamic";
-
-export async function POST(request: NextRequest) {
-  try {
-    const body = await request.json();
-    const { messages }: { messages: ChatMessage[] } = body;
-    const lastMessage = messages.pop();
-    if (!messages || !lastMessage || lastMessage.role !== "user") {
-      return NextResponse.json(
-        {
-          error:
-            "messages are required in the request body and the last message must be from the user",
-        },
-        { status: 400 },
-      );
-    }
-
-    const llm = new OpenAI({
-      model: "gpt-3.5-turbo",
-    });
-
-    const chatEngine = await createChatEngine(llm);
-
-    const response = await chatEngine.chat(lastMessage.content, messages);
-    const result: ChatMessage = {
-      role: "assistant",
-      content: response.response,
-    };
-
-    return NextResponse.json({ result });
-  } catch (error) {
-    console.error("[LlamaIndex]", error);
-    return NextResponse.json(
-      {
-        error: (error as Error).message,
-      },
-      {
-        status: 500,
-      },
-    );
-  }
-}
diff --git a/templates/types/simple/nextjs/app/components/chat-section.tsx b/templates/types/simple/nextjs/app/components/chat-section.tsx
deleted file mode 100644
index 133a0a884bb82fb1ed3c78553852b8ae9b169cd5..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/components/chat-section.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-"use client";
-
-import { nanoid } from "nanoid";
-import { useState } from "react";
-import { ChatInput, ChatInputProps, ChatMessages, Message } from "./ui/chat";
-
-function useChat(): ChatInputProps & { messages: Message[] } {
-  const [messages, setMessages] = useState<Message[]>([]);
-  const [isLoading, setIsLoading] = useState(false);
-  const [input, setInput] = useState("");
-
-  const getAssistantMessage = async (messages: Message[]) => {
-    const response = await fetch(
-      process.env.NEXT_PUBLIC_CHAT_API ?? "/api/chat",
-      {
-        method: "POST",
-        headers: {
-          "Content-Type": "application/json",
-        },
-        body: JSON.stringify({
-          messages,
-        }),
-      },
-    );
-    const data = await response.json();
-    const assistantMessage = data.result as Message;
-    return assistantMessage;
-  };
-
-  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
-    e.preventDefault();
-    if (!input) return;
-
-    setIsLoading(true);
-
-    try {
-      const newMessages = [
-        ...messages,
-        { id: nanoid(), content: input, role: "user" },
-      ];
-      setMessages(newMessages);
-      setInput("");
-      const assistantMessage = await getAssistantMessage(newMessages);
-      setMessages([...newMessages, { ...assistantMessage, id: nanoid() }]);
-    } catch (error: any) {
-      console.log(error);
-      alert(error.message);
-    } finally {
-      setIsLoading(false);
-    }
-  };
-
-  const handleInputChange = (e: any): void => {
-    setInput(e.target.value);
-  };
-
-  return {
-    messages,
-    isLoading,
-    input,
-    handleSubmit,
-    handleInputChange,
-  };
-}
-
-export default function ChatSection() {
-  const { messages, isLoading, input, handleSubmit, handleInputChange } =
-    useChat();
-  return (
-    <div className="space-y-4 max-w-5xl w-full">
-      <ChatMessages messages={messages} />
-      <ChatInput
-        handleSubmit={handleSubmit}
-        isLoading={isLoading}
-        input={input}
-        handleInputChange={handleInputChange}
-      />
-    </div>
-  );
-}
diff --git a/templates/types/simple/nextjs/app/components/header.tsx b/templates/types/simple/nextjs/app/components/header.tsx
deleted file mode 100644
index 2b0e488f769eff6700a282c2a6a77dd8d0a4dac8..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/components/header.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import Image from "next/image";
-
-export default function Header() {
-  return (
-    <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
-      <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto  lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
-        Get started by editing&nbsp;
-        <code className="font-mono font-bold">app/page.tsx</code>
-      </p>
-      <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
-        <a
-          href="https://www.llamaindex.ai/"
-          className="flex items-center justify-center font-nunito text-lg font-bold gap-2"
-        >
-          <span>Built by LlamaIndex</span>
-          <Image
-            className="rounded-xl"
-            src="/llama.png"
-            alt="Llama Logo"
-            width={40}
-            height={40}
-            priority
-          />
-        </a>
-      </div>
-    </div>
-  );
-}
diff --git a/templates/types/simple/nextjs/app/components/ui/chat/chat-avatar.tsx b/templates/types/simple/nextjs/app/components/ui/chat/chat-avatar.tsx
deleted file mode 100644
index cd241104e4ef210c728aec47a1ab8b0161ad6538..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/components/ui/chat/chat-avatar.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-"use client";
-
-import Image from "next/image";
-import { Message } from "./chat-messages";
-
-export default function ChatAvatar(message: Message) {
-  if (message.role === "user") {
-    return (
-      <div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border shadow bg-background">
-        <svg
-          xmlns="http://www.w3.org/2000/svg"
-          viewBox="0 0 256 256"
-          fill="currentColor"
-          className="h-4 w-4"
-        >
-          <path d="M230.92 212c-15.23-26.33-38.7-45.21-66.09-54.16a72 72 0 1 0-73.66 0c-27.39 8.94-50.86 27.82-66.09 54.16a8 8 0 1 0 13.85 8c18.84-32.56 52.14-52 89.07-52s70.23 19.44 89.07 52a8 8 0 1 0 13.85-8ZM72 96a56 56 0 1 1 56 56 56.06 56.06 0 0 1-56-56Z"></path>
-        </svg>
-      </div>
-    );
-  }
-
-  return (
-    <div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border  bg-black text-white">
-      <Image
-        className="rounded-md"
-        src="/llama.png"
-        alt="Llama Logo"
-        width={24}
-        height={24}
-        priority
-      />
-    </div>
-  );
-}
diff --git a/templates/types/simple/nextjs/app/components/ui/chat/chat-input.tsx b/templates/types/simple/nextjs/app/components/ui/chat/chat-input.tsx
deleted file mode 100644
index 3eb979b02735943f3f11290c78b84f0e37709438..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/components/ui/chat/chat-input.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-"use client";
-
-export interface ChatInputProps {
-  /** The current value of the input */
-  input?: string;
-  /** An input/textarea-ready onChange handler to control the value of the input */
-  handleInputChange?: (
-    e:
-      | React.ChangeEvent<HTMLInputElement>
-      | React.ChangeEvent<HTMLTextAreaElement>,
-  ) => void;
-  /** Form submission handler to automatically reset input and append a user message  */
-  handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
-  isLoading: boolean;
-}
-
-export default function ChatInput(props: ChatInputProps) {
-  return (
-    <>
-      <form
-        onSubmit={props.handleSubmit}
-        className="flex items-start justify-between w-full max-w-5xl p-4 bg-white rounded-xl shadow-xl gap-4"
-      >
-        <input
-          autoFocus
-          name="message"
-          placeholder="Type a message"
-          className="w-full p-4 rounded-xl shadow-inner flex-1"
-          value={props.input}
-          onChange={props.handleInputChange}
-        />
-        <button
-          disabled={props.isLoading}
-          type="submit"
-          className="p-4 text-white rounded-xl shadow-xl bg-gradient-to-r from-cyan-500 to-sky-500 disabled:opacity-50 disabled:cursor-not-allowed"
-        >
-          Send message
-        </button>
-      </form>
-    </>
-  );
-}
diff --git a/templates/types/simple/nextjs/app/components/ui/chat/chat-item.tsx b/templates/types/simple/nextjs/app/components/ui/chat/chat-item.tsx
deleted file mode 100644
index 2244f729a8ba668121ab5ec0842963d22153ef92..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/components/ui/chat/chat-item.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-"use client";
-
-import ChatAvatar from "./chat-avatar";
-import { Message } from "./chat-messages";
-
-export default function ChatItem(message: Message) {
-  return (
-    <div className="flex items-start gap-4 pt-5">
-      <ChatAvatar {...message} />
-      <p className="break-words">{message.content}</p>
-    </div>
-  );
-}
diff --git a/templates/types/simple/nextjs/app/components/ui/chat/chat-messages.tsx b/templates/types/simple/nextjs/app/components/ui/chat/chat-messages.tsx
deleted file mode 100644
index 65eacabbfb1b7bc99950b43e7fd07ba56b3ecdb0..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/components/ui/chat/chat-messages.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-"use client";
-
-import { useEffect, useRef } from "react";
-import ChatItem from "./chat-item";
-
-export interface Message {
-  id: string;
-  content: string;
-  role: string;
-}
-
-export default function ChatMessages({ messages }: { messages: Message[] }) {
-  const scrollableChatContainerRef = useRef<HTMLDivElement>(null);
-
-  const scrollToBottom = () => {
-    if (scrollableChatContainerRef.current) {
-      scrollableChatContainerRef.current.scrollTop =
-        scrollableChatContainerRef.current.scrollHeight;
-    }
-  };
-
-  useEffect(() => {
-    scrollToBottom();
-  }, [messages.length]);
-
-  return (
-    <div className="w-full max-w-5xl p-4 bg-white rounded-xl shadow-xl">
-      <div
-        className="flex flex-col gap-5 divide-y h-[50vh] overflow-auto"
-        ref={scrollableChatContainerRef}
-      >
-        {messages.map((m: Message) => (
-          <ChatItem key={m.id} {...m} />
-        ))}
-      </div>
-    </div>
-  );
-}
diff --git a/templates/types/simple/nextjs/app/components/ui/chat/index.ts b/templates/types/simple/nextjs/app/components/ui/chat/index.ts
deleted file mode 100644
index 5de7dce47fc1e2330759171db291eedbca19e722..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/components/ui/chat/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import ChatInput from "./chat-input";
-import ChatMessages from "./chat-messages";
-
-export type { ChatInputProps } from "./chat-input";
-export type { Message } from "./chat-messages";
-export { ChatInput, ChatMessages };
diff --git a/templates/types/simple/nextjs/app/favicon.ico b/templates/types/simple/nextjs/app/favicon.ico
deleted file mode 100644
index a1eaef62f2dfa895f1bbffc6595bb53d9604963e..0000000000000000000000000000000000000000
Binary files a/templates/types/simple/nextjs/app/favicon.ico and /dev/null differ
diff --git a/templates/types/simple/nextjs/app/globals.css b/templates/types/simple/nextjs/app/globals.css
deleted file mode 100644
index 09b85ed2c912e25518ddebbfebaba69090f889f4..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/globals.css
+++ /dev/null
@@ -1,94 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-@layer base {
-  :root {
-    --background: 0 0% 100%;
-    --foreground: 222.2 47.4% 11.2%;
-
-    --muted: 210 40% 96.1%;
-    --muted-foreground: 215.4 16.3% 46.9%;
-
-    --popover: 0 0% 100%;
-    --popover-foreground: 222.2 47.4% 11.2%;
-
-    --border: 214.3 31.8% 91.4%;
-    --input: 214.3 31.8% 91.4%;
-
-    --card: 0 0% 100%;
-    --card-foreground: 222.2 47.4% 11.2%;
-
-    --primary: 222.2 47.4% 11.2%;
-    --primary-foreground: 210 40% 98%;
-
-    --secondary: 210 40% 96.1%;
-    --secondary-foreground: 222.2 47.4% 11.2%;
-
-    --accent: 210 40% 96.1%;
-    --accent-foreground: 222.2 47.4% 11.2%;
-
-    --destructive: 0 100% 50%;
-    --destructive-foreground: 210 40% 98%;
-
-    --ring: 215 20.2% 65.1%;
-
-    --radius: 0.5rem;
-  }
-
-  .dark {
-    --background: 224 71% 4%;
-    --foreground: 213 31% 91%;
-
-    --muted: 223 47% 11%;
-    --muted-foreground: 215.4 16.3% 56.9%;
-
-    --accent: 216 34% 17%;
-    --accent-foreground: 210 40% 98%;
-
-    --popover: 224 71% 4%;
-    --popover-foreground: 215 20.2% 65.1%;
-
-    --border: 216 34% 17%;
-    --input: 216 34% 17%;
-
-    --card: 224 71% 4%;
-    --card-foreground: 213 31% 91%;
-
-    --primary: 210 40% 98%;
-    --primary-foreground: 222.2 47.4% 1.2%;
-
-    --secondary: 222.2 47.4% 11.2%;
-    --secondary-foreground: 210 40% 98%;
-
-    --destructive: 0 63% 31%;
-    --destructive-foreground: 210 40% 98%;
-
-    --ring: 216 34% 17%;
-
-    --radius: 0.5rem;
-  }
-}
-
-@layer base {
-  * {
-    @apply border-border;
-  }
-  body {
-    @apply bg-background text-foreground;
-    font-feature-settings:
-      "rlig" 1,
-      "calt" 1;
-  }
-  .background-gradient {
-    background-color: #fff;
-    background-image: radial-gradient(
-        at 21% 11%,
-        rgba(186, 186, 233, 0.53) 0,
-        transparent 50%
-      ),
-      radial-gradient(at 85% 0, hsla(46, 57%, 78%, 0.52) 0, transparent 50%),
-      radial-gradient(at 91% 36%, rgba(194, 213, 255, 0.68) 0, transparent 50%),
-      radial-gradient(at 8% 40%, rgba(251, 218, 239, 0.46) 0, transparent 50%);
-  }
-}
diff --git a/templates/types/simple/nextjs/app/layout.tsx b/templates/types/simple/nextjs/app/layout.tsx
deleted file mode 100644
index fb097706274bdfe4690e4953bba24d7acea0a021..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/layout.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { Metadata } from "next";
-import { Inter } from "next/font/google";
-import "./globals.css";
-
-const inter = Inter({ subsets: ["latin"] });
-
-export const metadata: Metadata = {
-  title: "Create Llama App",
-  description: "Generated by create-llama",
-};
-
-export default function RootLayout({
-  children,
-}: {
-  children: React.ReactNode;
-}) {
-  return (
-    <html lang="en">
-      <body className={inter.className}>{children}</body>
-    </html>
-  );
-}
diff --git a/templates/types/simple/nextjs/app/page.tsx b/templates/types/simple/nextjs/app/page.tsx
deleted file mode 100644
index 31f51facb248687cf7e7c6b34493778634a8c59c..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/app/page.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import ChatSection from "@/app/components/chat-section";
-import Header from "@/app/components/header";
-
-export default function Home() {
-  return (
-    <main className="flex min-h-screen flex-col items-center gap-10 p-24 background-gradient">
-      <Header />
-      <ChatSection />
-    </main>
-  );
-}
diff --git a/templates/types/simple/nextjs/eslintrc.json b/templates/types/simple/nextjs/eslintrc.json
deleted file mode 100644
index bffb357a7122523ec94045523758c4b825b448ef..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/eslintrc.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "extends": "next/core-web-vitals"
-}
diff --git a/templates/types/simple/nextjs/gitignore b/templates/types/simple/nextjs/gitignore
deleted file mode 100644
index 8f322f0d8f49570a594b865ef8916c428a01afc1..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/gitignore
+++ /dev/null
@@ -1,35 +0,0 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-# dependencies
-/node_modules
-/.pnp
-.pnp.js
-
-# testing
-/coverage
-
-# next.js
-/.next/
-/out/
-
-# production
-/build
-
-# misc
-.DS_Store
-*.pem
-
-# debug
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# local env files
-.env*.local
-
-# vercel
-.vercel
-
-# typescript
-*.tsbuildinfo
-next-env.d.ts
diff --git a/templates/types/simple/nextjs/next-env.d.ts b/templates/types/simple/nextjs/next-env.d.ts
deleted file mode 100644
index 4f11a03dc6cc37f2b5105c08f2e7b24c603ab2f4..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/next-env.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-/// <reference types="next" />
-/// <reference types="next/image-types/global" />
-
-// NOTE: This file should not be edited
-// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/templates/types/simple/nextjs/next.config.app.js b/templates/types/simple/nextjs/next.config.app.js
deleted file mode 100644
index 0ff94969142b0c759dfa75ace8ee4300e8860620..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/next.config.app.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/** @type {import('next').NextConfig} */
-const nextConfig = {
-  webpack: (config) => {
-    // See https://webpack.js.org/configuration/resolve/#resolvealias
-    config.resolve.alias = {
-      ...config.resolve.alias,
-      sharp$: false,
-      "onnxruntime-node$": false,
-      mongodb$: false,
-    };
-    return config;
-  },
-  experimental: {
-    serverComponentsExternalPackages: ["llamaindex"],
-    outputFileTracingIncludes: {
-      "/*": ["./cache/**/*"],
-    },
-  },
-};
-
-module.exports = nextConfig;
diff --git a/templates/types/simple/nextjs/next.config.static.js b/templates/types/simple/nextjs/next.config.static.js
deleted file mode 100644
index c5e9ab41f7395aba6fddbfd39ef9c7c776ae9f79..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/next.config.static.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/** @type {import('next').NextConfig} */
-const nextConfig = {
-  output: "export",
-  images: { unoptimized: true },
-  webpack: (config) => {
-    // See https://webpack.js.org/configuration/resolve/#resolvealias
-    config.resolve.alias = {
-      ...config.resolve.alias,
-      sharp$: false,
-      "onnxruntime-node$": false,
-      mongodb$: false,
-    };
-    return config;
-  },
-  experimental: {
-    serverComponentsExternalPackages: ["llamaindex"],
-    outputFileTracingIncludes: {
-      "/*": ["./cache/**/*"],
-    },
-  },
-};
-
-module.exports = nextConfig;
diff --git a/templates/types/simple/nextjs/package.json b/templates/types/simple/nextjs/package.json
deleted file mode 100644
index 5faf066d60bb3256f245b9f1536c9cf58e2fe2f4..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/package.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "name": "llama-index-nextjs",
-  "version": "1.0.0",
-  "scripts": {
-    "dev": "next dev",
-    "build": "next build",
-    "start": "next start",
-    "lint": "next lint"
-  },
-  "dependencies": {
-    "llamaindex": "0.0.31",
-    "dotenv": "^16.3.1",
-    "nanoid": "^5",
-    "next": "^13",
-    "react": "^18",
-    "react-dom": "^18"
-  },
-  "devDependencies": {
-    "@types/node": "^20",
-    "@types/react": "^18",
-    "@types/react-dom": "^18",
-    "autoprefixer": "^10.1",
-    "eslint": "^8",
-    "eslint-config-next": "^13",
-    "postcss": "^8",
-    "tailwindcss": "^3.3",
-    "typescript": "^5"
-  }
-}
\ No newline at end of file
diff --git a/templates/types/simple/nextjs/postcss.config.js b/templates/types/simple/nextjs/postcss.config.js
deleted file mode 100644
index 12a703d900da8159c30e75acbd2c4d87ae177f62..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/postcss.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = {
-  plugins: {
-    tailwindcss: {},
-    autoprefixer: {},
-  },
-};
diff --git a/templates/types/simple/nextjs/public/llama.png b/templates/types/simple/nextjs/public/llama.png
deleted file mode 100644
index d4efba3b816bf765439c6d01b322b02684e946c3..0000000000000000000000000000000000000000
Binary files a/templates/types/simple/nextjs/public/llama.png and /dev/null differ
diff --git a/templates/types/simple/nextjs/tailwind.config.ts b/templates/types/simple/nextjs/tailwind.config.ts
deleted file mode 100644
index aa5580affac868255fedb5a8ddc0dde7a105c454..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/tailwind.config.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import type { Config } from "tailwindcss";
-import { fontFamily } from "tailwindcss/defaultTheme";
-
-const config: Config = {
-  darkMode: ["class"],
-  content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"],
-  theme: {
-    container: {
-      center: true,
-      padding: "2rem",
-      screens: {
-        "2xl": "1400px",
-      },
-    },
-    extend: {
-      colors: {
-        border: "hsl(var(--border))",
-        input: "hsl(var(--input))",
-        ring: "hsl(var(--ring))",
-        background: "hsl(var(--background))",
-        foreground: "hsl(var(--foreground))",
-        primary: {
-          DEFAULT: "hsl(var(--primary))",
-          foreground: "hsl(var(--primary-foreground))",
-        },
-        secondary: {
-          DEFAULT: "hsl(var(--secondary))",
-          foreground: "hsl(var(--secondary-foreground))",
-        },
-        destructive: {
-          DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
-          foreground: "hsl(var(--destructive-foreground) / <alpha-value>)",
-        },
-        muted: {
-          DEFAULT: "hsl(var(--muted))",
-          foreground: "hsl(var(--muted-foreground))",
-        },
-        accent: {
-          DEFAULT: "hsl(var(--accent))",
-          foreground: "hsl(var(--accent-foreground))",
-        },
-        popover: {
-          DEFAULT: "hsl(var(--popover))",
-          foreground: "hsl(var(--popover-foreground))",
-        },
-        card: {
-          DEFAULT: "hsl(var(--card))",
-          foreground: "hsl(var(--card-foreground))",
-        },
-      },
-      borderRadius: {
-        xl: `calc(var(--radius) + 4px)`,
-        lg: `var(--radius)`,
-        md: `calc(var(--radius) - 2px)`,
-        sm: "calc(var(--radius) - 4px)",
-      },
-      fontFamily: {
-        sans: ["var(--font-sans)", ...fontFamily.sans],
-      },
-      keyframes: {
-        "accordion-down": {
-          from: { height: "0" },
-          to: { height: "var(--radix-accordion-content-height)" },
-        },
-        "accordion-up": {
-          from: { height: "var(--radix-accordion-content-height)" },
-          to: { height: "0" },
-        },
-      },
-      animation: {
-        "accordion-down": "accordion-down 0.2s ease-out",
-        "accordion-up": "accordion-up 0.2s ease-out",
-      },
-    },
-  },
-  plugins: [],
-};
-export default config;
diff --git a/templates/types/simple/nextjs/tsconfig.json b/templates/types/simple/nextjs/tsconfig.json
deleted file mode 100644
index e779aa667e9e83943147b44d06fa930e9175a2b7..0000000000000000000000000000000000000000
--- a/templates/types/simple/nextjs/tsconfig.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "es5",
-    "lib": [
-      "dom",
-      "dom.iterable",
-      "esnext"
-    ],
-    "allowJs": true,
-    "skipLibCheck": true,
-    "strict": true,
-    "noEmit": true,
-    "esModuleInterop": true,
-    "module": "esnext",
-    "moduleResolution": "bundler",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "jsx": "preserve",
-    "incremental": true,
-    "plugins": [
-      {
-        "name": "next"
-      }
-    ],
-    "paths": {
-      "@/*": [
-        "./*"
-      ]
-    },
-    "forceConsistentCasingInFileNames": true,
-  },
-  "include": [
-    "next-env.d.ts",
-    "**/*.ts",
-    "**/*.tsx",
-    ".next/types/**/*.ts"
-  ],
-  "exclude": [
-    "node_modules"
-  ]
-}
\ No newline at end of file
diff --git a/templates/types/streaming/nextjs/app/api/chat/route.ts b/templates/types/streaming/nextjs/app/api/chat/route.ts
index 989a5fec484fae3b34060ed20b4c1d5f1e42773f..eb3ddb0d49ef5de1b88fe1649d6b3c4e90b2f261 100644
--- a/templates/types/streaming/nextjs/app/api/chat/route.ts
+++ b/templates/types/streaming/nextjs/app/api/chat/route.ts
@@ -1,5 +1,6 @@
+import { MODEL } from "@/constants";
 import { Message, StreamingTextResponse } from "ai";
-import { OpenAI } from "llamaindex";
+import { MessageContent, OpenAI } from "llamaindex";
 import { NextRequest, NextResponse } from "next/server";
 import { createChatEngine } from "./engine";
 import { LlamaIndexStream } from "./llamaindex-stream";
@@ -7,10 +8,29 @@ import { LlamaIndexStream } from "./llamaindex-stream";
 export const runtime = "nodejs";
 export const dynamic = "force-dynamic";
 
+const getLastMessageContent = (
+  textMessage: string,
+  imageUrl: string | undefined,
+): MessageContent => {
+  if (!imageUrl) return textMessage;
+  return [
+    {
+      type: "text",
+      text: textMessage,
+    },
+    {
+      type: "image_url",
+      image_url: {
+        url: imageUrl,
+      },
+    },
+  ];
+};
+
 export async function POST(request: NextRequest) {
   try {
     const body = await request.json();
-    const { messages }: { messages: Message[] } = body;
+    const { messages, data }: { messages: Message[]; data: any } = body;
     const lastMessage = messages.pop();
     if (!messages || !lastMessage || lastMessage.role !== "user") {
       return NextResponse.json(
@@ -23,12 +43,22 @@ export async function POST(request: NextRequest) {
     }
 
     const llm = new OpenAI({
-      model: "gpt-3.5-turbo",
+      model: MODEL,
+      maxTokens: 4096,
     });
 
     const chatEngine = await createChatEngine(llm);
 
-    const response = await chatEngine.chat(lastMessage.content, messages, true);
+    const lastMessageContent = getLastMessageContent(
+      lastMessage.content,
+      data?.imageUrl,
+    );
+
+    const response = await chatEngine.chat(
+      lastMessageContent as MessageContent,
+      messages,
+      true,
+    );
 
     // Transform the response into a readable stream
     const stream = LlamaIndexStream(response);
diff --git a/templates/types/streaming/nextjs/app/components/chat-section.tsx b/templates/types/streaming/nextjs/app/components/chat-section.tsx
index 04098fcdf41a4e686459f0ce0d6f3ca311895a9e..791b223f40eb4fe716369efdb4d712dfa415fd8c 100644
--- a/templates/types/streaming/nextjs/app/components/chat-section.tsx
+++ b/templates/types/streaming/nextjs/app/components/chat-section.tsx
@@ -1,5 +1,6 @@
 "use client";
 
+import { MODEL } from "@/constants";
 import { useChat } from "ai/react";
 import { ChatInput, ChatMessages } from "./ui/chat";
 
@@ -27,6 +28,7 @@ export default function ChatSection() {
         handleSubmit={handleSubmit}
         handleInputChange={handleInputChange}
         isLoading={isLoading}
+        multiModal={MODEL === "gpt-4-vision-preview"}
       />
     </div>
   );
diff --git a/templates/types/streaming/nextjs/app/components/ui/chat/chat-input.tsx b/templates/types/streaming/nextjs/app/components/ui/chat/chat-input.tsx
index 3eb979b02735943f3f11290c78b84f0e37709438..7c3e87280b03ed571e8fc081a38c15a8d36df1ab 100644
--- a/templates/types/streaming/nextjs/app/components/ui/chat/chat-input.tsx
+++ b/templates/types/streaming/nextjs/app/components/ui/chat/chat-input.tsx
@@ -12,6 +12,7 @@ export interface ChatInputProps {
   /** Form submission handler to automatically reset input and append a user message  */
   handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
   isLoading: boolean;
+  multiModal?: boolean;
 }
 
 export default function ChatInput(props: ChatInputProps) {
diff --git a/templates/types/streaming/nextjs/constants.ts b/templates/types/streaming/nextjs/constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0959a5f6f4f9301f2559cf5b04c36de0ef3afe4a
--- /dev/null
+++ b/templates/types/streaming/nextjs/constants.ts
@@ -0,0 +1 @@
+export const MODEL = "gpt-4-vision-preview";
diff --git a/templates/types/streaming/nextjs/package.json b/templates/types/streaming/nextjs/package.json
index fbac43957dfce816506d1db7c4431352109ca61d..ea58702ea4375ab11d5a717ceef261f876f237bf 100644
--- a/templates/types/streaming/nextjs/package.json
+++ b/templates/types/streaming/nextjs/package.json
@@ -8,7 +8,7 @@
     "lint": "next lint"
   },
   "dependencies": {
-    "ai": "^2.2.5",
+    "ai": "^2.2.25",
     "llamaindex": "0.0.31",
     "dotenv": "^16.3.1",
     "next": "^13",
@@ -26,4 +26,4 @@
     "tailwindcss": "^3.3",
     "typescript": "^5"
   }
-}
+}
\ No newline at end of file