feat: add vercel/ai package; gigachat api; refactor dictionaries; add units put request #72
							
								
								
									
										6188
									
								
								server/routers/kfu-m-24-1/eng-it-lean/gigachat/ai.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6188
									
								
								server/routers/kfu-m-24-1/eng-it-lean/gigachat/ai.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										614
									
								
								server/routers/kfu-m-24-1/eng-it-lean/gigachat/gigachat.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										614
									
								
								server/routers/kfu-m-24-1/eng-it-lean/gigachat/gigachat.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,614 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
var __defProp = Object.defineProperty;
 | 
			
		||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
 | 
			
		||||
var __getOwnPropNames = Object.getOwnPropertyNames;
 | 
			
		||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
 | 
			
		||||
var __export = (target, all) => {
 | 
			
		||||
  for (var name in all)
 | 
			
		||||
    __defProp(target, name, { get: all[name], enumerable: true });
 | 
			
		||||
};
 | 
			
		||||
var __copyProps = (to, from, except, desc) => {
 | 
			
		||||
  if (from && typeof from === "object" || typeof from === "function") {
 | 
			
		||||
    for (let key of __getOwnPropNames(from))
 | 
			
		||||
      if (!__hasOwnProp.call(to, key) && key !== except)
 | 
			
		||||
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
 | 
			
		||||
  }
 | 
			
		||||
  return to;
 | 
			
		||||
};
 | 
			
		||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
 | 
			
		||||
 | 
			
		||||
// src/index.ts
 | 
			
		||||
var index_exports = {};
 | 
			
		||||
__export(index_exports, {
 | 
			
		||||
  createGigachat: () => createGigachat,
 | 
			
		||||
  gigachat: () => gigachat
 | 
			
		||||
});
 | 
			
		||||
module.exports = __toCommonJS(index_exports);
 | 
			
		||||
 | 
			
		||||
// src/gigachat-provider.ts
 | 
			
		||||
var import_provider_utils4 = require("@ai-sdk/provider-utils");
 | 
			
		||||
 | 
			
		||||
// src/gigachat-chat-language-model.ts
 | 
			
		||||
var import_provider_utils2 = require("@ai-sdk/provider-utils");
 | 
			
		||||
var import_zod2 = require("zod");
 | 
			
		||||
 | 
			
		||||
// src/convert-to-gigachat-chat-messages.ts
 | 
			
		||||
var import_provider = require("@ai-sdk/provider");
 | 
			
		||||
function convertToGigachatChatMessages(prompt) {
 | 
			
		||||
  const messages = [];
 | 
			
		||||
  for (let i = 0; i < prompt.length; i++) {
 | 
			
		||||
    const { role, content } = prompt[i];
 | 
			
		||||
    const isLastMessage = i === prompt.length - 1;
 | 
			
		||||
    switch (role) {
 | 
			
		||||
      case "system": {
 | 
			
		||||
        messages.push({ role: "system", content });
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case "user": {
 | 
			
		||||
        messages.push({
 | 
			
		||||
          role: "user",
 | 
			
		||||
          content: content.map((part) => {
 | 
			
		||||
            switch (part.type) {
 | 
			
		||||
              case "text": {
 | 
			
		||||
                return part.text;
 | 
			
		||||
              }
 | 
			
		||||
              case "image": {
 | 
			
		||||
                throw new import_provider.UnsupportedFunctionalityError({
 | 
			
		||||
                  functionality: 'Images should be added in "attachments" object'
 | 
			
		||||
                });
 | 
			
		||||
              }
 | 
			
		||||
              case "file": {
 | 
			
		||||
                throw new import_provider.UnsupportedFunctionalityError({
 | 
			
		||||
                  functionality: "File content parts in user messages"
 | 
			
		||||
                });
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }).join("")
 | 
			
		||||
        });
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case "assistant": {
 | 
			
		||||
        let text = "";
 | 
			
		||||
        let functionCall;
 | 
			
		||||
        for (const part of content) {
 | 
			
		||||
          switch (part.type) {
 | 
			
		||||
            case "text": {
 | 
			
		||||
              text += part.text;
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            case "tool-call": {
 | 
			
		||||
              functionCall = {
 | 
			
		||||
                name: part.toolName,
 | 
			
		||||
                arguments: part.args
 | 
			
		||||
              };
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            default: {
 | 
			
		||||
              const _exhaustiveCheck = part;
 | 
			
		||||
              throw new Error(`Unsupported part: ${_exhaustiveCheck}`);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        messages.push({
 | 
			
		||||
          role: "assistant",
 | 
			
		||||
          content: text,
 | 
			
		||||
          prefix: isLastMessage ? true : void 0,
 | 
			
		||||
          function_call: functionCall
 | 
			
		||||
        });
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case "tool": {
 | 
			
		||||
        for (const toolResponse of content) {
 | 
			
		||||
          messages.push({
 | 
			
		||||
            role: "function",
 | 
			
		||||
            name: toolResponse.toolName,
 | 
			
		||||
            content: JSON.stringify(toolResponse.result)
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      default: {
 | 
			
		||||
        const _exhaustiveCheck = role;
 | 
			
		||||
        throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return messages;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// src/map-gigachat-finish-reason.ts
 | 
			
		||||
function mapGigachatFinishReason(finishReason) {
 | 
			
		||||
  switch (finishReason) {
 | 
			
		||||
    case "stop":
 | 
			
		||||
      return "stop";
 | 
			
		||||
    case "length":
 | 
			
		||||
    case "model_length":
 | 
			
		||||
      return "length";
 | 
			
		||||
    case "function_call":
 | 
			
		||||
      return "tool-calls";
 | 
			
		||||
    case "error":
 | 
			
		||||
      return "error";
 | 
			
		||||
    default:
 | 
			
		||||
      return "unknown";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// src/gigachat-error.ts
 | 
			
		||||
var import_provider_utils = require("@ai-sdk/provider-utils");
 | 
			
		||||
var import_zod = require("zod");
 | 
			
		||||
var gigachatErrorDataSchema = import_zod.z.object({
 | 
			
		||||
  object: import_zod.z.literal("error"),
 | 
			
		||||
  message: import_zod.z.string(),
 | 
			
		||||
  type: import_zod.z.string(),
 | 
			
		||||
  param: import_zod.z.string().nullable(),
 | 
			
		||||
  code: import_zod.z.string().nullable()
 | 
			
		||||
});
 | 
			
		||||
var gigachatFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponseHandler)({
 | 
			
		||||
  errorSchema: gigachatErrorDataSchema,
 | 
			
		||||
  errorToMessage: (data) => data.message
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// src/get-response-metadata.ts
 | 
			
		||||
function getResponseMetadata({
 | 
			
		||||
  model,
 | 
			
		||||
  created
 | 
			
		||||
}) {
 | 
			
		||||
  return {
 | 
			
		||||
    modelId: model != null ? model : void 0,
 | 
			
		||||
    timestamp: created != null ? new Date(created * 1e3) : void 0
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// src/gigachat-prepare-tools.ts
 | 
			
		||||
var import_provider2 = require("@ai-sdk/provider");
 | 
			
		||||
function prepareTools(mode) {
 | 
			
		||||
  var _a;
 | 
			
		||||
  const tools = ((_a = mode.tools) == null ? void 0 : _a.length) ? mode.tools : void 0;
 | 
			
		||||
  const toolWarnings = [];
 | 
			
		||||
  if (tools == null) {
 | 
			
		||||
    return { tools: void 0, tool_choice: void 0, toolWarnings };
 | 
			
		||||
  }
 | 
			
		||||
  const gigachatTools = [];
 | 
			
		||||
  for (const tool of tools) {
 | 
			
		||||
    if (tool.type === "provider-defined") {
 | 
			
		||||
      toolWarnings.push({ type: "unsupported-tool", tool });
 | 
			
		||||
    } else {
 | 
			
		||||
      gigachatTools.push({
 | 
			
		||||
        type: "function",
 | 
			
		||||
        function: {
 | 
			
		||||
          name: tool.name,
 | 
			
		||||
          description: tool.description,
 | 
			
		||||
          parameters: tool.parameters
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  const toolChoice = mode.toolChoice;
 | 
			
		||||
  if (toolChoice == null) {
 | 
			
		||||
    return { tools: gigachatTools, tool_choice: void 0, toolWarnings };
 | 
			
		||||
  }
 | 
			
		||||
  const type = toolChoice.type;
 | 
			
		||||
  switch (type) {
 | 
			
		||||
    case "auto":
 | 
			
		||||
    case "none":
 | 
			
		||||
      return { tools: gigachatTools, tool_choice: type, toolWarnings };
 | 
			
		||||
    case "required":
 | 
			
		||||
      return { tools: gigachatTools, tool_choice: "any", toolWarnings };
 | 
			
		||||
    // gigachat does not support tool mode directly,
 | 
			
		||||
    // so we filter the tools and force the tool choice through 'any'
 | 
			
		||||
    case "tool":
 | 
			
		||||
      return {
 | 
			
		||||
        tools: gigachatTools.filter((tool) => tool.function.name === toolChoice.toolName),
 | 
			
		||||
        tool_choice: "any",
 | 
			
		||||
        toolWarnings
 | 
			
		||||
      };
 | 
			
		||||
    default: {
 | 
			
		||||
      const _exhaustiveCheck = type;
 | 
			
		||||
      throw new import_provider2.UnsupportedFunctionalityError({
 | 
			
		||||
        functionality: `Unsupported tool choice type: ${_exhaustiveCheck}`
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// src/gigachat-chat-language-model.ts
 | 
			
		||||
var GigachatChatLanguageModel = class {
 | 
			
		||||
  constructor(modelId, settings, config) {
 | 
			
		||||
    this.specificationVersion = "v1";
 | 
			
		||||
    this.defaultObjectGenerationMode = "json";
 | 
			
		||||
    this.supportsImageUrls = false;
 | 
			
		||||
    this.modelId = modelId;
 | 
			
		||||
    this.settings = settings;
 | 
			
		||||
    this.config = config;
 | 
			
		||||
  }
 | 
			
		||||
  get provider() {
 | 
			
		||||
    return this.config.provider;
 | 
			
		||||
  }
 | 
			
		||||
  getArgs({
 | 
			
		||||
    mode,
 | 
			
		||||
    prompt,
 | 
			
		||||
    maxTokens,
 | 
			
		||||
    temperature,
 | 
			
		||||
    topP,
 | 
			
		||||
    topK,
 | 
			
		||||
    frequencyPenalty,
 | 
			
		||||
    presencePenalty,
 | 
			
		||||
    stopSequences,
 | 
			
		||||
    responseFormat,
 | 
			
		||||
    seed
 | 
			
		||||
  }) {
 | 
			
		||||
    const type = mode.type;
 | 
			
		||||
    const warnings = [];
 | 
			
		||||
    if (topK != null) {
 | 
			
		||||
      warnings.push({
 | 
			
		||||
        type: "unsupported-setting",
 | 
			
		||||
        setting: "topK"
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (frequencyPenalty != null) {
 | 
			
		||||
      warnings.push({
 | 
			
		||||
        type: "unsupported-setting",
 | 
			
		||||
        setting: "frequencyPenalty"
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (presencePenalty != null) {
 | 
			
		||||
      warnings.push({
 | 
			
		||||
        type: "unsupported-setting",
 | 
			
		||||
        setting: "presencePenalty"
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (stopSequences != null) {
 | 
			
		||||
      warnings.push({
 | 
			
		||||
        type: "unsupported-setting",
 | 
			
		||||
        setting: "stopSequences"
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (responseFormat != null && responseFormat.type === "json" && responseFormat.schema != null) {
 | 
			
		||||
      warnings.push({
 | 
			
		||||
        type: "unsupported-setting",
 | 
			
		||||
        setting: "responseFormat",
 | 
			
		||||
        details: "JSON response format schema is not supported"
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    const baseArgs = {
 | 
			
		||||
      // model id:
 | 
			
		||||
      model: this.modelId,
 | 
			
		||||
      // model specific settings:
 | 
			
		||||
      stream: this.settings.stream,
 | 
			
		||||
      repetition_penalty: this.settings.repetition_penalty,
 | 
			
		||||
      update_interval: this.settings.update_interval,
 | 
			
		||||
      // standardized settings:
 | 
			
		||||
      max_tokens: maxTokens,
 | 
			
		||||
      temperature,
 | 
			
		||||
      top_p: topP,
 | 
			
		||||
      // response format:
 | 
			
		||||
      response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? { type: "json_object" } : void 0,
 | 
			
		||||
      // messages:
 | 
			
		||||
      messages: convertToGigachatChatMessages(prompt)
 | 
			
		||||
    };
 | 
			
		||||
    switch (type) {
 | 
			
		||||
      case "regular": {
 | 
			
		||||
        const { tools, tool_choice, toolWarnings } = prepareTools(mode);
 | 
			
		||||
        return {
 | 
			
		||||
          args: { ...baseArgs, tools, tool_choice },
 | 
			
		||||
          warnings: [...warnings, ...toolWarnings]
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
      case "object-json": {
 | 
			
		||||
        return {
 | 
			
		||||
          args: {
 | 
			
		||||
            ...baseArgs,
 | 
			
		||||
            response_format: { type: "json_object" }
 | 
			
		||||
          },
 | 
			
		||||
          warnings
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
      case "object-tool": {
 | 
			
		||||
        return {
 | 
			
		||||
          args: {
 | 
			
		||||
            ...baseArgs,
 | 
			
		||||
            tool_choice: "any",
 | 
			
		||||
            tools: [{ type: "function", function: mode.tool }]
 | 
			
		||||
          },
 | 
			
		||||
          warnings
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
      default: {
 | 
			
		||||
        const _exhaustiveCheck = type;
 | 
			
		||||
        throw new Error(`Unsupported type: ${_exhaustiveCheck}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  async doGenerate(options) {
 | 
			
		||||
    var _a;
 | 
			
		||||
    const { args, warnings } = this.getArgs(options);
 | 
			
		||||
    const { responseHeaders, value: response } = await (0, import_provider_utils2.postJsonToApi)({
 | 
			
		||||
      url: `${this.config.baseURL}/chat/completions`,
 | 
			
		||||
      headers: (0, import_provider_utils2.combineHeaders)(this.config.headers(), options.headers),
 | 
			
		||||
      body: args,
 | 
			
		||||
      failedResponseHandler: gigachatFailedResponseHandler,
 | 
			
		||||
      successfulResponseHandler: (0, import_provider_utils2.createJsonResponseHandler)(gigachatChatResponseSchema),
 | 
			
		||||
      abortSignal: options.abortSignal,
 | 
			
		||||
      fetch: this.config.fetch
 | 
			
		||||
    });
 | 
			
		||||
    const { messages: rawPrompt, ...rawSettings } = args;
 | 
			
		||||
    const choice = response.choices[0];
 | 
			
		||||
    let text = (_a = choice.message.content) != null ? _a : void 0;
 | 
			
		||||
    const lastMessage = rawPrompt[rawPrompt.length - 1];
 | 
			
		||||
    if (lastMessage.role === "assistant" && (text == null ? void 0 : text.startsWith(lastMessage.content))) {
 | 
			
		||||
      text = text.slice(lastMessage.content.length);
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
      text,
 | 
			
		||||
      toolCalls: choice.message.function_call ? [
 | 
			
		||||
        {
 | 
			
		||||
          toolCallType: "function",
 | 
			
		||||
          toolCallId: choice.message.function_call.name,
 | 
			
		||||
          toolName: choice.message.function_call.name,
 | 
			
		||||
          args: JSON.stringify(choice.message.function_call.arguments)
 | 
			
		||||
        }
 | 
			
		||||
      ] : [],
 | 
			
		||||
      finishReason: mapGigachatFinishReason(choice.finish_reason),
 | 
			
		||||
      usage: {
 | 
			
		||||
        promptTokens: response.usage.prompt_tokens,
 | 
			
		||||
        completionTokens: response.usage.completion_tokens
 | 
			
		||||
      },
 | 
			
		||||
      rawCall: { rawPrompt, rawSettings },
 | 
			
		||||
      rawResponse: { headers: responseHeaders },
 | 
			
		||||
      request: { body: JSON.stringify(args) },
 | 
			
		||||
      response: getResponseMetadata(response),
 | 
			
		||||
      warnings
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
  async doStream(options) {
 | 
			
		||||
    const { args, warnings } = this.getArgs(options);
 | 
			
		||||
    const body = { ...args, stream: true };
 | 
			
		||||
    const { responseHeaders, value: response } = await (0, import_provider_utils2.postJsonToApi)({
 | 
			
		||||
      url: `${this.config.baseURL}/chat/completions`,
 | 
			
		||||
      headers: (0, import_provider_utils2.combineHeaders)(this.config.headers(), options.headers),
 | 
			
		||||
      body,
 | 
			
		||||
      failedResponseHandler: gigachatFailedResponseHandler,
 | 
			
		||||
      successfulResponseHandler: (0, import_provider_utils2.createEventSourceResponseHandler)(gigachatChatChunkSchema),
 | 
			
		||||
      abortSignal: options.abortSignal,
 | 
			
		||||
      fetch: this.config.fetch
 | 
			
		||||
    });
 | 
			
		||||
    const { messages: rawPrompt, ...rawSettings } = args;
 | 
			
		||||
    let finishReason = "unknown";
 | 
			
		||||
    let usage = {
 | 
			
		||||
      promptTokens: Number.NaN,
 | 
			
		||||
      completionTokens: Number.NaN
 | 
			
		||||
    };
 | 
			
		||||
    let chunkNumber = 0;
 | 
			
		||||
    let trimLeadingSpace = false;
 | 
			
		||||
    return {
 | 
			
		||||
      stream: response.pipeThrough(
 | 
			
		||||
        new TransformStream({
 | 
			
		||||
          transform(chunk, controller) {
 | 
			
		||||
            if (!chunk.success) {
 | 
			
		||||
              controller.enqueue({ type: "error", error: chunk.error });
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
            chunkNumber++;
 | 
			
		||||
            const value = chunk.value;
 | 
			
		||||
            if (chunkNumber === 1) {
 | 
			
		||||
              controller.enqueue({
 | 
			
		||||
                type: "response-metadata",
 | 
			
		||||
                ...getResponseMetadata(value)
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
            if (value.usage != null) {
 | 
			
		||||
              usage = {
 | 
			
		||||
                promptTokens: value.usage.prompt_tokens,
 | 
			
		||||
                completionTokens: value.usage.completion_tokens
 | 
			
		||||
              };
 | 
			
		||||
            }
 | 
			
		||||
            const choice = value.choices[0];
 | 
			
		||||
            if ((choice == null ? void 0 : choice.finish_reason) != null) {
 | 
			
		||||
              finishReason = mapGigachatFinishReason(choice.finish_reason);
 | 
			
		||||
            }
 | 
			
		||||
            if ((choice == null ? void 0 : choice.delta) == null) {
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
            const delta = choice.delta;
 | 
			
		||||
            if (chunkNumber <= 2) {
 | 
			
		||||
              const lastMessage = rawPrompt[rawPrompt.length - 1];
 | 
			
		||||
              if (lastMessage.role === "assistant" && delta.content === lastMessage.content.trimEnd()) {
 | 
			
		||||
                if (delta.content.length < lastMessage.content.length) {
 | 
			
		||||
                  trimLeadingSpace = true;
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            if (delta.content != null) {
 | 
			
		||||
              controller.enqueue({
 | 
			
		||||
                type: "text-delta",
 | 
			
		||||
                textDelta: trimLeadingSpace ? delta.content.trimStart() : delta.content
 | 
			
		||||
              });
 | 
			
		||||
              trimLeadingSpace = false;
 | 
			
		||||
            }
 | 
			
		||||
            if (delta.function_call != null) {
 | 
			
		||||
              controller.enqueue({
 | 
			
		||||
                type: "tool-call-delta",
 | 
			
		||||
                toolCallType: "function",
 | 
			
		||||
                toolCallId: delta.function_call.name,
 | 
			
		||||
                toolName: delta.function_call.name,
 | 
			
		||||
                argsTextDelta: JSON.stringify(delta.function_call.arguments)
 | 
			
		||||
              });
 | 
			
		||||
              controller.enqueue({
 | 
			
		||||
                type: "tool-call",
 | 
			
		||||
                toolCallType: "function",
 | 
			
		||||
                toolCallId: delta.function_call.name,
 | 
			
		||||
                toolName: delta.function_call.name,
 | 
			
		||||
                args: JSON.stringify(delta.function_call.arguments)
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          flush(controller) {
 | 
			
		||||
            controller.enqueue({ type: "finish", finishReason, usage });
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      ),
 | 
			
		||||
      rawCall: { rawPrompt, rawSettings },
 | 
			
		||||
      rawResponse: { headers: responseHeaders },
 | 
			
		||||
      request: { body: JSON.stringify(body) },
 | 
			
		||||
      warnings
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
var gigachatChatResponseSchema = import_zod2.z.object({
 | 
			
		||||
  created: import_zod2.z.number().nullish(),
 | 
			
		||||
  model: import_zod2.z.string().nullish(),
 | 
			
		||||
  choices: import_zod2.z.array(
 | 
			
		||||
    import_zod2.z.object({
 | 
			
		||||
      message: import_zod2.z.object({
 | 
			
		||||
        role: import_zod2.z.literal("assistant"),
 | 
			
		||||
        content: import_zod2.z.string().nullable(),
 | 
			
		||||
        created: import_zod2.z.number().nullish(),
 | 
			
		||||
        name: import_zod2.z.string().nullish(),
 | 
			
		||||
        function_call: import_zod2.z.object({
 | 
			
		||||
          name: import_zod2.z.string(),
 | 
			
		||||
          arguments: import_zod2.z.record(import_zod2.z.any())
 | 
			
		||||
        }).nullish(),
 | 
			
		||||
        data_for_context: import_zod2.z.array(import_zod2.z.object({})).nullish()
 | 
			
		||||
      }),
 | 
			
		||||
      index: import_zod2.z.number(),
 | 
			
		||||
      finish_reason: import_zod2.z.string().nullish()
 | 
			
		||||
    })
 | 
			
		||||
  ),
 | 
			
		||||
  object: import_zod2.z.literal("chat.completion"),
 | 
			
		||||
  usage: import_zod2.z.object({
 | 
			
		||||
    prompt_tokens: import_zod2.z.number(),
 | 
			
		||||
    completion_tokens: import_zod2.z.number(),
 | 
			
		||||
    total_tokens: import_zod2.z.number()
 | 
			
		||||
  })
 | 
			
		||||
});
 | 
			
		||||
var gigachatChatChunkSchema = import_zod2.z.object({
 | 
			
		||||
  created: import_zod2.z.number().nullish(),
 | 
			
		||||
  model: import_zod2.z.string().nullish(),
 | 
			
		||||
  object: import_zod2.z.literal("chat.completion"),
 | 
			
		||||
  choices: import_zod2.z.array(
 | 
			
		||||
    import_zod2.z.object({
 | 
			
		||||
      delta: import_zod2.z.object({
 | 
			
		||||
        role: import_zod2.z.enum(["assistant"]).optional(),
 | 
			
		||||
        content: import_zod2.z.string().nullish(),
 | 
			
		||||
        functions_state_id: import_zod2.z.string().nullish(),
 | 
			
		||||
        function_call: import_zod2.z.object({
 | 
			
		||||
          name: import_zod2.z.string(),
 | 
			
		||||
          arguments: import_zod2.z.object({})
 | 
			
		||||
        }).nullish()
 | 
			
		||||
      }),
 | 
			
		||||
      finish_reason: import_zod2.z.string().nullish(),
 | 
			
		||||
      index: import_zod2.z.number()
 | 
			
		||||
    })
 | 
			
		||||
  ),
 | 
			
		||||
  usage: import_zod2.z.object({
 | 
			
		||||
    prompt_tokens: import_zod2.z.number(),
 | 
			
		||||
    completion_tokens: import_zod2.z.number()
 | 
			
		||||
  }).nullish()
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// src/gigachat-embedding-model.ts
 | 
			
		||||
var import_provider3 = require("@ai-sdk/provider");
 | 
			
		||||
var import_provider_utils3 = require("@ai-sdk/provider-utils");
 | 
			
		||||
var import_zod3 = require("zod");
 | 
			
		||||
var GigachatEmbeddingModel = class {
 | 
			
		||||
  constructor(modelId, settings, config) {
 | 
			
		||||
    this.specificationVersion = "v1";
 | 
			
		||||
    this.modelId = modelId;
 | 
			
		||||
    this.settings = settings;
 | 
			
		||||
    this.config = config;
 | 
			
		||||
  }
 | 
			
		||||
  get provider() {
 | 
			
		||||
    return this.config.provider;
 | 
			
		||||
  }
 | 
			
		||||
  get maxEmbeddingsPerCall() {
 | 
			
		||||
    var _a;
 | 
			
		||||
    return (_a = this.settings.maxEmbeddingsPerCall) != null ? _a : 32;
 | 
			
		||||
  }
 | 
			
		||||
  get supportsParallelCalls() {
 | 
			
		||||
    var _a;
 | 
			
		||||
    return (_a = this.settings.supportsParallelCalls) != null ? _a : false;
 | 
			
		||||
  }
 | 
			
		||||
  async doEmbed({
 | 
			
		||||
    values,
 | 
			
		||||
    abortSignal,
 | 
			
		||||
    headers
 | 
			
		||||
  }) {
 | 
			
		||||
    if (values.length > this.maxEmbeddingsPerCall) {
 | 
			
		||||
      throw new import_provider3.TooManyEmbeddingValuesForCallError({
 | 
			
		||||
        provider: this.provider,
 | 
			
		||||
        modelId: this.modelId,
 | 
			
		||||
        maxEmbeddingsPerCall: this.maxEmbeddingsPerCall,
 | 
			
		||||
        values
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    const { responseHeaders, value: response } = await (0, import_provider_utils3.postJsonToApi)({
 | 
			
		||||
      url: `${this.config.baseURL}/embeddings`,
 | 
			
		||||
      headers: (0, import_provider_utils3.combineHeaders)(this.config.headers(), headers),
 | 
			
		||||
      body: {
 | 
			
		||||
        model: this.modelId,
 | 
			
		||||
        input: values,
 | 
			
		||||
        encoding_format: "float"
 | 
			
		||||
      },
 | 
			
		||||
      failedResponseHandler: gigachatFailedResponseHandler,
 | 
			
		||||
      successfulResponseHandler: (0, import_provider_utils3.createJsonResponseHandler)(GigachatTextEmbeddingResponseSchema),
 | 
			
		||||
      abortSignal,
 | 
			
		||||
      fetch: this.config.fetch
 | 
			
		||||
    });
 | 
			
		||||
    return {
 | 
			
		||||
      embeddings: response.data.map((item) => item.embedding),
 | 
			
		||||
      usage: response.usage ? { tokens: response.usage.prompt_tokens } : void 0,
 | 
			
		||||
      rawResponse: { headers: responseHeaders }
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
var GigachatTextEmbeddingResponseSchema = import_zod3.z.object({
 | 
			
		||||
  data: import_zod3.z.array(import_zod3.z.object({ embedding: import_zod3.z.array(import_zod3.z.number()) })),
 | 
			
		||||
  usage: import_zod3.z.object({ prompt_tokens: import_zod3.z.number() }).nullish()
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// src/gigachat-provider.ts
 | 
			
		||||
function createGigachat(options = {}) {
 | 
			
		||||
  var _a;
 | 
			
		||||
  const baseURL = (_a = (0, import_provider_utils4.withoutTrailingSlash)(options.baseURL)) != null ? _a : "https://gigachat.devices.sberbank.ru/api/v1";
 | 
			
		||||
  const getAccessToken = () => ({});
 | 
			
		||||
  const getHeaders = () => ({
 | 
			
		||||
    Authorization: `Bearer ${(0, import_provider_utils4.loadApiKey)({
 | 
			
		||||
      apiKey: options.apiKey,
 | 
			
		||||
      environmentVariableName: "GIGACHAT_ACCESS_TOKEN",
 | 
			
		||||
      description: "GigaChat"
 | 
			
		||||
    })}`,
 | 
			
		||||
    ...options.headers
 | 
			
		||||
  });
 | 
			
		||||
  const createChatModel = (modelId, settings = {}) => new GigachatChatLanguageModel(modelId, settings, {
 | 
			
		||||
    provider: "gigachat.chat",
 | 
			
		||||
    baseURL,
 | 
			
		||||
    headers: getHeaders,
 | 
			
		||||
    fetch: options.fetch
 | 
			
		||||
  });
 | 
			
		||||
  const createEmbeddingModel = (modelId, settings = {}) => new GigachatEmbeddingModel(modelId, settings, {
 | 
			
		||||
    provider: "gigachat.embedding",
 | 
			
		||||
    baseURL,
 | 
			
		||||
    headers: getHeaders,
 | 
			
		||||
    fetch: options.fetch
 | 
			
		||||
  });
 | 
			
		||||
  const provider = function(modelId, settings) {
 | 
			
		||||
    if (new.target) {
 | 
			
		||||
      throw new Error("Gigachat function cannot be called with the new keyword.");
 | 
			
		||||
    }
 | 
			
		||||
    return createChatModel(modelId, settings);
 | 
			
		||||
  };
 | 
			
		||||
  provider.languageModel = createChatModel;
 | 
			
		||||
  provider.chat = createChatModel;
 | 
			
		||||
  provider.embedding = createEmbeddingModel;
 | 
			
		||||
  provider.textEmbedding = createEmbeddingModel;
 | 
			
		||||
  provider.textEmbeddingModel = createEmbeddingModel;
 | 
			
		||||
  return provider;
 | 
			
		||||
}
 | 
			
		||||
var gigachat = createGigachat();
 | 
			
		||||
// Annotate the CommonJS export names for ESM import in node:
 | 
			
		||||
0 && (module.exports = {
 | 
			
		||||
  createGigachat,
 | 
			
		||||
  gigachat
 | 
			
		||||
});
 | 
			
		||||
//# sourceMappingURL=index.js.map
 | 
			
		||||
							
								
								
									
										120
									
								
								server/routers/kfu-m-24-1/eng-it-lean/gigachat/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								server/routers/kfu-m-24-1/eng-it-lean/gigachat/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
const https = require('follow-redirects').https;
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const qs = require('querystring');
 | 
			
		||||
const uuid = require('uuid');
 | 
			
		||||
 | 
			
		||||
const router = require('express').Router();
 | 
			
		||||
 | 
			
		||||
// vercel/ai package - https://github.com/vercel/ai
 | 
			
		||||
const ai = require('./ai')
 | 
			
		||||
// gigachat provider for vercel/ai
 | 
			
		||||
const gigachatProvider = require('./gigachat')
 | 
			
		||||
 | 
			
		||||
module.exports = router;
 | 
			
		||||
 | 
			
		||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
 | 
			
		||||
process.env.GIGACHAT_AUTH = 'NWVjYTczYjctNWRkYi00NzExLTg0YTEtMjhlOWVmODM2MjI4OjlmMTBkMGVkLWZjZjktNGZhOS1hNDZjLTc5ZWU1YzExOGExMw=='
 | 
			
		||||
 | 
			
		||||
const gigachat = gigachatProvider.createGigachat( { 
 | 
			
		||||
  headers: {
 | 
			
		||||
    'Content-Type': 'application/json',
 | 
			
		||||
    'Accept': 'application/json',
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
router.use((req, res, next) => {
 | 
			
		||||
  const hasToken = process.env.GIGACHAT_ACCESS_TOKEN && process.env.GIGACHAT_EXPIRES_AT != null;
 | 
			
		||||
  const hasExpired = new Date(process.env.GIGACHAT_EXPIRES_AT) <= new Date();
 | 
			
		||||
  if (!hasToken || hasExpired) {
 | 
			
		||||
    let auth = process.env.GIGACHAT_AUTH;
 | 
			
		||||
    let rquid = uuid.v4();
 | 
			
		||||
    let options = {
 | 
			
		||||
      'method': 'POST',
 | 
			
		||||
      'hostname': 'ngw.devices.sberbank.ru',
 | 
			
		||||
      'port': 9443,
 | 
			
		||||
      'path': '/api/v2/oauth',
 | 
			
		||||
      'headers': {
 | 
			
		||||
        'Content-Type': 'application/x-www-form-urlencoded',
 | 
			
		||||
        'Accept': 'application/json',
 | 
			
		||||
        'RqUID': rquid,
 | 
			
		||||
        'Authorization': 'Basic ' + auth
 | 
			
		||||
      },
 | 
			
		||||
      'maxRedirects': 20
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    const req = https.request(options, (response) => {
 | 
			
		||||
      let chunks = [];
 | 
			
		||||
    
 | 
			
		||||
      response.on("data", (chunk) => {
 | 
			
		||||
        chunks.push(chunk);
 | 
			
		||||
      });
 | 
			
		||||
    
 | 
			
		||||
      response.on("end", (chunk) => {
 | 
			
		||||
        let body = Buffer.concat(chunks);
 | 
			
		||||
        console.log(body.toString());
 | 
			
		||||
        let json = JSON.parse(body.toString());
 | 
			
		||||
        process.env.GIGACHAT_ACCESS_TOKEN = json.access_token;
 | 
			
		||||
        process.env.GIGACHAT_EXPIRES_AT = json.expires_at;
 | 
			
		||||
      });
 | 
			
		||||
    
 | 
			
		||||
      response.on("error", (error) => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        res.status(500).send(error);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    let postData = qs.stringify({
 | 
			
		||||
      'scope': 'GIGACHAT_API_PERS'
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    req.write(postData);
 | 
			
		||||
    req.end();
 | 
			
		||||
  }
 | 
			
		||||
  next()
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.post('/chat', async (req, res) => {
 | 
			
		||||
  const { messages } = req.body;
 | 
			
		||||
 | 
			
		||||
  const result = ai.streamText({
 | 
			
		||||
    model: gigachat('GigaChat'),
 | 
			
		||||
    system: 'You are a helpful assistant.',
 | 
			
		||||
    messages,
 | 
			
		||||
    stream: true,
 | 
			
		||||
    update_interval: 0.2,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  result.pipeDataStreamToResponse(res);
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
router.post('/new-unit', async (req, res) => {
 | 
			
		||||
  const { prompt } = req.body;
 | 
			
		||||
 | 
			
		||||
  const result =  ai.streamText({
 | 
			
		||||
    model: gigachat('GigaChat'),
 | 
			
		||||
    system:`
 | 
			
		||||
    Я хочу, чтобы вы выступали в роли помощника для создания продвинутых текстовых уроков английского языка. Я буду указывать тему и уровень сложности (начинающий, средний, продвинутый), а вы будете предоставлять структурированный план урока в формате Markdown. Урок должен включать только текстовые элементы (без видео, картинок, аудио) и содержать следующие разделы:
 | 
			
		||||
    -Цель урока — конкретный навык или знание, которое освоят студенты.
 | 
			
		||||
    -Лексика
 | 
			
		||||
      -Базовые термины: 5-7 слов/фраз с примерами употребления.
 | 
			
		||||
      -Расширенная лексика: 3-5 идиом, фразовых глаголов или сложных выражений (для среднего/продвинутого уровня).
 | 
			
		||||
    -Грамматический фокус
 | 
			
		||||
      -Правило с пояснением и 3-5 примерами.
 | 
			
		||||
      -Типичные ошибки и как их избежать.
 | 
			
		||||
    -Контекстуализация
 | 
			
		||||
      -Короткий текст (диалог, статья, описание) для анализа с использованием лексики и грамматики урока.
 | 
			
		||||
    -Упражнения
 | 
			
		||||
      -Письменное задание: например, составить предложения/эссе по теме.
 | 
			
		||||
      -Устная практика: ролевые диалоги (текстовые сценарии), описание ситуаций.
 | 
			
		||||
      -Аналитическое задание: исправление ошибок в предложениях, перевод сложных конструкций.
 | 
			
		||||
    -Домашнее задание
 | 
			
		||||
      Текстовые задачи: написание текста, грамматические тесты, поиск синонимов/антонимов.
 | 
			
		||||
    Ответ должен быть оформлен в Markdown, лаконичным, без лишних комментариев, если пишешь блок кода, начинай его с новой строки.
 | 
			
		||||
    `,
 | 
			
		||||
    prompt,
 | 
			
		||||
    stream: true,
 | 
			
		||||
    update_interval: 0.3,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  result.pipeDataStreamToResponse(res);
 | 
			
		||||
});
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
const router = require("express").Router();
 | 
			
		||||
const router = require('express').Router();
 | 
			
		||||
 | 
			
		||||
const dictionariesRouter = require("./dictionaries");
 | 
			
		||||
const dictionariesRouter = require('./dictionaries');
 | 
			
		||||
const unitsRouter = require('./units');
 | 
			
		||||
const gigachatRouter = require('./gigachat');
 | 
			
		||||
module.exports = router;
 | 
			
		||||
 | 
			
		||||
const delay =
 | 
			
		||||
@ -11,5 +12,6 @@ const delay =
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
router.use(delay());
 | 
			
		||||
router.use("/dictionaries", dictionariesRouter);
 | 
			
		||||
router.use('/dictionaries', dictionariesRouter);
 | 
			
		||||
router.use('/units', unitsRouter);
 | 
			
		||||
router.use('/gigachat', gigachatRouter);
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user