All files / api/src/utils object.ts

42.39% Statements 39/92
100% Branches 13/13
50% Functions 2/4
42.39% Lines 39/92

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119      1x   1x                                                                                         1x                                           1x 5x 5x 5x 5x 1x 1x   5x   1x 2x 1x 1x   3x 3x 7x 7x 7x 7x   2x 2x 2x 2x 7x   5x 5x   7x 7x 3x 3x   3x       7x 7x 7x 7x 7x 3x  
import type {} from '@shared/types/api/request/body';
import type { ChatCompletionRequestBody } from '@shared/types/api/routes/chat-completions-api';
import type { CompletionRequestBody } from '@shared/types/api/routes/completions-api';
import { AIProvider } from '@shared/types/constants';
 
export const getStreamModeSplitPattern = (
  provider: string,
  aiProviderRequestURL: string,
): SplitPatternType => {
  let splitPattern: SplitPatternType = '\n\n';
 
  if (
    provider === AIProvider.ANTHROPIC &&
    aiProviderRequestURL.endsWith('/complete')
  ) {
    splitPattern = '\r\n\r\n';
  }
 
  if (provider === AIProvider.COHERE) {
    splitPattern = '\n';
  }
 
  if (provider === AIProvider.GOOGLE) {
    splitPattern = '\r\n';
  }
 
  // In Vertex Anthropic and LLama have \n\n as the pattern only Gemini has \r\n\r\n
  if (
    provider === AIProvider.GOOGLE_VERTEX_AI &&
    aiProviderRequestURL.includes('/publishers/google')
  ) {
    splitPattern = '\r\n\r\n';
  }
 
  if (provider === AIProvider.PERPLEXITY_AI) {
    splitPattern = '\r\n\r\n';
  }
 
  if (provider === AIProvider.DEEPINFRA) {
    splitPattern = '\n';
  }
 
  if (provider === AIProvider.SAMBANOVA) {
    splitPattern = '\n';
  }
 
  return splitPattern;
};
export type SplitPatternType = '\n\n' | '\r\n\r\n' | '\n' | '\r\n';
 
export const getStreamingMode = (
  saRequestBody: ChatCompletionRequestBody | CompletionRequestBody,
  provider: AIProvider,
  aiProviderRequestURL: string,
): boolean | undefined => {
  if (
    provider === AIProvider.GOOGLE ||
    (provider === AIProvider.GOOGLE_VERTEX_AI &&
      aiProviderRequestURL.indexOf('stream') > -1)
  ) {
    return true;
  }
  if (
    provider === AIProvider.BEDROCK &&
    (aiProviderRequestURL.indexOf('invoke-with-response-stream') > -1 ||
      aiProviderRequestURL.indexOf('converse-stream') > -1)
  ) {
    return true;
  }
  return saRequestBody.stream;
};
 
export function convertKeysToCamelCase(
  obj: Record<string, unknown>,
  parentKeysToPreserve: string[] = [],
): Record<string, unknown> | Record<string, unknown>[] {
  if (typeof obj !== 'object' || obj === null) {
    return obj; // Return unchanged for non-objects or null
  }
 
  if (Array.isArray(obj)) {
    // If it's an array, recursively convert each element
    return obj.map((item) =>
      convertKeysToCamelCase(item, parentKeysToPreserve),
    ) as Record<string, unknown>[];
  }
 
  return Object.keys(obj).reduce(
    (result: Record<string, unknown>, key: string) => {
      const value = obj[key];
      const camelCaseKey = toCamelCase(key);
      const isParentKeyToPreserve = parentKeysToPreserve.includes(key);
      if (typeof value === 'object' && !isParentKeyToPreserve) {
        // Recursively convert child objects
        result[camelCaseKey] = convertKeysToCamelCase(
          value as Record<string, unknown>,
          parentKeysToPreserve,
        );
      } else {
        // Add key in camelCase to the result
        result[camelCaseKey] = value;
      }
 
      return result;
    },
    {},
  );
 
  function toCamelCase(snakeCase: string): string {
    // Remove any leading underscores first, then replace one or more
    // underscores with the following alphanumeric character's uppercase
    // version and strip any trailing underscores.
    return snakeCase
      .replace(/^_+/, '')
      .replace(/_+([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())
      .replace(/_+$/g, '');
  }
}