3ru/gpt-translate

View on GitHub
src/gpt.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { error, getInput, info, notice, setFailed } from '@actions/core'
import OpenAI from 'openai'
import { encode } from 'gpt-3-encoder'
import { modelTokens, minimumTokens } from './const'

const API_KEY = getInput('apikey')
const BASE_PATH = getInput('basePath') || 'https://api.openai.com/v1'
const MODEL = getInput('model') || Object.keys(modelTokens)[0]
const PROMPT =
  getInput('prompt') ||
  'Please translate the given text into naturalistic {targetLanguage}.'
if (!API_KEY) {
  setFailed('Error: API_KEY could not be retrieved.')
}

const configuration = {
  apiKey: API_KEY,
  basePath: BASE_PATH,
}
// const openAIApi = new OpenAI(configuration)
const openAIApi = new OpenAI({
  apiKey: API_KEY,
  baseURL: BASE_PATH,
})

export const askGPT = async (text: string, prompt: string): Promise<string> => {
  const {
    choices: [{ message: { content: content } = { content: '' } }],
  } = await openAIApi.chat.completions
    .create({
      model: MODEL,
      messages: [
        { role: 'system', content: prompt },
        { role: 'user', content: text },
      ],
      top_p: 0.5,
    })
    .catch((err) => {
      error(err)

      const notifications = [
        'If the status code is 400, the file exceeds token limit without line breaks. \nPlease open one line as appropriate.',
        'If the status code is 404, you do not have right access to the model.',
      ]
      notifications.forEach((msg) => notice(msg))

      process.exit(1)
    })

  if (!content || content === '') {
    info('Possible Error: Translation result is empty')
    return ''
  }

  return content
}

export const gptTranslate = async (
  text: string,
  targetLanguage: string,
  targetFileExt: string, // filename extension. Must be within availableFileExtensions.
  splitter = `\n\n`,
): Promise<string> => {
  const maxToken = modelTokens[MODEL] || minimumTokens
  const prompt = PROMPT.replaceAll(
    '{targetLanguage}',
    targetLanguage,
  ).replaceAll('{targetFileExt}', targetFileExt)

  let translated = ''
  let chunk = ''

  info(`${new Date().toLocaleString()} Start translating with ${MODEL}...`)
  const contentChunks = text.split(splitter)
  for (let i = 0; i < contentChunks.length; i++) {
    if (encode(chunk + contentChunks[i]).length > maxToken) {
      const translatedContent = await askGPT(chunk, prompt)
      translated += translatedContent + splitter
      chunk = ''
    }
    chunk += contentChunks[i] + (i < contentChunks.length - 1 ? splitter : '')
  }
  translated += await askGPT(chunk, prompt)
  info('Translation completed!')

  return translated
}