diff --git a/app_chatgpt/i18n/zh_CN.po b/app_chatgpt/i18n/zh_CN.po index 53f4aa0a..3f170f4a 100644 --- a/app_chatgpt/i18n/zh_CN.po +++ b/app_chatgpt/i18n/zh_CN.po @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 16.0+e-20230213\n" +"Project-Id-Version: Odoo Server 16.0+e-20230320\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-02 10:08+0000\n" -"PO-Revision-Date: 2023-03-02 10:08+0000\n" +"POT-Creation-Date: 2023-03-29 07:58+0000\n" +"PO-Revision-Date: 2023-03-29 07:58+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -15,6 +15,21 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: app_chatgpt +#: model:ir.model.fields,help:app_chatgpt.field_ai_robot__ai_model +msgid "" +"\n" +"GPT-4: Can understand Image, generate natural language or code.\n" +"GPT-3.5: A set of models that improve on GPT-3 and can understand as well as generate natural language or code\n" +"DALL·E: A model that can generate and edit images given a natural language prompt\n" +"Whisper: A model that can convert audio into text\n" +"Embeddings:\tA set of models that can convert text into a numerical form\n" +"CodexLimited: A set of models that can understand and generate code, including translating natural language to code\n" +"Moderation: A fine-tuned model that can detect whether text may be sensitive or unsafe\n" +"GPT-3\tA set of models that can understand and generate natural language\n" +" " +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -405,6 +420,16 @@ msgstr "" msgid "ABCD" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__ai_model +msgid "AI Model" +msgstr "" + +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__provider +msgid "AI Provider" +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -414,11 +439,14 @@ msgstr "" #. module: app_chatgpt #: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__openapi_api_key -#: model:ir.model.fields,field_description:app_chatgpt.field_res_config_settings__openapi_api_key -#: model_terms:ir.ui.view,arch_db:app_chatgpt.is_res_config_settings_view msgid "API Key" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__api_version +msgid "API Version" +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -510,6 +538,11 @@ msgstr "" msgid "Australia" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__provider__azure +msgid "Azure" +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -619,6 +652,11 @@ msgstr "" msgid "ChatGPT" msgstr "" +#. module: app_chatgpt +#: model:ai.robot,name:app_chatgpt.chatgpt_robot3 +msgid "ChatGPT Azure" +msgstr "" + #. module: app_chatgpt #: model:ai.robot,name:app_chatgpt.chatgpt_robot1 msgid "ChatGPT Coding" @@ -648,6 +686,36 @@ msgstr "" msgid "ChatGpt Training" msgstr "ChatGpt训练" +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__ai_model__code-davinci-002 +msgid "Chatgpt 2 Code Optimized" +msgstr "" + +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__ai_model__text-davinci-002 +msgid "Chatgpt 2 Davinci" +msgstr "" + +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__ai_model__text-davinci-003 +msgid "Chatgpt 3 Davinci" +msgstr "" + +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__ai_model__gpt-3_5-turbo +msgid "Chatgpt 3.5 Turbo" +msgstr "" + +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__ai_model__gpt-3_5-turbo-0301 +msgid "Chatgpt 3.5 Turbo on 20230301" +msgstr "" + +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__ai_model__gpt-4 +msgid "Chatgpt 4" +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -710,6 +778,11 @@ msgstr "" msgid "DVD" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__ai_model__dall-e2 +msgid "Dall-E Image" +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -764,6 +837,16 @@ msgstr "" msgid "END arrow" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__endpoint +msgid "End Point" +msgstr "" + +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__engine +msgid "Engine" +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -822,6 +905,11 @@ msgstr "" msgid "Ferris" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__is_filtering +msgid "Filter Sensitive Words" +msgstr "是否启用敏感词过滤" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -917,6 +1005,11 @@ msgstr "" msgid "ILY" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields,help:app_chatgpt.field_ai_robot__engine +msgid "If use Azure, Please input the Model deployment name." +msgstr "" + #. module: app_chatgpt #. odoo-javascript #: code:addons/app_chatgpt/static/src/models_data/emoji_data.js:0 @@ -1244,6 +1337,11 @@ msgstr "" msgid "Mahjong red dragon" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__max_length +msgid "Max Length" +msgstr "" + #. module: app_chatgpt #: model:ir.model,name:app_chatgpt.model_mail_message msgid "Message" @@ -1436,8 +1534,13 @@ msgid "Objects" msgstr "" #. module: app_chatgpt -#: model_terms:ir.ui.view,arch_db:app_chatgpt.is_res_config_settings_view -msgid "OpenAPI API Key" +#: model:ir.model.fields.selection,name:app_chatgpt.selection__ai_robot__provider__openai +msgid "OpenAI" +msgstr "" + +#. module: app_chatgpt +#: model_terms:ir.ui.view,arch_db:app_chatgpt.ai_robot_form_view +msgid "OpenAI Document" msgstr "" #. module: app_chatgpt @@ -1487,9 +1590,22 @@ msgstr "" msgid "Pisces" msgstr "" +#. module: app_chatgpt +#. odoo-python +#: code:addons/app_chatgpt/models/ai_robot.py:0 +#, python-format +msgid "Please Set your AI robot's API Version first." +msgstr "" + +#. module: app_chatgpt +#. odoo-python +#: code:addons/app_chatgpt/models/ai_robot.py:0 +#, python-format +msgid "Please Set your AI robot's endpoint first." +msgstr "" + #. module: app_chatgpt #: model:ir.model.fields,help:app_chatgpt.field_ai_robot__openapi_api_key -#: model:ir.model.fields,help:app_chatgpt.field_res_config_settings__openapi_api_key msgid "Provide the API key here" msgstr "" @@ -1582,6 +1698,16 @@ msgstr "" msgid "Selected Users" msgstr "" +#. module: app_chatgpt +#: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__sensitive_words +msgid "Sensitive Words" +msgstr "敏感词" + +#. module: app_chatgpt +#: model:ir.model.fields,help:app_chatgpt.field_ai_robot__sensitive_words +msgid "Sensitive word filtering. Separate keywords with a carriage return." +msgstr "敏感词过滤。请用回车符分隔关键词。" + #. module: app_chatgpt #: model:ir.model.fields,field_description:app_chatgpt.field_ai_robot__sequence msgid "Sequence" @@ -1805,7 +1931,7 @@ msgstr "" #. module: app_chatgpt #: model:ir.model,name:app_chatgpt.model_res_users msgid "User" -msgstr "用户" +msgstr "" #. module: app_chatgpt #. odoo-javascript diff --git a/app_chatgpt/models/ai_robot.py b/app_chatgpt/models/ai_robot.py index 8d863317..0259218e 100644 --- a/app_chatgpt/models/ai_robot.py +++ b/app_chatgpt/models/ai_robot.py @@ -4,10 +4,12 @@ import requests import openai from odoo import api, fields, models, _ from odoo.exceptions import UserError +from .lib.WordsSearch import WordsSearch import logging _logger = logging.getLogger(__name__) + class AiRobot(models.Model): _name = 'ai.robot' _description = 'Gpt Robot' @@ -41,6 +43,8 @@ GPT-3 A set of models that can understand and generate natural language engine = fields.Char('Engine', help='If use Azure, Please input the Model deployment name.') api_version = fields.Char('API Version', default='2022-12-01') sequence = fields.Integer('Sequence', help="Determine the display order", default=10) + sensitive_words = fields.Text('Sensitive Words', help='Sensitive word filtering. Separate keywords with a carriage return.') + is_filtering = fields.Boolean('Filter Sensitive Words', default=False) def action_disconnect(self): requests.delete('https://chatgpt.com/v1/disconnect') @@ -68,6 +72,7 @@ GPT-3 A set of models that can understand and generate natural language _logger.warning('=====================azure input data: %s' % data) if 'choices' in response: res = response['choices'][0]['text'].replace(' .', '.').strip() + res = self.filter_sensitive_words(res) return res @api.onchange('provider') @@ -77,3 +82,10 @@ GPT-3 A set of models that can understand and generate natural language elif self.provider == 'azure': self.endpoint = 'https://odoo.openai.azure.com' + def filter_sensitive_words(self, data): + if self.is_filtering: + search = WordsSearch() + s = self.sensitive_words + search.SetKeywords(s.split('\n')) + result = search.Replace(text=data) + return result diff --git a/app_chatgpt/models/lib/WordsSearch.py b/app_chatgpt/models/lib/WordsSearch.py new file mode 100644 index 00000000..02c16410 --- /dev/null +++ b/app_chatgpt/models/lib/WordsSearch.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# ToolGood.Words.WordsSearch.py +# 2020, Lin Zhijun, https://github.com/toolgood/ToolGood.Words +# Licensed under the Apache License 2.0 +# 更新日志 +# 2020.04.06 第一次提交 +# 2020.05.16 修改,支持大于0xffff的字符 + +__all__ = ['WordsSearch'] +__author__ = 'Lin Zhijun' +__date__ = '2020.05.16' + + +class TrieNode(): + def __init__(self): + self.Index = 0 + self.Index = 0 + self.Layer = 0 + self.End = False + self.Char = '' + self.Results = [] + self.m_values = {} + self.Failure = None + self.Parent = None + + def Add(self, c): + if c in self.m_values: + return self.m_values[c] + node = TrieNode() + node.Parent = self + node.Char = c + self.m_values[c] = node + return node + + def SetResults(self, index): + if (self.End == False): + self.End = True + self.Results.append(index) + + +class TrieNode2(): + def __init__(self): + self.End = False + self.Results = [] + self.m_values = {} + self.minflag = 0xffff + self.maxflag = 0 + + def Add(self, c, node3): + if (self.minflag > c): + self.minflag = c + if (self.maxflag < c): + self.maxflag = c + self.m_values[c] = node3 + + def SetResults(self, index): + if (self.End == False): + self.End = True + if (index in self.Results) == False: + self.Results.append(index) + + def HasKey(self, c): + return c in self.m_values + + def TryGetValue(self, c): + if (self.minflag <= c and self.maxflag >= c): + if c in self.m_values: + return self.m_values[c] + return None + + +class WordsSearch(): + def __init__(self): + self._first = {} + self._keywords = [] + self._indexs = [] + + def SetKeywords(self, keywords): + self._keywords = keywords + self._indexs = [] + for i in range(len(keywords)): + self._indexs.append(i) + + root = TrieNode() + allNodeLayer = {} + + for i in range(len(self._keywords)): # for (i = 0; i < _keywords.length; i++) + p = self._keywords[i] + nd = root + for j in range(len(p)): # for (j = 0; j < p.length; j++) + nd = nd.Add(ord(p[j])) + if (nd.Layer == 0): + nd.Layer = j + 1 + if nd.Layer in allNodeLayer: + allNodeLayer[nd.Layer].append(nd) + else: + allNodeLayer[nd.Layer] = [] + allNodeLayer[nd.Layer].append(nd) + nd.SetResults(i) + + allNode = [] + allNode.append(root) + for key in allNodeLayer.keys(): + for nd in allNodeLayer[key]: + allNode.append(nd) + allNodeLayer = None + + for i in range(len(allNode)): # for (i = 0; i < allNode.length; i++) + if i == 0: + continue + nd = allNode[i] + nd.Index = i + r = nd.Parent.Failure + c = nd.Char + while (r != None and (c in r.m_values) == False): + r = r.Failure + if (r == None): + nd.Failure = root + else: + nd.Failure = r.m_values[c] + for key2 in nd.Failure.Results: + nd.SetResults(key2) + root.Failure = root + + allNode2 = [] + for i in range(len(allNode)): # for (i = 0; i < allNode.length; i++) + allNode2.append(TrieNode2()) + + for i in range(len(allNode2)): # for (i = 0; i < allNode2.length; i++) + oldNode = allNode[i] + newNode = allNode2[i] + + for key in oldNode.m_values: + index = oldNode.m_values[key].Index + newNode.Add(key, allNode2[index]) + + for index in range(len(oldNode.Results)): # for (index = 0; index < oldNode.Results.length; index++) + item = oldNode.Results[index] + newNode.SetResults(item) + + oldNode = oldNode.Failure + while oldNode != root: + for key in oldNode.m_values: + if (newNode.HasKey(key) == False): + index = oldNode.m_values[key].Index + newNode.Add(key, allNode2[index]) + for index in range(len(oldNode.Results)): + item = oldNode.Results[index] + newNode.SetResults(item) + oldNode = oldNode.Failure + allNode = None + root = None + + # first = [] + # for index in range(65535):# for (index = 0; index < 0xffff; index++) + # first.append(None) + + # for key in allNode2[0].m_values : + # first[key] = allNode2[0].m_values[key] + + self._first = allNode2[0] + + def FindFirst(self, text): + ptr = None + for index in range(len(text)): # for (index = 0; index < text.length; index++) + t = ord(text[index]) # text.charCodeAt(index) + tn = None + if (ptr == None): + tn = self._first.TryGetValue(t) + else: + tn = ptr.TryGetValue(t) + if (tn == None): + tn = self._first.TryGetValue(t) + + if (tn != None): + if (tn.End): + item = tn.Results[0] + keyword = self._keywords[item] + return {"Keyword": keyword, "Success": True, "End": index, "Start": index + 1 - len(keyword), "Index": self._indexs[item]} + ptr = tn + return None + + def FindAll(self, text): + ptr = None + list = [] + + for index in range(len(text)): # for (index = 0; index < text.length; index++) + t = ord(text[index]) # text.charCodeAt(index) + tn = None + if (ptr == None): + tn = self._first.TryGetValue(t) + else: + tn = ptr.TryGetValue(t) + if (tn == None): + tn = self._first.TryGetValue(t) + + if (tn != None): + if (tn.End): + for j in range(len(tn.Results)): # for (j = 0; j < tn.Results.length; j++) + item = tn.Results[j] + keyword = self._keywords[item] + list.append({"Keyword": keyword, "Success": True, "End": index, "Start": index + 1 - len(keyword), "Index": self._indexs[item]}) + ptr = tn + return list + + def ContainsAny(self, text): + ptr = None + for index in range(len(text)): # for (index = 0; index < text.length; index++) + t = ord(text[index]) # text.charCodeAt(index) + tn = None + if (ptr == None): + tn = self._first.TryGetValue(t) + else: + tn = ptr.TryGetValue(t) + if (tn == None): + tn = self._first.TryGetValue(t) + + if (tn != None): + if (tn.End): + return True + ptr = tn + return False + + def Replace(self, text, replaceChar='*'): + result = list(text) + + ptr = None + for i in range(len(text)): # for (i = 0; i < text.length; i++) + t = ord(text[i]) # text.charCodeAt(index) + tn = None + if (ptr == None): + tn = self._first.TryGetValue(t) + else: + tn = ptr.TryGetValue(t) + if (tn == None): + tn = self._first.TryGetValue(t) + + if (tn != None): + if (tn.End): + maxLength = len(self._keywords[tn.Results[0]]) + start = i + 1 - maxLength + for j in range(start, i + 1): # for (j = start; j <= i; j++) + result[j] = replaceChar + ptr = tn + return ''.join(result) + + +if __name__ == "__main__": + s = "中国|国人|zg人|乾清宫" + test = "我是中国人" + + search = WordsSearch() + search.SetKeywords(s.split('|')) + + print("----------------------------------- WordsSearch -----------------------------------") + + print("WordsSearch FindFirst is run.") + f = search.FindFirst(test) + if f["Keyword"] != "中国": + print("WordsSearch FindFirst is error.............................") + + print("WordsSearch FindFirst is run.") + all = search.FindAll("乾清宫") + if all[0]["Keyword"] != "乾清宫": + print("WordsSearch FindFirst is error.............................") + + print("WordsSearch FindAll is run.") + all = search.FindAll(test) + if all[0]["Keyword"] != "中国": + print("WordsSearch FindAll is error.............................") + if all[1]["Keyword"] != "国人": + print("WordsSearch FindAll is error.............................") + if all[0]["Start"] != 2: + print("WordsSearch FindAll is error.............................") + if all[0]["End"] != 3: + print("WordsSearch FindAll is error.............................") + if len(all) != 2: + print("WordsSearch FindAll is error.............................") + + print("WordsSearch ContainsAny is run.") + b = search.ContainsAny(test) + if b == False: + print("WordsSearch ContainsAny is error.............................") + + print("WordsSearch Replace is run.") + txt = search.Replace(test) + if (txt != "我是***"): + print("WordsSearch Replace is error.............................") + + print("----------------------------------- Test End -----------------------------------") \ No newline at end of file diff --git a/app_chatgpt/views/ai_robot_views.xml b/app_chatgpt/views/ai_robot_views.xml index 017010c8..735934d0 100644 --- a/app_chatgpt/views/ai_robot_views.xml +++ b/app_chatgpt/views/ai_robot_views.xml @@ -43,6 +43,10 @@ + + + +