-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: rework guidelines * refactor: rename config file format * feat: hitstory context and gpt extractor * fix: enforce answers from context * feat: static context window * feat: enforce token limit in chat API call
- Loading branch information
1 parent
09bcf47
commit 6a896d2
Showing
14 changed files
with
270 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import ERROR_MESSAGES from "./error-config"; | ||
|
||
export const COMPLETION_URL = "https://api.openai.com/v1/chat/completions" | ||
|
||
export const OPENAI_EXTRACTOR_MODEL = "gpt-3.5-turbo" | ||
|
||
export const extractorSystemPrompt = ` | ||
You are a helpful assistant. You are given a list of user questions, the questions serve as context. Giving priority to ONLY the LAST QUESTION and the context from any relevant previous questions, what are the most relevant keywords that can be used in a search engine to find an answer to the last question. Return the minimum amount of relevant keywords in a json object: {keywords: 'keyword1, keyword2, ...'} | ||
`; | ||
|
||
export const guidelines = { | ||
BASE_INSTRUCTION: | ||
"You are an AI assistant providing helpful answers. You are given the following extracted parts of a long document called CONTEXT BLOCK and a conversation. Provide a conversational detailed answer in the same writing style as based on the context provided. DO NOT include any external references or links in the answers.", | ||
NO_ANSWER: `If you are absolutely certain that the answer cannot be found in the CONTEXT BLOCK, just say this phrase '${ERROR_MESSAGES.NO_ANSWER_WITH_LINKS}' EXACTLY. DO NOT try to make up an answer that is not in the CONTEXT BLOCK.`, | ||
UNRELATED_QUESTION: `If the question is not related to the context, say this phrase EXACTLY '${ERROR_MESSAGES.NO_ANSWER}'`, | ||
LINKING: `DO NOT explicity mention the existence of the context provided, however, references can and should be made to the links provided in the context e.g '[0]'`, | ||
FOLLOW_UP_QUESTIONS: `In addition, generate four follow up questions related to the answer generated. Each question should be in this format -{QUESTION_INDEX_HERE}-{{QUESTION_HERE}} and each question should be seperated by a new line. DO NOT ADD AN INTRODUCTORY TEXT TO THE FOLLOW UP QUESTIONS.`, | ||
USED_SOURCES: `Lastly, list all sources relevant in generating the answer in a list in this format '__sources__: [LINK_INDICES_HERE]'` | ||
}; | ||
|
||
export const CONTEXT_WINDOW_MESSAGES = 6 | ||
|
||
export const TOKEN_UPPER_LIMIT = 7000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export const DOCUMENTS = { | ||
MAX_NUMBER_OF_DOCUMENTS: 6, | ||
MAX_LENGTH_PER_DOCUMENT: 2000, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { COMPLETION_URL, extractorSystemPrompt, OPENAI_EXTRACTOR_MODEL } from "@/config/chatAPI-config"; | ||
import { ChatHistory } from "@/types"; | ||
|
||
export const GPTKeywordExtractor = async (history: ChatHistory[]) => { | ||
try { | ||
const userQuestions = history | ||
.filter((message) => message.role === "user") | ||
.slice(-10); | ||
const messages = [ | ||
{ | ||
role: "system", | ||
content: extractorSystemPrompt, | ||
}, | ||
...userQuestions, | ||
]; | ||
|
||
const payload = { | ||
model: OPENAI_EXTRACTOR_MODEL, | ||
response_format: { "type": "json_object" }, | ||
messages, | ||
}; | ||
const response = await fetch(COMPLETION_URL, { | ||
headers: { | ||
"Content-Type": "application/json", | ||
Authorization: `Bearer ${process.env.OPENAI_API_KEY ?? ""}`, | ||
}, | ||
method: "POST", | ||
body: JSON.stringify(payload), | ||
}); | ||
const body = await response.json(); | ||
const keywords = JSON.parse(body.choices[0]?.message.content).keywords | ||
if (Array.isArray(keywords)) { | ||
return keywords.map((keyword: string) => keyword.trim()).join(" ") | ||
} | ||
if (typeof keywords !== "string") { | ||
throw new Error("Parsed response is not a string") | ||
} | ||
|
||
return keywords.replaceAll(",", "") | ||
} catch (err) { | ||
console.log(err) | ||
return undefined | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { Message } from "@/components/message/message"; | ||
import { separateLinksFromApiMessage } from "@/utils/links"; | ||
import { CONTEXT_WINDOW_MESSAGES, guidelines } from "@/config/chatAPI-config"; | ||
import { ChatHistory } from "@/types"; | ||
|
||
const buildSystemMessage = (question: string, context: string) => { | ||
const { | ||
BASE_INSTRUCTION, | ||
NO_ANSWER, | ||
UNRELATED_QUESTION, | ||
FOLLOW_UP_QUESTIONS, | ||
LINKING, | ||
} = guidelines; | ||
return `${BASE_INSTRUCTION}\n${NO_ANSWER}\n${UNRELATED_QUESTION}\n${context}\n${LINKING}\n${FOLLOW_UP_QUESTIONS}`; | ||
}; | ||
|
||
export const buildChatMessages = ({ | ||
question, | ||
context, | ||
oldContext, | ||
messages, | ||
}: { | ||
question: string; | ||
context: string; | ||
oldContext?: string; | ||
messages: ChatHistory[]; | ||
}) => { | ||
const systemMessage = buildSystemMessage(question, context); | ||
return [ | ||
{ | ||
role: "system", | ||
content: systemMessage, | ||
}, | ||
...messages | ||
] as ChatHistory[]; | ||
}; | ||
|
||
const formatMessageToChatHistory = (message: Message) => { | ||
try { | ||
let role, content; | ||
if (message.type === "errorMessage" || message.type === "apiStream") { | ||
return undefined; | ||
} | ||
switch (message.type) { | ||
case "apiMessage": { | ||
role = "assistant"; | ||
content = separateLinksFromApiMessage(message.message).messageBody; | ||
break; | ||
} | ||
case "authorMessage": { | ||
role = "system"; | ||
content = message.message; | ||
break; | ||
} | ||
case "userMessage": { | ||
role = "user"; | ||
content = message.message; | ||
break; | ||
} | ||
default: | ||
return undefined; | ||
} | ||
return { | ||
role, | ||
content, | ||
} as ChatHistory; | ||
} catch (err) { | ||
console.error(err); | ||
return undefined; | ||
} | ||
}; | ||
|
||
export const constructMessageHistory = (messages: Message[]) => { | ||
const list: ChatHistory[] = []; | ||
const messageWindow = messages.slice(-CONTEXT_WINDOW_MESSAGES) | ||
for (let index = 0; index < messageWindow.length; index++) { | ||
const message = messages[index]; | ||
const chat = formatMessageToChatHistory(message); | ||
if (chat) list.push(chat); | ||
} | ||
return list; | ||
}; |
Oops, something went wrong.