Skip to content

Instantly share code, notes, and snippets.

@ivansglazunov
Last active June 29, 2024 15:02
Show Gist options
  • Save ivansglazunov/3ac187de0bb09449da8207136e1d9843 to your computer and use it in GitHub Desktop.
Save ivansglazunov/3ac187de0bb09449da8207136e1d9843 to your computer and use it in GitHub Desktop.
async ({ data: { newLink: replyLink, triggeredByLinkId }, deep, require }) => {
console.log({triggeredByLinkId})
const startTime = Date.now();
const PACKAGE_NAME = `@deep-foundation/chatgpt-azure`;
const axios = require('axios');
const { Configuration, OpenAIApi } = require('openai');
const chatGPTTypeLinkId = await deep.id(PACKAGE_NAME, 'ChatGPT');
const conversationTypeLinkId = await deep.id(PACKAGE_NAME, 'Conversation');
const apiKeyTypeLinkId = await deep.id('@deep-foundation/openai', 'ApiKey');
const usesApiKeyTypeLinkId = await deep.id('@deep-foundation/openai', 'UsesApiKey');
const modelTypeLinkId = await deep.id('@deep-foundation/openai', 'Model');
const usesModelTypeLinkId = await deep.id('@deep-foundation/openai', 'UsesModel');
const messageTypeLinkId = await deep.id('@deep-foundation/messaging', 'Message');
const replyTypeLinkId = await deep.id('@deep-foundation/chatgpt-azure', 'Reply');
const authorTypeLinkId = await deep.id('@deep-foundation/messaging', 'Author');
const containTypeLinkId = await deep.id('@deep-foundation/core', 'Contain');
const messagingTreeId = await deep.id('@deep-foundation/messaging', 'messagingTree');
const systemTypeLinkId = await deep.id('@deep-foundation/chatgpt-azure', 'System');
const tokensTypeLinkId = await deep.id("@deep-foundation/tokens", "Tokens")
const providedByTypeLinkId = await deep.id("@deep-foundation/chatgpt-azure", "ProvidedBy")
const reservedIds = await deep.reserve(1);
const chatGPTMessageLinkId = reservedIds.pop();
let systemMessageId;
let model;
let systemMessage;
await deep.await(replyLink.from_id)
const { data: [messageLink] } = await deep.select({
id: replyLink.from_id,
_not: {
out: {
to_id: chatGPTTypeLinkId,
type_id: authorTypeLinkId,
},
},
});
if (!messageLink) {
return 'No need to react to message of this reply.';
}
if (!messageLink.value?.value) {
throw new Error(`Message ##${messageLink.id} must have a value`);
}
const message = messageLink.value.value;
const apiKeyLink = await getTokenLink();
const apiKey = apiKeyLink.value.value;
const configuration = new Configuration({
apiKey: apiKey,
});
const openai = new OpenAIApi(configuration);
const { data: conversationLink } = await deep.select({
tree_id: { _eq: messagingTreeId },
parent: { type_id: { _in: [conversationTypeLinkId, messageTypeLinkId] } },
link: { id: { _eq: replyLink.from_id } },
}, {
table: 'tree',
variables: { order_by: { depth: "asc" } },
returning: `
id
depth
root_id
parent_id
link_id
parent {
id
from_id
type_id
to_id
value
author: out (where: { type_id: { _eq: ${authorTypeLinkId}} }) {
id
from_id
type_id
to_id
}
tokens: out (where: { type_id: { _eq: ${tokensTypeLinkId}} }) {
id
from_id
type_id
to_id
value
}
}`
})
if (!conversationLink) {
throw new Error('A conversationLink link is not found');
}
const currentConversation = conversationLink.find(
(link) => link.parent.type_id === conversationTypeLinkId
);
conversationLink.forEach((link) => {
if (link.parent.author && link.parent.author.length > 0) {
link.parent.author = link.parent.author[0];
}
});
const {
data: [linkedModel],
} = await deep.select({
type_id: modelTypeLinkId,
in: {
type_id: usesModelTypeLinkId,
from_id: currentConversation.parent.id,
},
});
const usedModelSelectData = {
type_id: modelTypeLinkId,
in: {
type_id: usesModelTypeLinkId,
from_id: triggeredByLinkId,
},
}
const {
data: [userLinkedModel],
} = await deep.select(usedModelSelectData, {
returning: `
id
value
in(where: { type_id: { _eq: ${usesModelTypeLinkId} } }) {
id
type_id
from_id
to_id
value
}
tokens: out(where: { type_id: { _eq: ${tokensTypeLinkId} } }) {
id
from_id
to_id
value
}
endpointLink: out(where: { type_id: { _eq: ${providedByTypeLinkId} } }) {
id
from_id
to_id
endpoint: to {
id
value
}
}
`
});
if(!userLinkedModel) {
throw new Error(`Failed to find used model. Select data: ${JSON.stringify(usedModelSelectData, null, 2)}`)
}
let MAX_TOKENS
console.log({userLinkedModel})
if (!userLinkedModel.tokens?.[0]?.value?.value) {
throw new Error("Token limit for the model is not specified.");
} else if (userLinkedModel.tokens?.[0]?.value?.value) {
MAX_TOKENS = userLinkedModel.tokens[0].value.value;
}
if (!userLinkedModel.endpointLink?.[0]?.endpoint?.value?.value) {
throw new Error("Endpoint for the model is not specified.");
}
const API_ENDPOINT = userLinkedModel.endpointLink[0].endpoint.value?.value;
if (!linkedModel && !userLinkedModel) {
throw new Error("Before using azure-GPT, create a model, tokens, and an endpoint links.");
} else if (
(linkedModel &&
linkedModel.value?.value &&
userLinkedModel &&
userLinkedModel.value?.value) ||
(linkedModel && linkedModel.value?.value)
) {
model = linkedModel.value.value;
} else {
if (!userLinkedModel) {
throw new Error(`A link with type ##${userLinkedModel} is not found`);
}
if (!userLinkedModel.value?.value) {
throw new Error(`Linked model with user ##${userLinkedModel.id} must have a value`);
} else {
model = userLinkedModel.value.value;
}
}
const messageLinks = conversationLink
.map(item => item.parent)
.filter(link => link && link.type_id === messageTypeLinkId);
let allMessages = await getMessages({ messageLinks });
const messagesToSend = [...allMessages];
const { data: userLinkedSystemMessageLinks } = await deep.select({
type_id: systemTypeLinkId,
to_id: triggeredByLinkId,
}, { returning: `id message: from{ id value} conversation:to{id}` });
const { data: conversationLinkedSystemMessageLink } = await deep.select({
type_id: systemTypeLinkId,
to_id: currentConversation.parent.id,
}, { returning: `id message: from{ id value} conversation:to{id}` });
if (conversationLinkedSystemMessageLink && conversationLinkedSystemMessageLink.length > 0) {
const systemMessageLink = conversationLinkedSystemMessageLink[0];
if (!systemMessageLink.message?.value?.value) {
throw new Error(`System message with link to conversation ##${systemMessageLink.id} must have a value`);
} else {
systemMessage = systemMessageLink.message.value.value;
systemMessageId = systemMessageLink.message;
await deep.await(systemMessageId.id)
}
} else if (userLinkedSystemMessageLinks && userLinkedSystemMessageLinks.length > 0) {
if (userLinkedSystemMessageLinks.length > 1) {
throw new Error("Multiple system messages linked to the user are found");
}
const userLinkedSystemMessageLink = userLinkedSystemMessageLinks[0];
if (!userLinkedSystemMessageLink.message?.value?.value) {
throw new Error(`System message with link to user ##${userLinkedSystemMessageLink.id} must have a value`);
} else {
systemMessage = userLinkedSystemMessageLink.message.value.value;
systemMessageId = userLinkedSystemMessageLink.message;
await deep.await(systemMessageId.id)
}
}
if (systemMessage) {
const { data: tokensLinkedToSystemMessage } = await deep.select({
type_id: tokensTypeLinkId,
from_id: systemMessageId.id,
to_id: systemMessageId.id,
});
if (!tokensLinkedToSystemMessage[0]?.value?.value) {
throw new Error(`System message does not contain tokens`);
} else if (tokensLinkedToSystemMessage[0]?.value?.value) {
let tokenCount = tokensLinkedToSystemMessage[0].value?.value;
messagesToSend.unshift({
role: "system",
content: systemMessage,
tokens: tokenCount,
});
}
}
const tokenLimit = MAX_TOKENS * 7 / 8;
let totalTokens = 0;
let messagesToSendToOpenAI = [];
for (let i = messagesToSend.length - 1; i >= 0; i--) {
const message = messagesToSend[i];
console.log({message})
if (message.role === 'system' || totalTokens + message.tokens <= tokenLimit) {
messagesToSendToOpenAI.unshift({ role: message.role, content: message.content });
totalTokens += message.tokens;
} else {
break;
}
}
let response;
try {
response = await axios.post(API_ENDPOINT, {
messages: [...messagesToSendToOpenAI]
}, {
headers: {
'Content-Type': 'application/json',
'api-key': apiKey
}
});
} catch (error) {
console.error('Error making API call:', error.response ? error.response.data : error.message);
}
const content = response.data.choices[0]?.message?.content;
await deep.serial({
operations: [
{
table: 'links',
type: 'insert',
objects: {
id: chatGPTMessageLinkId,
type_id: messageTypeLinkId,
out: {
data: [
{
type_id: authorTypeLinkId,
to_id: chatGPTTypeLinkId,
},
],
},
},
},
{
table: 'strings',
type: 'insert',
objects: {
link_id: chatGPTMessageLinkId,
value: content
}
},
{
table: 'links',
type: 'insert',
objects: {
type_id: replyTypeLinkId,
from_id: chatGPTMessageLinkId,
to_id: replyLink.from_id,
},
},
],
});
async function getMessages({ messageLinks }) {
return Promise.all(
messageLinks.map(async (link) => {
const tokens = link.tokens?.length > 0 ? link.tokens[0].value.value : undefined;
return {
role: await getMessageRole({ messageLink: link }),
content: link.value.value,
tokens: tokens,
}
})
);
}
async function getMessageRole({ messageLink }) {
const authorLink = messageLink.author;
if (!authorLink) {
throw new Error(`Author link not found for message ##${messageLink.id}`);
}
return authorLink.to_id === chatGPTTypeLinkId ? 'assistant' : 'user';
}
async function getTokenLink() {
let resultTokenLink;
const { data } = await deep.select({
_or: [
{
type_id: apiKeyTypeLinkId,
in: {
type_id: containTypeLinkId,
from_id: triggeredByLinkId,
},
},
{
from_id: triggeredByLinkId,
type_id: usesApiKeyTypeLinkId,
},
{
type_id: apiKeyTypeLinkId,
in: {
from_id: triggeredByLinkId,
type_id: usesApiKeyTypeLinkId,
},
},
],
})
console.log("FREEPHOENIX888.getTokenLink", {data})
if (data.length === 0) {
throw new Error(`ApiKey ##${apiKeyTypeLinkId} is not found`);
}
const usesLinks = data.filter(
(link) => link.type_id === usesApiKeyTypeLinkId
);
if (usesLinks.length > 1) {
throw new Error(
`More than 1 links of type ##${usesApiKeyTypeLinkId} are found`
);
}
const usesLink = data.find(
(link) => link.type_id === usesApiKeyTypeLinkId
);
if (usesLink) {
const tokenLink = data.find((link) => link.id === usesLink.to_id);
if (!tokenLink) {
throw new Error(`ApiKey ##${apiKeyTypeLinkId} is not found`);
} else {
resultTokenLink = tokenLink;
}
} else {
const tokenLink = data.filter(
(link) => link.type_id === apiKeyTypeLinkId
);
if (tokenLink.length > 1) {
throw new Error(
`For 2 or more ApiKey ##${apiKeyTypeLinkId} links you must activate it with usesOpenAiApiKey link`
);
} else {
const tokenLink = data.find(
(link) => link.type_id === apiKeyTypeLinkId
);
if (!tokenLink) {
throw new Error(`ApiKey ##${apiKeyTypeLinkId} is not found`);
}
resultTokenLink = tokenLink;
}
}
if (!resultTokenLink.value?.value) {
throw new Error(`ApiKey ##${apiKeyTypeLinkId} has no value`);
}
return resultTokenLink;
}
const endTime = Date.now();
const duration = (endTime - startTime) / 1000;
return {
request: {
model: model,
messages: [
...messagesToSendToOpenAI
],
},
response: response.data,
duration: duration,
totalTokens: totalTokens
};
};
async ({ data: { newLink: reply, triggeredByLinkId }, deep, require }) => {
const ml = deep.minilinks;
const startTime = Date.now();
const axios = require('axios');
const ChatGPT = await deep.id(deep.linkid, 'ChatGPT');
const Conversation = await deep.id(deep.linkid, 'Conversation');
const ApiKey = await deep.id('@deep-foundation/openai', 'ApiKey');
const UsesApiKey = await deep.id('@deep-foundation/openai', 'UsesApiKey');
const Model = await deep.id('@deep-foundation/openai', 'Model');
const UsesModel = await deep.id('@deep-foundation/openai', 'UsesModel');
const Message = await deep.id('@deep-foundation/messaging', 'Message');
const Reply = await deep.id('@deep-foundation/chatgpt-azure', 'Reply');
const Author = await deep.id('@deep-foundation/messaging', 'Author');
const messagingTree = await deep.id('@deep-foundation/messaging', 'messagingTree');
const System = await deep.id('@deep-foundation/chatgpt-azure', 'System');
const Tokens = await deep.id("@deep-foundation/tokens", "Tokens")
const ProvidedBy = await deep.id("@deep-foundation/chatgpt-azure", "ProvidedBy")
await deep.await(reply.from_id);
const { data: [message] } = await deep.select({
id: reply.from_id,
_not: { out: { to_id: ChatGPT, type_id: Author } },
});
if (!message) return 'No need to react to message of this reply.';
if (!message.value?.value) throw new Error(`Message ##${message.id} must have a value`);
ml.apply(await deep.select({
type_id: ApiKey,
in: { from_id: triggeredByLinkId, type_id: UsesApiKey },
return: {
uses: { relation: 'in', type_id: UsesApiKey },
},
}), 'apikey');
const apikeys = ml.select({ type_id: ApiKey });
const useses = ml.select({ tyoe_id: UsesApiKey, to: { type_id: ApiKey } });
if (!apikeys.length) throw new Error(`ApiKey not founded`);
if (useses.length > 1) throw new Error(`More than 1 links of type UsesApiKey are found`);
if (!apikeys[0]?.value?.value) throw new Error(`ApiKey has no value`);
const { data: [conversation] } = await deep.select({
type_id: Conversation,
down: { tree_id: messagingTree, link_id: reply.id }
});
if (!conversation) return 'Conversation upper not founded.';
const messagesByReply = await deep.select({
type_id: Message,
down: { tree_id: messagingTree, link_id: reply.from_id },
order_by: { id: 'desc' },
return: {
authors: { relation: 'out', type_id: Author },
tokens: { relation: 'out', type_id: Tokens },
}
});
ml.apply(messagesByReply, 'messagesByReply');
const messagesById = await deep.select({
id: { _nin: messagesByReply.data.map(l => l.id) },
type_id: Message,
up: { tree_id: messagingTree, parent_id: conversation.id },
order_by: { id: 'desc' },
return: {
authors: { relation: 'out', type_id: Author },
tokens: { relation: 'out', type_id: Tokens },
}
});
ml.apply(messagesById, 'messagesById');
const messagesToSend = [...messagesByReply.data, messagesById.data];
const models = await deep.select({
type_id: Model,
in: { type_id: UsesModel, from_id: { _in: [conversation.id, triggeredByLinkId] } },
return: {
usesModel: { relation: 'in', type_id: UsesModel },
tokens: { relation: 'out', type_id: Tokens },
providedBy: {
relation: 'out', type_id: ProvidedBy,
return: {
endpoint: { relation: 'to' }
},
},
},
});
ml.apply(models, 'models');
const [userLinkedModel] = ml.select({ type_id: Model, in: { type_id: UsesModel, from_id: triggeredByLinkId } });
if(!userLinkedModel) throw new Error(`UsersModel from triggeredByLinkId to Model not founded.`);
const [userLinkedModelTokens] = ml.select({ type_id: Tokens, from_id: userLinkedModel?.id });
const [linkedModel] = ml.select({ type_id: Model, in: { type_id: UsesModel, from_id: conversation.id } });
const MAX_TOKENS = userLinkedModelTokens.value.value;
if (!MAX_TOKENS) throw new Error("MAX_TOKENS Tokens .value from model not founded.");
const API_ENDPOINT = ml.select({ in: { type_id: ProvidedBy } })[0]?.value?.value;
if (!API_ENDPOINT) throw new Error("API_ENDPOINT Endpoint instance.value nout founded.");
const model = linkedModel.value.value || userLinkedModel.value.value;
if(!model) throw new Error(`UsersModel from conversation.id to Model not founded.`);
let preparedMessages = messagesToSend.map((link) => {
const tokens = ml.select({ type_id: Tokens, from_id: link.id })[0]?.value?.value;
return {
role: ml.select({ type_id: Author, from_id: link.id })[0]?.to_id === ChatGPT ? 'assistant' : 'user',
content: link.value.value,
tokens: ml.select({ type_id: Tokens, from_id: link.id })[0]?.value?.value,
}
});
ml.apply(await deep.select({
type_id: System, to_id: { _in: [triggeredByLinkId, conversation.id] },
return: {
message: { relation: 'from' },
conversation: { relation: 'to' },
tokens: { relation: 'in', type_id: Tokens },
},
}), 'systems');
const conversationSystem = ml.select({ type_id: System, to_id: conversation.id })?.[0];
if (!conversationSystem?.value?.value) throw new Error(`System .value to conversation not defined`);
const userSystems = ml.select({ type_id: System, to_id: triggeredByLinkId });
if (userSystems.length > 1) throw new Error("Multiple system messages linked to the user are found");
const userSystem = userSystems[0];
const systemMessage = conversationSystem.from || userSystem.from;
if (systemMessage) {
if (!systemMessage?.value?.value) throw new Error(`System.from Message.value not founded`);
await deep.await(systemMessage.id);
const tokens = ml.select({ type_id: Tokens, from_id: systemMessage.id, to_id: systemMessage.id })?.[0];
if (!tokens?.value?.value) throw new Error(`System message does not contain tokens`);
preparedMessages.unshift({ role: 'system', content: systemMessage?.value?.value, tokens: tokens?.value?.value });
}
const tokenLimit = MAX_TOKENS * 7 / 8;
let totalTokens = 0;
let messages = [];
for (let i = preparedMessages.length - 1; i >= 0; i--) {
const message = preparedMessages[i];
if (message.role === 'system' || totalTokens + message.tokens <= tokenLimit) {
messages.unshift({ role: message.role, content: message.content });
totalTokens += message.tokens;
} else {
break;
}
}
let response;
try {
response = await axios.post(API_ENDPOINT, { messages }, {
headers: { 'Content-Type': 'application/json', 'api-key': apikeys[0]?.value?.value },
});
} catch (error) {
console.error('Error making API call:', error.response ? error.response.data : error.message);
}
const content = response.data.choices[0]?.message?.content;
await deep.insert({
type_id: Message,
string: { data: { value: content } },
out: { data: [
{ type_id: Author, to_id: ChatGPT },
{ type_id: Reply, to_id: reply.from_id },
] },
});
const endTime = Date.now();
const duration = (endTime - startTime) / 1000;
ml.remove(Object.keys(ml.byId));
return {
request: { model, messages },
response: response.data,
duration, totalTokens,
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment