deep-foundation / deep-packages

This is repository for packages that are published only in NPM.
https://github.com/orgs/deep-foundation/projects/12
The Unlicense
0 stars 2 forks source link

customizable messages splitters (published to GitHub Pages) #43

Open Konard opened 9 months ago

Konard commented 9 months ago

We should make a deep package, that allows publishing client handlers directly to GitHub Pages.

For example, we can make specialized messages or file splitter for Discord, to make beautiful messages that contain the entire code file.

It should be in design of Discord. It should allow choosing is Discord Nitro is available. It should make good markdown splitting based on lines. So no line is ever split.

Example of how splitting might work

Original code/file

async ({ data: { newLink: replyLink, triggeredByLinkId }, deep, require }) => {
  const startTime = Date.now();
  const PACKAGE_NAME = `@deep-foundation/chatgpt`;
  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', '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', 'System');
  const tokensTypeLinkId = await deep.id("@deep-foundation/tokens", "Tokens")
  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 {
    data: [userLinkedModel],
  } = await deep.select({
    type_id: modelTypeLinkId,
    in: {
      type_id: usesModelTypeLinkId,
      from_id: triggeredByLinkId,
    },
  }, {
    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
    }
  `
  });

  let MAX_TOKENS;
  if (userLinkedModel?.usesModelTypeLinkId[0] && !userLinkedModel?.tokens?.[0]?.value?.value) {
    throw new Error("Token limit for the model is not specified.");
  } else if (userLinkedModel?.usesModelTypeLinkId[0] && userLinkedModel?.tokens?.[0]?.value?.value) {
    MAX_TOKENS = userLinkedModel.tokens[0].value.value;
  }

  if (!linkedModel && !userLinkedModel) {
    model = 'gpt-3.5-turbo';
    MAX_TOKENS = '4096'
  } 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];

    if (message.role === 'system' || totalTokens + message.tokens <= tokenLimit) {
      messagesToSendToOpenAI.unshift({ role: message.role, content: message.content });
      totalTokens += message.tokens;
    } else {
      break;
    }
  }

  const response = await openai.createChatCompletion({
    model: model,
    messages: [
      ...messagesToSendToOpenAI,
    ],
  });

  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: response.data.choices[0].message.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,
        },
      ],
    });
    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
  };
};

Split messages

async ({ data: { newLink: replyLink, triggeredByLinkId }, deep, require }) => {
  const startTime = Date.now();
  const PACKAGE_NAME = `@deep-foundation/chatgpt`;
  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', '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', 'System');
  const tokensTypeLinkId = await deep.id("@deep-foundation/tokens", "Tokens")
  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 {
    data: [userLinkedModel],
  } = await deep.select({
    type_id: modelTypeLinkId,
    in: {
      type_id: usesModelTypeLinkId,
      from_id: triggeredByLinkId,
    },
  }, {
    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
    }
  `
  });
  let MAX_TOKENS;
  if (userLinkedModel?.usesModelTypeLinkId[0] && !userLinkedModel?.tokens?.[0]?.value?.value) {
    throw new Error("Token limit for the model is not specified.");
  } else if (userLinkedModel?.usesModelTypeLinkId[0] && userLinkedModel?.tokens?.[0]?.value?.value) {
    MAX_TOKENS = userLinkedModel.tokens[0].value.value;
  }

  if (!linkedModel && !userLinkedModel) {
    model = 'gpt-3.5-turbo';
    MAX_TOKENS = '4096'
  } 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];

    if (message.role === 'system' || totalTokens + message.tokens <= tokenLimit) {
      messagesToSendToOpenAI.unshift({ role: message.role, content: message.content });
      totalTokens += message.tokens;
    } else {
      break;
    }
  }

  const response = await openai.createChatCompletion({
    model: model,
    messages: [
      ...messagesToSendToOpenAI,
    ],
  });
  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: response.data.choices[0].message.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,
        },
      ],
    });
    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
  };
};

All these messages are no more than 4000 characters.