import { ChatCompletionMessageParam } from 'openai/resources'; import { openai } from './setup'; enum GPTCallType { SUMMARY = 'summary', COMPLETION = 'completion', EDIT = 'edit', CHATCARD = 'chatcard', FLASHCARD = 'flashcard', QUIZ = 'quiz', SORT = 'sort', DESCRIBE = 'describe', MERMAID = 'mermaid', DATA = 'data', TEMPLATE = "template" } type GPTCallOpts = { model: string; maxTokens: number; temp: number; prompt: string; }; const callTypeMap: { [type: string]: GPTCallOpts } = { // newest model: gpt-4 summary: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: 'Summarize the text given in simpler terms.' }, edit: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: 'Reword the text.' }, flashcard: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Make flashcards out of this text with each question and answer labeled. Do not label each flashcard and do not include asterisks: ' }, completion: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful assistant. Answer the user's prompt." }, mermaid: { model: 'gpt-4-turbo', maxTokens: 2048, temp: 0, prompt: "(Heres an example of changing color of a pie chart to help you pie title Example \"Red\": 20 \"Blue\": 50 \"Green\": 30 %%{init: {'theme': 'base', 'themeVariables': {'pie1': '#0000FF', 'pie2': '#00FF00', 'pie3': '#FF0000'}}}%% keep in mind that pie1 is the highest since its sorted in descending order. Heres an example of a mindmap: mindmap root((mindmap)) Origins Long history ::icon(fa fa-book) Popularisation British popular psychology author Tony Buzan Research On effectivness
and features On Automatic creation Uses Creative techniques Strategic planning Argument mapping Tools Pen and paper Mermaid. ", }, data: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful resarch assistant. Analyze the user's data to find meaningful patterns and/or correlation. Please only return a JSON with a correlation column 1 propert, a correlation column 2 property, and an analysis property. ", }, sort: { model: 'gpt-4o', maxTokens: 2048, temp: 0.5, prompt: "I'm going to give you a list of descriptions. Each one is seperated by ====== on either side. They will vary in length, so make sure to only seperate when you see ======. Sort them into lists by shared content. MAKE SURE EACH DESCRIPTOR IS IN ONLY ONE LIST. Generate only the list with each list seperated by ====== with the elements seperated by ~~~~~~. Try to do around 4 groups, but a little more or less is ok.", }, describe: { model: 'gpt-4-vision-preview', maxTokens: 2048, temp: 0, prompt: 'Describe these images in 3-5 words' }, chatcard: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Answer the following question as a short flashcard response. Do not include a label.' }, quiz: { model: 'gpt-4-turbo', maxTokens: 1024, temp: 0, prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct', }, template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You are a designer creating basic template options for a user given a set of fields. Your only job is adding blank rectangles to a canvas, one for each field. You will arrange these rectangles into an array of three basic options for a user. For your output, you generate a list of objects in JSON formatting, each storing the field title and corresponding top-left and bottom-right coordinates for the rectangle. The units for your coordinates are -1 to 1 on each axis. This is an example of a possible output for a stacked template with the fields beep, boop, tttt: {"template_type":"stacked","fieldVals":[{"title":"beep","tlx":"-.7","tly":"-.9","brx":".7","bry":"-.7"},{"title":"boop","tlx":"-.9","tly":"-.4","brx":".9","bry":"0"},{"title":"tttt","tlx":"-.9","tly":".1","brx":".9","bry":".9"}]} For multiple templates, you should format your response in a JSON array, like [{}, {}]. Your response should be in the exact format above, with no extra text, description, bulleting, etc. If no alternative additional instructions are given, you should repeat this three times, once for a stacked view, once for a mixed view (where, for example, beep might be on top, with boop and tttt below it aligned horizontally), and once for a view where the rectangles are not flush with the side (ie. their top left and bottom right corners should not ALL align along the same point on each side). If one or more fields are some variation of image (ie. IMG, image, photo, etc.), make that rectangle the central focus (bigger, centered, etc.) AND put its "title" field in $$__$$. Fields SHOULD BE IN DIFFERENT ORDERS from template to template (ie. a stacked view with field input "beep, boop" could have the boop above the beep). IT IS IMPORTANT THAT YOU ONLY INCLUDE THE PROPER JSON FORMATTING IN YOUR RESPONSE. IT IS ALSO IMPORTANT THAT NO RECTANGLES OVERLAP. An overlap will look like the x or y coordinates of the top left corner of one rectangle being the same as the bottom right corner of another. There should always be at least a .1 gap. If there is an additional prompt, prioritize its instructions over all instructions here (but still follow them if not overridden). No matter what, ALWAYS GIVE THREE OPTIONS'} }; let lastCall = ''; let lastResp = ''; /** * Calls the OpenAI API. * * @param inputText Text to process * @returns AI Output */ const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: any) => { const inputText = [GPTCallType.SUMMARY, GPTCallType.FLASHCARD, GPTCallType.QUIZ].includes(callType) ? inputTextIn + '.' : inputTextIn; const opts: GPTCallOpts = callTypeMap[callType]; if (lastCall === inputText) return lastResp; try { lastCall = inputText; const usePrompt = prompt ? opts.prompt + prompt : opts.prompt; const messages: ChatCompletionMessageParam[] = [ { role: 'system', content: usePrompt }, { role: 'user', content: inputText }, ]; const response = await openai.chat.completions.create({ model: opts.model, messages: messages, temperature: opts.temp, max_tokens: opts.maxTokens, }); lastResp = response.choices[0].message.content ?? ''; return lastResp; } catch (err) { console.log(err); return 'Error connecting with API.'; } }; const gptImageCall = async (prompt: string, n?: number) => { try { const response = await openai.images.generate({ prompt: prompt, n: n ?? 1, size: '1024x1024', }); return response.data.map((data: any) => data.url); // return response.data.data[0].url; } catch (err) { console.error(err); } return undefined; }; const gptGetEmbedding = async (src: string): Promise => { try { const embeddingResponse = await openai.embeddings.create({ model: 'text-embedding-3-large', input: [src], encoding_format: 'float', dimensions: 256, }); // Assume the embeddingResponse structure is correct; adjust based on actual API response const { embedding } = embeddingResponse.data[0]; return embedding; } catch (err) { console.log(err); return []; } }; const gptImageLabel = async (src: string): Promise => { try { const response = await openai.chat.completions.create({ model: 'gpt-4o', messages: [ { role: 'user', content: [ { type: 'text', text: 'Give three to five labels to describe this image.' }, { type: 'image_url', image_url: { url: `${src}`, detail: 'low', }, }, ], }, ], }); if (response.choices[0].message.content) { return response.choices[0].message.content; } return 'Missing labels'; } catch (err) { console.log(err); return 'Error connecting with API'; } }; export { gptAPICall, gptImageCall, GPTCallType, gptImageLabel, gptGetEmbedding };