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 @@
+
+
+
+