Skip to content

Instantly share code, notes, and snippets.

@motorro
Created December 14, 2023 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save motorro/38b5e7142638ddac456286630f50b0f0 to your computer and use it in GitHub Desktop.
Save motorro/38b5e7142638ddac456286630f50b0f0 to your computer and use it in GitHub Desktop.
Open AI assistant chat
import OpenAI from "openai";
import {AssistantTools} from "./assistantTools";
import * as fs from "fs";
import {FileObject} from "openai/resources";
import {Threads} from "openai/resources/beta";
import ThreadCreateParams = Threads.ThreadCreateParams;
import Run = Threads.Run;
import {sleep} from "openai/core";
import PromptSync from "prompt-sync";
import console from "console";
import ThreadMessagesPage = Threads.ThreadMessagesPage;
export async function assistantConversation(params?: {
name?: string,
instructions?: string,
messages?: Array<ThreadCreateParams.Message>
files?: Array<string>
tools?: AssistantTools,
model?: string
}) {
const options = {
name: "Mr.Assistant",
instructions: "You are a helpful assistant.",
model: "gpt-3.5-turbo",
...params
}
console.log(`Building new Assistant: ${options.name}...`)
const openAi = new OpenAI();
const prompt = PromptSync({sigint: false});
let files: Array<FileObject> | undefined = undefined;
if (undefined !== options.files && options.files.length > 0) {
console.log("Uploading files...");
files = await Promise.all(
options.files.map(function (fileName): Promise<FileObject> {
return openAi.files.create({
file: fs.createReadStream(fileName),
purpose: "assistants"
});
})
);
}
console.log("Creating assistant...");
const assistant = await openAi.beta.assistants.create({
name: options.name,
instructions: options.instructions,
tools: options.tools?.tools,
file_ids: files?.map((f) => f.id),
model: options.model
});
console.log("Creating thread...");
const thread = await openAi.beta.threads.create(
{
messages: options.messages
}
);
let terminated = false;
let cursor: string | undefined = undefined;
while(!terminated) {
let run: Run = await openAi.beta.threads.runs.create(thread.id, {assistant_id: assistant.id});
do {
await sleep(1000);
run = await openAi.beta.threads.runs.retrieve(thread.id, run.id);
} while(isRunning(run));
const status = run.status;
switch (status) {
case "cancelled":
case "failed":
case "expired":
console.log(`Thread terminated with status: ${status}`);
terminated = true;
continue;
case "completed":
await getMessages();
let userMessage: string | null;
do {
userMessage = prompt("User: ");
if (null !== userMessage && "" == userMessage.trim()) {
console.log("Please enter a message to continue or 'quit' to stop");
}
} while (null !== userMessage && 0 === userMessage.trim().length);
if (null == userMessage || "quit" === userMessage.trim().toLowerCase()) {
terminated = true;
console.log("Terminated...")
continue;
}
await addUserMessage(userMessage);
break;
case "requires_action":
console.log("ACTIONSSSSSSSSSS");
break;
}
}
console.log("Deleting thread...");
await openAi.beta.threads.del(thread.id);
console.log("Deleting assistant...");
await openAi.beta.assistants.del(assistant.id);
console.log("Bye!");
/**
* Retrieves message pages one-by one
*/
async function getMessages(): Promise<void> {
const list: ThreadMessagesPage = await openAi.beta.threads.messages.list(
thread.id,
{after: cursor, order: "asc"}
);
for await (const page of list.iterPages()) {
page.getPaginatedItems().forEach((message) => {
cursor = message.id;
message.content.forEach((content) => {
switch (content.type) {
case "image_file":
console.log("Assistant: [IMAGE]");
break;
case "text":
console.log(`Assistant: ${content.text.value}`);
break;
}
});
});
}
}
/**
* Adds new user message to chat
* @param message Message to add
*/
async function addUserMessage(message: string): Promise<void> {
await openAi.beta.threads.messages.create(
thread.id,
{
role: "user",
content: message
}
);
}
}
/**
* Checks thread run status
* @param run Thread run status
*/
function isRunning(run: Run): boolean {
return ["queued", "in_progress", "cancelling"].indexOf(run.status) >= 0;
}
import {assistantConversation} from "./assistant";
async function main() {
await assistantConversation();
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment