Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| import type { BackendModel } from "./server/models"; | |
| import type { Message } from "./types/Message"; | |
| import { format } from "date-fns"; | |
| import type { WebSearch } from "./types/WebSearch"; | |
| import { downloadFile } from "./server/files/downloadFile"; | |
| import type { Conversation } from "./types/Conversation"; | |
| interface buildPromptOptions { | |
| messages: Pick<Message, "from" | "content" | "files">[]; | |
| id?: Conversation["_id"]; | |
| model: BackendModel; | |
| locals?: App.Locals; | |
| webSearch?: WebSearch; | |
| preprompt?: string; | |
| files?: File[]; | |
| continue?: boolean; | |
| } | |
| export async function buildPrompt({ | |
| messages, | |
| model, | |
| webSearch, | |
| preprompt, | |
| id, | |
| }: buildPromptOptions): Promise<string> { | |
| let modifiedMessages = [...messages]; | |
| if (webSearch && webSearch.context) { | |
| // find index of the last user message | |
| const lastUsrMsgIndex = modifiedMessages.map((el) => el.from).lastIndexOf("user"); | |
| // combine all the other previous questions into one string | |
| const previousUserMessages = modifiedMessages.filter((el) => el.from === "user").slice(0, -1); | |
| const previousQuestions = | |
| previousUserMessages.length > 0 | |
| ? `Previous questions: \n${previousUserMessages | |
| .map(({ content }) => `- ${content}`) | |
| .join("\n")}` | |
| : ""; | |
| const currentDate = format(new Date(), "MMMM d, yyyy"); | |
| // update the last user message directly (that way if the last message is an assistant partial answer, we keep the beginning of that answer) | |
| modifiedMessages[lastUsrMsgIndex] = { | |
| from: "user", | |
| content: `I searched the web using the query: ${webSearch.searchQuery}. Today is ${currentDate} and here are the results: | |
| ===================== | |
| ${webSearch.context} | |
| ===================== | |
| ${previousQuestions} | |
| Answer the question: ${messages[lastUsrMsgIndex].content}`, | |
| }; | |
| } | |
| // section to handle potential files input | |
| if (model.multimodal) { | |
| modifiedMessages = await Promise.all( | |
| modifiedMessages.map(async (el) => { | |
| let content = el.content; | |
| if (el.from === "user") { | |
| if (el?.files && el.files.length > 0 && id) { | |
| const markdowns = await Promise.all( | |
| el.files.map(async (hash) => { | |
| try { | |
| const { content: image, mime } = await downloadFile(hash, id); | |
| const b64 = image.toString("base64"); | |
| return `})`; | |
| } catch (e) { | |
| console.error(e); | |
| } | |
| }) | |
| ); | |
| content += markdowns.join("\n "); | |
| } else { | |
| // if no image, append an empty white image | |
| content += | |
| "\n"; | |
| } | |
| } | |
| return { ...el, content }; | |
| }) | |
| ); | |
| } | |
| return ( | |
| model | |
| .chatPromptRender({ messages: modifiedMessages, preprompt }) | |
| // Not super precise, but it's truncated in the model's backend anyway | |
| .split(" ") | |
| .slice(-(model.parameters?.truncate ?? 0)) | |
| .join(" ") | |
| ); | |
| } | |