diff --git a/README.md b/README.md index 77e4d84..5350cd2 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,20 @@ Supported Translator: [`Apertium`](https://www.apertium.org/), [`Argos`](https://translate.argosopentech.com/), [`Bing`](https://www.bing.com/translator), +[`ChatGPT`](https://chat.openai.com/), [`Google`](https://translate.google.com/)(default), [`Reverso`](https://www.reverso.net/text-translation) +## ⚠️ Note for ChatGPT + +You need to apply a API key on [ChatGPT](https://platform.openai.com/account/api-keys). +And write it to `$XDG_CONFIG_HOME/gtt/gtt.yaml` or `$HOME/.config/gtt/gtt.yaml`. + +```yaml +api_key: + chatgpt: YOUR_API_KEY # <- Replace with your API Key +``` + ## ScreenShot ![screenshot](https://user-images.githubusercontent.com/58657914/213123592-5d8bccfb-ff80-4ad6-aaca-03b31c4c2c59.gif) @@ -50,6 +61,7 @@ See available languages on: - [Apertium Translate](https://www.apertium.org/) for `Apertium` - [argosopentech/argos-translate](https://github.com/argosopentech/argos-translate#supported-languages) for `Argos` - [Bing language-support](https://learn.microsoft.com/en-us/azure/cognitive-services/translator/language-support#translation) for `Bing` +- `ChatGPT` is same as `Bing`. See [Bing language-support](https://learn.microsoft.com/en-us/azure/cognitive-services/translator/language-support#translation) - [Google Language support](https://cloud.google.com/translate/docs/languages) for `Google` - [Reverso Translation](https://www.reverso.net/text-translation) for `Reverso` diff --git a/config.go b/config.go index 05ef925..7cddd07 100644 --- a/config.go +++ b/config.go @@ -25,6 +25,8 @@ func configInit() { "destination.language.argos": "English", "source.language.bing": "English", "destination.language.bing": "English", + "source.language.chatgpt": "English", + "destination.language.chatgpt": "English", "source.language.google": "English", "destination.language.google": "English", "source.language.reverso": "English", @@ -76,7 +78,7 @@ func configInit() { } } - // setup + // Setup for _, name := range translate.AllTranslator { translators[name] = translate.NewTranslator(name) translators[name].SetSrcLang( @@ -90,7 +92,11 @@ func configInit() { uiStyle.Transparent = config.GetBool("transparent") uiStyle.SetSrcBorderColor(config.GetString("source.border_color")). SetDstBorderColor(config.GetString("destination.border_color")) - // set argument language + // Set API Key + if config.Get("api_key.chatgpt") != nil { + translators["ChatGPT"].SetAPIKey(config.GetString("api_key.chatgpt")) + } + // Set argument language if len(*srcLangArg) > 0 { translator.SetSrcLang(*srcLangArg) } diff --git a/internal/translate/apertium/translator.go b/internal/translate/apertium/translator.go index 5c25b80..0d10f71 100644 --- a/internal/translate/apertium/translator.go +++ b/internal/translate/apertium/translator.go @@ -29,6 +29,9 @@ func NewTranslator() *Translator { } } +func (t *Translator) SetAPIKey(key string) { +} + func (t *Translator) GetAllLang() []string { return lang } diff --git a/internal/translate/argos/translator.go b/internal/translate/argos/translator.go index e8c07e2..1a978d1 100644 --- a/internal/translate/argos/translator.go +++ b/internal/translate/argos/translator.go @@ -29,6 +29,9 @@ func NewTranslator() *Translator { } } +func (t *Translator) SetAPIKey(key string) { +} + func (t *Translator) GetAllLang() []string { return lang } diff --git a/internal/translate/bing/translator.go b/internal/translate/bing/translator.go index 81370e8..a82e67d 100644 --- a/internal/translate/bing/translator.go +++ b/internal/translate/bing/translator.go @@ -45,6 +45,9 @@ func NewTranslator() *Translator { } } +func (t *Translator) SetAPIKey(key string) { +} + func (t *Translator) GetAllLang() []string { return lang } diff --git a/internal/translate/chatgpt/language.go b/internal/translate/chatgpt/language.go new file mode 100644 index 0000000..ebfa048 --- /dev/null +++ b/internal/translate/chatgpt/language.go @@ -0,0 +1,130 @@ +package chatgpt + +var ( + // Generated from Bing + lang = []string{ + "Afrikaans", + "Albanian", + "Amharic", + "Auto", + "Arabic", + "Armenian", + "Assamese", + "Azerbaijani", + "Bangla", + "Bashkir", + "Basque", + "Bosnian", + "Bulgarian", + "Cantonese (Traditional)", + "Catalan", + "Chinese (Literary)", + "Chinese Simplified", + "Chinese Traditional", + "Croatian", + "Czech", + "Danish", + "Dari", + "Divehi", + "Dutch", + "English", + "Estonian", + "Faroese", + "Fijian", + "Filipino", + "Finnish", + "French", + "French (Canada)", + "Galician", + "Ganda", + "Georgian", + "German", + "Greek", + "Gujarati", + "Haitian Creole", + "Hausa", + "Hebrew", + "Hindi", + "Hmong Daw", + "Hungarian", + "Icelandic", + "Igbo", + "Indonesian", + "Inuinnaqtun", + "Inuktitut", + "Inuktitut (Latin)", + "Irish", + "Italian", + "Japanese", + "Kannada", + "Kazakh", + "Khmer", + "Kinyarwanda", + "Klingon (Latin)", + "Korean", + "Kurdish (Central)", + "Kurdish (Northern)", + "Kyrgyz", + "Lao", + "Latvian", + "Lingala", + "Lithuanian", + "Macedonian", + "Malagasy", + "Malay", + "Malayalam", + "Maltese", + "Marathi", + "Mongolian (Cyrillic)", + "Mongolian (Traditional)", + "Myanmar (Burmese)", + "Māori", + "Nepali", + "Norwegian", + "Nyanja", + "Odia", + "Pashto", + "Persian", + "Polish", + "Portuguese (Brazil)", + "Portuguese (Portugal)", + "Punjabi", + "Querétaro Otomi", + "Romanian", + "Rundi", + "Russian", + "Samoan", + "Serbian (Cyrillic)", + "Serbian (Latin)", + "Sesotho", + "Sesotho sa Leboa", + "Setswana", + "Shona", + "Slovak", + "Slovenian", + "Somali", + "Spanish", + "Swahili", + "Swedish", + "Tahitian", + "Tamil", + "Tatar", + "Telugu", + "Thai", + "Tibetan", + "Tigrinya", + "Tongan", + "Turkish", + "Turkmen", + "Ukrainian", + "Urdu", + "Uyghur", + "Uzbek (Latin)", + "Vietnamese", + "Welsh", + "Xhosa", + "Yoruba", + "Yucatec Maya", + "Zulu", + } +) diff --git a/internal/translate/chatgpt/translator.go b/internal/translate/chatgpt/translator.go new file mode 100644 index 0000000..fb68180 --- /dev/null +++ b/internal/translate/chatgpt/translator.go @@ -0,0 +1,94 @@ +package chatgpt + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + + "github.com/eeeXun/gtt/internal/translate/core" +) + +const ( + textURL = "https://api.openai.com/v1/chat/completions" +) + +type Translator struct { + *core.Language + *core.TTSLock + core.EngineName + apiKey string +} + +func NewTranslator() *Translator { + return &Translator{ + Language: new(core.Language), + TTSLock: core.NewTTSLock(), + EngineName: core.NewEngineName("ChatGPT"), + } +} + +func (t *Translator) SetAPIKey(key string) { + t.apiKey = key +} + +func (t *Translator) GetAllLang() []string { + return lang +} + +func (t *Translator) Translate(message string) (translation *core.Translation, err error) { + translation = new(core.Translation) + var data map[string]interface{} + + if len(t.apiKey) <= 0 { + return nil, errors.New("Please set API Key in config file for " + t.GetEngineName()) + } + + userData, _ := json.Marshal(map[string]interface{}{ + "model": "gpt-3.5-turbo", + "messages": []map[string]string{{ + "role": "user", + "content": fmt.Sprintf( + "Translate following text from %s to %s\n%s", + t.GetSrcLang(), + t.GetDstLang(), + message, + ), + }}, + "temperature": 0.7, + }) + req, _ := http.NewRequest("POST", + textURL, + bytes.NewBuffer(userData), + ) + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Authorization", "Bearer "+t.apiKey) + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + if err = json.Unmarshal(body, &data); err != nil { + return nil, err + } + + if len(data) <= 0 { + return nil, errors.New("Translation not found") + } + + translation.TEXT = + data["choices"].([]interface{})[0].(map[string]interface{})["message"].(map[string]interface{})["content"].(string) + + return translation, nil +} + +func (t *Translator) PlayTTS(lang, message string) error { + defer t.ReleaseLock() + + return errors.New(t.GetEngineName() + " does not support text to speech") +} diff --git a/internal/translate/google/translator.go b/internal/translate/google/translator.go index e0246ae..acca491 100644 --- a/internal/translate/google/translator.go +++ b/internal/translate/google/translator.go @@ -33,6 +33,9 @@ func NewTranslator() *Translator { } } +func (t *Translator) SetAPIKey(key string) { +} + func (t *Translator) GetAllLang() []string { return lang } diff --git a/internal/translate/reverso/translator.go b/internal/translate/reverso/translator.go index 0fe3bd7..97324a5 100644 --- a/internal/translate/reverso/translator.go +++ b/internal/translate/reverso/translator.go @@ -35,6 +35,9 @@ func NewTranslator() *Translator { } } +func (t *Translator) SetAPIKey(key string) { +} + func (t *Translator) GetAllLang() []string { return lang } diff --git a/internal/translate/translator.go b/internal/translate/translator.go index 708f2fb..4fa6aa4 100644 --- a/internal/translate/translator.go +++ b/internal/translate/translator.go @@ -4,6 +4,7 @@ import ( "github.com/eeeXun/gtt/internal/translate/apertium" "github.com/eeeXun/gtt/internal/translate/argos" "github.com/eeeXun/gtt/internal/translate/bing" + "github.com/eeeXun/gtt/internal/translate/chatgpt" "github.com/eeeXun/gtt/internal/translate/core" "github.com/eeeXun/gtt/internal/translate/google" "github.com/eeeXun/gtt/internal/translate/reverso" @@ -14,6 +15,7 @@ var ( "Apertium", "Argos", "Bing", + "ChatGPT", "Google", "Reverso", } @@ -41,6 +43,9 @@ type Translator interface { // Swap source and destination language of the translator SwapLang() + // Set API Key + SetAPIKey(key string) + // Check if lock is available LockAvailable() bool @@ -67,6 +72,8 @@ func NewTranslator(name string) Translator { translator = argos.NewTranslator() case "Bing": translator = bing.NewTranslator() + case "ChatGPT": + translator = chatgpt.NewTranslator() case "Google": translator = google.NewTranslator() case "Reverso":