diff --git a/ai/ai.go b/ai/ai.go deleted file mode 100644 index 264a9600..00000000 --- a/ai/ai.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ai - -import ( - "context" - "fmt" - "io" - "net/http" - "strings" - "time" - - "github.com/sashabaranov/go-openai" -) - -func queryAnswer(authToken string, question string, timeout int) (string, error) { - // fmt.Printf("Question: %s\n", question) - - client := getProxyClientFromToken(authToken) - - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(2+timeout*2)*time.Second) - defer cancel() - - resp, err := client.CreateChatCompletion( - ctx, - openai.ChatCompletionRequest{ - Model: openai.GPT3Dot5Turbo, - Messages: []openai.ChatCompletionMessage{ - { - Role: openai.ChatMessageRoleUser, - Content: question, - }, - }, - }, - ) - if err != nil { - return "", err - } - - res := resp.Choices[0].Message.Content - res = strings.Trim(res, "\n") - // fmt.Printf("Answer: %s\n\n", res) - return res, nil -} - -func QueryAnswerSafe(authToken string, question string) string { - var res string - var err error - for i := 0; i < 10; i++ { - res, err = queryAnswer(authToken, question, i) - if err != nil { - if i > 0 { - fmt.Printf("\tFailed (%d): %s\n", i+1, err.Error()) - } - } else { - break - } - } - if err != nil { - panic(err) - } - - return res -} - -func QueryAnswerStream(authToken string, question string, writer io.Writer, builder *strings.Builder) error { - client := getProxyClientFromToken(authToken) - - ctx := context.Background() - flusher, ok := writer.(http.Flusher) - if !ok { - return fmt.Errorf("writer does not implement http.Flusher") - } - // https://platform.openai.com/tokenizer - // https://github.com/pkoukk/tiktoken-go#available-encodings - promptTokens, err := getTokenSize(openai.GPT3TextDavinci003, question) - if err != nil { - return err - } - - // https://platform.openai.com/docs/models/gpt-3-5 - maxTokens := 4097 - promptTokens - - respStream, err := client.CreateCompletionStream( - ctx, - openai.CompletionRequest{ - Model: openai.GPT3TextDavinci003, - Prompt: question, - MaxTokens: maxTokens, - Stream: true, - }, - ) - if err != nil { - return err - } - defer respStream.Close() - - isLeadingReturn := true - for { - completion, streamErr := respStream.Recv() - if streamErr != nil { - if streamErr == io.EOF { - break - } - return streamErr - } - - data := completion.Choices[0].Text - if isLeadingReturn && len(data) != 0 { - if strings.Count(data, "\n") == len(data) { - continue - } else { - isLeadingReturn = false - } - } - - fmt.Printf("%s", data) - - // Write the streamed data as Server-Sent Events - if _, err = fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil { - return err - } - flusher.Flush() - // Append the response to the strings.Builder - builder.WriteString(data) - } - - return nil -} diff --git a/ai/ai_test.go b/ai/ai_test.go deleted file mode 100644 index 975cdd58..00000000 --- a/ai/ai_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !skipCi -// +build !skipCi - -package ai - -import ( - "testing" - - "github.com/casdoor/casdoor/object" - "github.com/casdoor/casdoor/proxy" - "github.com/sashabaranov/go-openai" -) - -func TestRun(t *testing.T) { - object.InitConfig() - proxy.InitHttpClient() - - text, err := queryAnswer("", "hi", 5) - if err != nil { - panic(err) - } - - println(text) -} - -func TestToken(t *testing.T) { - println(getTokenSize(openai.GPT3TextDavinci003, "")) -} diff --git a/ai/proxy.go b/ai/proxy.go deleted file mode 100644 index 84c5c981..00000000 --- a/ai/proxy.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ai - -import ( - "github.com/casdoor/casdoor/proxy" - "github.com/sashabaranov/go-openai" -) - -func getProxyClientFromToken(authToken string) *openai.Client { - config := openai.DefaultConfig(authToken) - config.HTTPClient = proxy.ProxyHttpClient - - c := openai.NewClientWithConfig(config) - return c -} diff --git a/ai/util.go b/ai/util.go deleted file mode 100644 index e0f1085f..00000000 --- a/ai/util.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ai - -import "github.com/pkoukk/tiktoken-go" - -func getTokenSize(model string, prompt string) (int, error) { - tkm, err := tiktoken.EncodingForModel(model) - if err != nil { - return 0, err - } - - token := tkm.Encode(prompt, nil, nil) - res := len(token) - return res, nil -} diff --git a/controllers/chat.go b/controllers/chat.go deleted file mode 100644 index c0911386..00000000 --- a/controllers/chat.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package controllers - -import ( - "encoding/json" - - "github.com/beego/beego/utils/pagination" - "github.com/casdoor/casdoor/object" - "github.com/casdoor/casdoor/util" -) - -// GetChats -// @Title GetChats -// @Tag Chat API -// @Description get chats -// @Param owner query string true "The owner of chats" -// @Success 200 {array} object.Chat The Response object -// @router /get-chats [get] -func (c *ApiController) GetChats() { - owner := "admin" - limit := c.Input().Get("pageSize") - page := c.Input().Get("p") - field := c.Input().Get("field") - value := c.Input().Get("value") - sortField := c.Input().Get("sortField") - sortOrder := c.Input().Get("sortOrder") - - if limit == "" || page == "" { - maskedChats, err := object.GetMaskedChats(object.GetChats(owner)) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.ResponseOk(maskedChats) - } else { - limit := util.ParseInt(limit) - count, err := object.GetChatCount(owner, field, value) - if err != nil { - c.ResponseError(err.Error()) - return - } - - paginator := pagination.SetPaginator(c.Ctx, limit, count) - chats, err := object.GetMaskedChats(object.GetPaginationChats(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.ResponseOk(chats, paginator.Nums()) - } -} - -// GetChat -// @Title GetChat -// @Tag Chat API -// @Description get chat -// @Param id query string true "The id ( owner/name ) of the chat" -// @Success 200 {object} object.Chat The Response object -// @router /get-chat [get] -func (c *ApiController) GetChat() { - id := c.Input().Get("id") - - maskedChat, err := object.GetMaskedChat(object.GetChat(id)) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.ResponseOk(maskedChat) -} - -// UpdateChat -// @Title UpdateChat -// @Tag Chat API -// @Description update chat -// @Param id query string true "The id ( owner/name ) of the chat" -// @Param body body object.Chat true "The details of the chat" -// @Success 200 {object} controllers.Response The Response object -// @router /update-chat [post] -func (c *ApiController) UpdateChat() { - id := c.Input().Get("id") - - var chat object.Chat - err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.Data["json"] = wrapActionResponse(object.UpdateChat(id, &chat)) - c.ServeJSON() -} - -// AddChat -// @Title AddChat -// @Tag Chat API -// @Description add chat -// @Param body body object.Chat true "The details of the chat" -// @Success 200 {object} controllers.Response The Response object -// @router /add-chat [post] -func (c *ApiController) AddChat() { - var chat object.Chat - err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.Data["json"] = wrapActionResponse(object.AddChat(&chat)) - c.ServeJSON() -} - -// DeleteChat -// @Title DeleteChat -// @Tag Chat API -// @Description delete chat -// @Param body body object.Chat true "The details of the chat" -// @Success 200 {object} controllers.Response The Response object -// @router /delete-chat [post] -func (c *ApiController) DeleteChat() { - var chat object.Chat - err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.Data["json"] = wrapActionResponse(object.DeleteChat(&chat)) - c.ServeJSON() -} diff --git a/controllers/message.go b/controllers/message.go deleted file mode 100644 index 79a5b367..00000000 --- a/controllers/message.go +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package controllers - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/beego/beego/utils/pagination" - "github.com/casdoor/casdoor/ai" - "github.com/casdoor/casdoor/object" - "github.com/casdoor/casdoor/util" -) - -// GetMessages -// @Title GetMessages -// @Tag Message API -// @Description get messages -// @Param owner query string true "The owner of messages" -// @Success 200 {array} object.Message The Response object -// @router /get-messages [get] -func (c *ApiController) GetMessages() { - owner := c.Input().Get("owner") - organization := c.Input().Get("organization") - limit := c.Input().Get("pageSize") - page := c.Input().Get("p") - field := c.Input().Get("field") - value := c.Input().Get("value") - sortField := c.Input().Get("sortField") - sortOrder := c.Input().Get("sortOrder") - chat := c.Input().Get("chat") - - if limit == "" || page == "" { - var messages []*object.Message - var err error - if chat == "" { - messages, err = object.GetMessages(owner) - } else { - messages, err = object.GetChatMessages(chat) - } - - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.ResponseOk(object.GetMaskedMessages(messages)) - } else { - limit := util.ParseInt(limit) - count, err := object.GetMessageCount(owner, organization, field, value) - if err != nil { - c.ResponseError(err.Error()) - return - } - - paginator := pagination.SetPaginator(c.Ctx, limit, count) - paginationMessages, err := object.GetPaginationMessages(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder) - if err != nil { - c.ResponseError(err.Error()) - return - } - - messages := object.GetMaskedMessages(paginationMessages) - c.ResponseOk(messages, paginator.Nums()) - } -} - -// GetMessage -// @Title GetMessage -// @Tag Message API -// @Description get message -// @Param id query string true "The id ( owner/name ) of the message" -// @Success 200 {object} object.Message The Response object -// @router /get-message [get] -func (c *ApiController) GetMessage() { - id := c.Input().Get("id") - message, err := object.GetMessage(id) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.ResponseOk(message) -} - -func (c *ApiController) ResponseErrorStream(errorText string) { - event := fmt.Sprintf("event: myerror\ndata: %s\n\n", errorText) - _, err := c.Ctx.ResponseWriter.Write([]byte(event)) - if err != nil { - c.ResponseError(err.Error()) - return - } -} - -// GetMessageAnswer -// @Title GetMessageAnswer -// @Tag Message API -// @Description get message answer -// @Param id query string true "The id ( owner/name ) of the message" -// @Success 200 {object} object.Message The Response object -// @router /get-message-answer [get] -func (c *ApiController) GetMessageAnswer() { - id := c.Input().Get("id") - - c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream") - c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache") - c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive") - - message, err := object.GetMessage(id) - if err != nil { - c.ResponseError(err.Error()) - return - } - - if message == nil { - c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The message: %s is not found"), id)) - return - } - - if message.Author != "AI" || message.ReplyTo == "" || message.Text != "" { - c.ResponseErrorStream(c.T("chat:The message is invalid")) - return - } - - chatId := util.GetId("admin", message.Chat) - chat, err := object.GetChat(chatId) - if err != nil { - c.ResponseError(err.Error()) - return - } - - if chat == nil || chat.Organization != message.Organization { - c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The chat: %s is not found"), chatId)) - return - } - - if chat.Type != "AI" { - c.ResponseErrorStream(c.T("chat:The chat type must be \"AI\"")) - return - } - - questionMessage, err := object.GetMessage(message.ReplyTo) - if questionMessage == nil { - c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The message: %s is not found"), id)) - return - } - - providerId := util.GetId(chat.Owner, chat.User2) - provider, err := object.GetProvider(providerId) - if err != nil { - c.ResponseError(err.Error()) - return - } - - if provider == nil { - c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The provider: %s is not found"), providerId)) - return - } - - if provider.Category != "AI" || provider.ClientSecret == "" { - c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The provider: %s is invalid"), providerId)) - return - } - - c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream") - c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache") - c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive") - - authToken := provider.ClientSecret - question := questionMessage.Text - var stringBuilder strings.Builder - - fmt.Printf("Question: [%s]\n", questionMessage.Text) - fmt.Printf("Answer: [") - - err = ai.QueryAnswerStream(authToken, question, c.Ctx.ResponseWriter, &stringBuilder) - if err != nil { - c.ResponseErrorStream(err.Error()) - return - } - - fmt.Printf("]\n") - - event := fmt.Sprintf("event: end\ndata: %s\n\n", "end") - _, err = c.Ctx.ResponseWriter.Write([]byte(event)) - if err != nil { - c.ResponseError(err.Error()) - return - } - - answer := stringBuilder.String() - - message.Text = answer - _, err = object.UpdateMessage(message.GetId(), message) - if err != nil { - c.ResponseError(err.Error()) - return - } -} - -// UpdateMessage -// @Title UpdateMessage -// @Tag Message API -// @Description update message -// @Param id query string true "The id ( owner/name ) of the message" -// @Param body body object.Message true "The details of the message" -// @Success 200 {object} controllers.Response The Response object -// @router /update-message [post] -func (c *ApiController) UpdateMessage() { - id := c.Input().Get("id") - - var message object.Message - err := json.Unmarshal(c.Ctx.Input.RequestBody, &message) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.Data["json"] = wrapActionResponse(object.UpdateMessage(id, &message)) - c.ServeJSON() -} - -// AddMessage -// @Title AddMessage -// @Tag Message API -// @Description add message -// @Param body body object.Message true "The details of the message" -// @Success 200 {object} controllers.Response The Response object -// @router /add-message [post] -func (c *ApiController) AddMessage() { - var message object.Message - err := json.Unmarshal(c.Ctx.Input.RequestBody, &message) - if err != nil { - c.ResponseError(err.Error()) - return - } - - var chat *object.Chat - if message.Chat != "" { - chatId := util.GetId("admin", message.Chat) - chat, err = object.GetChat(chatId) - if err != nil { - c.ResponseError(err.Error()) - return - } - - if chat == nil || chat.Organization != message.Organization { - c.ResponseError(fmt.Sprintf(c.T("chat:The chat: %s is not found"), chatId)) - return - } - } - - affected, err := object.AddMessage(&message) - if err != nil { - c.ResponseError(err.Error()) - return - } - - if affected { - if chat != nil && chat.Type == "AI" { - answerMessage := &object.Message{ - Owner: message.Owner, - Name: fmt.Sprintf("message_%s", util.GetRandomName()), - CreatedTime: util.GetCurrentTimeEx(message.CreatedTime), - Organization: message.Organization, - Chat: message.Chat, - ReplyTo: message.GetId(), - Author: "AI", - Text: "", - } - _, err = object.AddMessage(answerMessage) - if err != nil { - c.ResponseError(err.Error()) - return - } - } - } - - c.Data["json"] = wrapActionResponse(affected) - c.ServeJSON() -} - -// DeleteMessage -// @Title DeleteMessage -// @Tag Message API -// @Description delete message -// @Param body body object.Message true "The details of the message" -// @Success 200 {object} controllers.Response The Response object -// @router /delete-message [post] -func (c *ApiController) DeleteMessage() { - var message object.Message - err := json.Unmarshal(c.Ctx.Input.RequestBody, &message) - if err != nil { - c.ResponseError(err.Error()) - return - } - - c.Data["json"] = wrapActionResponse(object.DeleteMessage(&message)) - c.ServeJSON() -} diff --git a/i18n/locales/de/data.json b/i18n/locales/de/data.json index 1890f64c..4db0a4c1 100644 --- a/i18n/locales/de/data.json +++ b/i18n/locales/de/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Service %s und %s stimmen nicht überein" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein", "DisplayName cannot be blank": "Anzeigename kann nicht leer sein", diff --git a/i18n/locales/en/data.json b/i18n/locales/en/data.json index e9fbc0c7..7f57f35f 100644 --- a/i18n/locales/en/data.json +++ b/i18n/locales/en/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Service %s and %s do not match" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Affiliation cannot be blank", "DisplayName cannot be blank": "DisplayName cannot be blank", diff --git a/i18n/locales/es/data.json b/i18n/locales/es/data.json index dae65d40..12e8196a 100644 --- a/i18n/locales/es/data.json +++ b/i18n/locales/es/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Los servicios %s y %s no coinciden" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Afiliación no puede estar en blanco", "DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco", diff --git a/i18n/locales/fr/data.json b/i18n/locales/fr/data.json index 819af959..d9c6af3a 100644 --- a/i18n/locales/fr/data.json +++ b/i18n/locales/fr/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Les services %s et %s ne correspondent pas" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Affiliation ne peut pas être vide", "DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide", diff --git a/i18n/locales/id/data.json b/i18n/locales/id/data.json index af75f00e..d683126b 100644 --- a/i18n/locales/id/data.json +++ b/i18n/locales/id/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Layanan %s dan %s tidak cocok" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Keterkaitan tidak boleh kosong", "DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong", diff --git a/i18n/locales/ja/data.json b/i18n/locales/ja/data.json index 158518f8..87795d06 100644 --- a/i18n/locales/ja/data.json +++ b/i18n/locales/ja/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "サービス%sと%sは一致しません" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "所属は空白にできません", "DisplayName cannot be blank": "表示名は空白にできません", diff --git a/i18n/locales/ko/data.json b/i18n/locales/ko/data.json index b9aec68d..472388ae 100644 --- a/i18n/locales/ko/data.json +++ b/i18n/locales/ko/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "소속은 비워 둘 수 없습니다", "DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다", diff --git a/i18n/locales/pt/data.json b/i18n/locales/pt/data.json index e9fbc0c7..7f57f35f 100644 --- a/i18n/locales/pt/data.json +++ b/i18n/locales/pt/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Service %s and %s do not match" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Affiliation cannot be blank", "DisplayName cannot be blank": "DisplayName cannot be blank", diff --git a/i18n/locales/ru/data.json b/i18n/locales/ru/data.json index a5a06062..d4baa1f8 100644 --- a/i18n/locales/ru/data.json +++ b/i18n/locales/ru/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Сервисы %s и %s не совпадают" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Принадлежность не может быть пустым значением", "DisplayName cannot be blank": "Имя отображения не может быть пустым", diff --git a/i18n/locales/vi/data.json b/i18n/locales/vi/data.json index 2d9ef037..7652ad1d 100644 --- a/i18n/locales/vi/data.json +++ b/i18n/locales/vi/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "Dịch sang tiếng Việt: Dịch vụ %s và %s không khớp" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "Tình trạng liên kết không thể để trống", "DisplayName cannot be blank": "Tên hiển thị không thể để trống", diff --git a/i18n/locales/zh/data.json b/i18n/locales/zh/data.json index 9f2fe781..578995e8 100644 --- a/i18n/locales/zh/data.json +++ b/i18n/locales/zh/data.json @@ -24,14 +24,6 @@ "cas": { "Service %s and %s do not match": "服务%s与%s不匹配" }, - "chat": { - "The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"", - "The chat: %s is not found": "The chat: %s is not found", - "The message is invalid": "The message is invalid", - "The message: %s is not found": "The message: %s is not found", - "The provider: %s is invalid": "The provider: %s is invalid", - "The provider: %s is not found": "The provider: %s is not found" - }, "check": { "Affiliation cannot be blank": "工作单位不可为空", "DisplayName cannot be blank": "显示名称不可为空", diff --git a/object/chat.go b/object/chat.go deleted file mode 100644 index 8b53a7f7..00000000 --- a/object/chat.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package object - -import ( - "fmt" - - "github.com/casdoor/casdoor/util" - "github.com/xorm-io/core" -) - -type Chat struct { - Owner string `xorm:"varchar(100) notnull pk" json:"owner"` - Name string `xorm:"varchar(100) notnull pk" json:"name"` - CreatedTime string `xorm:"varchar(100)" json:"createdTime"` - UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"` - - Organization string `xorm:"varchar(100)" json:"organization"` - DisplayName string `xorm:"varchar(100)" json:"displayName"` - Type string `xorm:"varchar(100)" json:"type"` - Category string `xorm:"varchar(100)" json:"category"` - User1 string `xorm:"varchar(100)" json:"user1"` - User2 string `xorm:"varchar(100)" json:"user2"` - Users []string `xorm:"varchar(100)" json:"users"` - MessageCount int `json:"messageCount"` -} - -func GetMaskedChat(chat *Chat, err ...error) (*Chat, error) { - if len(err) > 0 && err[0] != nil { - return nil, err[0] - } - - if chat == nil { - return nil, nil - } - - return chat, nil -} - -func GetMaskedChats(chats []*Chat, errs ...error) ([]*Chat, error) { - if len(errs) > 0 && errs[0] != nil { - return nil, errs[0] - } - var err error - for _, chat := range chats { - chat, err = GetMaskedChat(chat) - if err != nil { - return nil, err - } - } - return chats, nil -} - -func GetChatCount(owner, field, value string) (int64, error) { - session := GetSession(owner, -1, -1, field, value, "", "") - return session.Count(&Chat{}) -} - -func GetChats(owner string) ([]*Chat, error) { - chats := []*Chat{} - err := ormer.Engine.Desc("created_time").Find(&chats, &Chat{Owner: owner}) - if err != nil { - return chats, err - } - - return chats, nil -} - -func GetPaginationChats(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Chat, error) { - chats := []*Chat{} - session := GetSession(owner, offset, limit, field, value, sortField, sortOrder) - err := session.Find(&chats) - if err != nil { - return chats, err - } - - return chats, nil -} - -func getChat(owner string, name string) (*Chat, error) { - if owner == "" || name == "" { - return nil, nil - } - - chat := Chat{Owner: owner, Name: name} - existed, err := ormer.Engine.Get(&chat) - if err != nil { - return &chat, err - } - - if existed { - return &chat, nil - } else { - return nil, nil - } -} - -func GetChat(id string) (*Chat, error) { - owner, name := util.GetOwnerAndNameFromId(id) - return getChat(owner, name) -} - -func UpdateChat(id string, chat *Chat) (bool, error) { - owner, name := util.GetOwnerAndNameFromId(id) - if c, err := getChat(owner, name); err != nil { - return false, err - } else if c == nil { - return false, nil - } - - affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(chat) - if err != nil { - return false, nil - } - - return affected != 0, nil -} - -func AddChat(chat *Chat) (bool, error) { - if chat.Type == "AI" && chat.User2 == "" { - provider, err := getDefaultAiProvider() - if err != nil { - return false, err - } - - if provider != nil { - chat.User2 = provider.Name - } - } - - affected, err := ormer.Engine.Insert(chat) - if err != nil { - return false, nil - } - - return affected != 0, nil -} - -func DeleteChat(chat *Chat) (bool, error) { - affected, err := ormer.Engine.ID(core.PK{chat.Owner, chat.Name}).Delete(&Chat{}) - if err != nil { - return false, err - } - - if affected != 0 { - return DeleteChatMessages(chat.Name) - } - - return affected != 0, nil -} - -func (p *Chat) GetId() string { - return fmt.Sprintf("%s/%s", p.Owner, p.Name) -} diff --git a/object/message.go b/object/message.go deleted file mode 100644 index cef54fbe..00000000 --- a/object/message.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package object - -import ( - "fmt" - - "github.com/casdoor/casdoor/util" - "github.com/xorm-io/core" -) - -type Message struct { - Owner string `xorm:"varchar(100) notnull pk" json:"owner"` - Name string `xorm:"varchar(100) notnull pk" json:"name"` - CreatedTime string `xorm:"varchar(100)" json:"createdTime"` - - Organization string `xorm:"varchar(100)" json:"organization"` - Chat string `xorm:"varchar(100) index" json:"chat"` - ReplyTo string `xorm:"varchar(100) index" json:"replyTo"` - Author string `xorm:"varchar(100)" json:"author"` - Text string `xorm:"mediumtext" json:"text"` -} - -func GetMaskedMessage(message *Message) *Message { - if message == nil { - return nil - } - - return message -} - -func GetMaskedMessages(messages []*Message) []*Message { - for _, message := range messages { - message = GetMaskedMessage(message) - } - return messages -} - -func GetMessageCount(owner, organization, field, value string) (int64, error) { - session := GetSession(owner, -1, -1, field, value, "", "") - return session.Count(&Message{Organization: organization}) -} - -func GetMessages(owner string) ([]*Message, error) { - messages := []*Message{} - err := ormer.Engine.Desc("created_time").Find(&messages, &Message{Owner: owner}) - return messages, err -} - -func GetChatMessages(chat string) ([]*Message, error) { - messages := []*Message{} - err := ormer.Engine.Asc("created_time").Find(&messages, &Message{Chat: chat}) - return messages, err -} - -func GetPaginationMessages(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) ([]*Message, error) { - messages := []*Message{} - session := GetSession(owner, offset, limit, field, value, sortField, sortOrder) - err := session.Find(&messages, &Message{Organization: organization}) - return messages, err -} - -func getMessage(owner string, name string) (*Message, error) { - if owner == "" || name == "" { - return nil, nil - } - - message := Message{Owner: owner, Name: name} - existed, err := ormer.Engine.Get(&message) - if err != nil { - return nil, err - } - - if existed { - return &message, nil - } else { - return nil, nil - } -} - -func GetMessage(id string) (*Message, error) { - owner, name := util.GetOwnerAndNameFromId(id) - return getMessage(owner, name) -} - -func UpdateMessage(id string, message *Message) (bool, error) { - owner, name := util.GetOwnerAndNameFromId(id) - if m, err := getMessage(owner, name); err != nil { - return false, err - } else if m == nil { - return false, nil - } - - affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(message) - if err != nil { - return false, err - } - - return affected != 0, nil -} - -func AddMessage(message *Message) (bool, error) { - affected, err := ormer.Engine.Insert(message) - if err != nil { - return false, err - } - - return affected != 0, nil -} - -func DeleteMessage(message *Message) (bool, error) { - affected, err := ormer.Engine.ID(core.PK{message.Owner, message.Name}).Delete(&Message{}) - if err != nil { - return false, err - } - - return affected != 0, nil -} - -func DeleteChatMessages(chat string) (bool, error) { - affected, err := ormer.Engine.Delete(&Message{Chat: chat}) - if err != nil { - return false, err - } - - return affected != 0, nil -} - -func (p *Message) GetId() string { - return fmt.Sprintf("%s/%s", p.Owner, p.Name) -} diff --git a/object/ormer.go b/object/ormer.go index 8ecf78ed..0e5f199c 100644 --- a/object/ormer.go +++ b/object/ormer.go @@ -249,16 +249,6 @@ func (a *Ormer) createTable() { panic(err) } - err = a.Engine.Sync2(new(Chat)) - if err != nil { - panic(err) - } - - err = a.Engine.Sync2(new(Message)) - if err != nil { - panic(err) - } - err = a.Engine.Sync2(new(Product)) if err != nil { panic(err) diff --git a/object/provider.go b/object/provider.go index cf04fbcf..28650a46 100644 --- a/object/provider.go +++ b/object/provider.go @@ -182,20 +182,6 @@ func GetProvider(id string) (*Provider, error) { return getProvider(owner, name) } -func getDefaultAiProvider() (*Provider, error) { - provider := Provider{Owner: "admin", Category: "AI"} - existed, err := ormer.Engine.Get(&provider) - if err != nil { - return &provider, err - } - - if !existed { - return nil, nil - } - - return &provider, nil -} - func GetWechatMiniProgramProvider(application *Application) *Provider { providers := application.Providers for _, provider := range providers { diff --git a/routers/router.go b/routers/router.go index f7e7ad2a..44d0fc5b 100644 --- a/routers/router.go +++ b/routers/router.go @@ -211,19 +211,6 @@ func initAPI() { beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert") beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert") - beego.Router("/api/get-chats", &controllers.ApiController{}, "GET:GetChats") - beego.Router("/api/get-chat", &controllers.ApiController{}, "GET:GetChat") - beego.Router("/api/update-chat", &controllers.ApiController{}, "POST:UpdateChat") - beego.Router("/api/add-chat", &controllers.ApiController{}, "POST:AddChat") - beego.Router("/api/delete-chat", &controllers.ApiController{}, "POST:DeleteChat") - - beego.Router("/api/get-messages", &controllers.ApiController{}, "GET:GetMessages") - beego.Router("/api/get-message", &controllers.ApiController{}, "GET:GetMessage") - beego.Router("/api/get-message-answer", &controllers.ApiController{}, "GET:GetMessageAnswer") - beego.Router("/api/update-message", &controllers.ApiController{}, "POST:UpdateMessage") - beego.Router("/api/add-message", &controllers.ApiController{}, "POST:AddMessage") - beego.Router("/api/delete-message", &controllers.ApiController{}, "POST:DeleteMessage") - beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions") beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription") beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription") diff --git a/web/src/App.js b/web/src/App.js index 689dba1f..658ad1f6 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -18,7 +18,7 @@ import {Helmet} from "react-helmet"; import {MfaRuleRequired} from "./Setting"; import * as Setting from "./Setting"; import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs"; -import {BarsOutlined, CommentOutlined, DownOutlined, InfoCircleFilled, LogoutOutlined, SettingOutlined} from "@ant-design/icons"; +import {BarsOutlined, DownOutlined, InfoCircleFilled, LogoutOutlined, SettingOutlined} from "@ant-design/icons"; import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd"; import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom"; import OrganizationListPage from "./OrganizationListPage"; @@ -56,11 +56,6 @@ import PricingListPage from "./PricingListPage"; import PricingEditPage from "./PricingEditPage"; import PlanListPage from "./PlanListPage"; import PlanEditPage from "./PlanEditPage"; -import ChatListPage from "./ChatListPage"; -import ChatEditPage from "./ChatEditPage"; -import ChatPage from "./ChatPage"; -import MessageEditPage from "./MessageEditPage"; -import MessageListPage from "./MessageListPage"; import ProductListPage from "./ProductListPage"; import ProductEditPage from "./ProductEditPage"; import ProductBuyPage from "./ProductBuyPage"; @@ -186,10 +181,6 @@ class App extends Component { this.setState({selectedMenuKey: "/syncers"}); } else if (uri.includes("/certs")) { this.setState({selectedMenuKey: "/certs"}); - } else if (uri.includes("/chats")) { - this.setState({selectedMenuKey: "/chats"}); - } else if (uri.includes("/messages")) { - this.setState({selectedMenuKey: "/messages"}); } else if (uri.includes("/products")) { this.setState({selectedMenuKey: "/products"}); } else if (uri.includes("/payments")) { @@ -368,11 +359,6 @@ class App extends Component { items.push(Setting.getItem(<>  {i18next.t("account:My Account")}, "/account" )); - if (Conf.EnableChatPages) { - items.push(Setting.getItem(<>  {i18next.t("account:Chats & Messages")}, - "/chat" - )); - } } items.push(Setting.getItem(<>  {i18next.t("account:Logout")}, "/logout")); @@ -382,8 +368,6 @@ class App extends Component { this.props.history.push("/account"); } else if (e.key === "/subscription") { this.props.history.push("/subscription"); - } else if (e.key === "/chat") { - this.props.history.push("/chat"); } else if (e.key === "/logout") { this.logout(); } @@ -500,16 +484,6 @@ class App extends Component { "/providers" )); - if (Conf.EnableChatPages) { - res.push(Setting.getItem({i18next.t("general:Chats")}, - "/chats" - )); - - res.push(Setting.getItem({i18next.t("general:Messages")}, - "/messages" - )); - } - res.push(Setting.getItem({i18next.t("general:Resources")}, "/resources" )); @@ -628,11 +602,6 @@ class App extends Component { this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> - this.renderLoginIfNotLoggedIn()} /> - this.renderLoginIfNotLoggedIn()} /> - this.renderLoginIfNotLoggedIn()} /> - this.renderLoginIfNotLoggedIn()} /> - this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> @@ -668,8 +637,7 @@ class App extends Component { }; isWithoutCard() { - return Setting.isMobile() || window.location.pathname === "/chat" || - window.location.pathname.startsWith("/trees"); + return Setting.isMobile() || window.location.pathname.startsWith("/trees"); } renderContent() { diff --git a/web/src/ChatBox.js b/web/src/ChatBox.js deleted file mode 100644 index ed04c46f..00000000 --- a/web/src/ChatBox.js +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2023 The Casdoor Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import React from "react"; -import {Alert, Avatar, Input, List, Spin} from "antd"; -import {CopyOutlined, DislikeOutlined, LikeOutlined, SendOutlined} from "@ant-design/icons"; -import i18next from "i18next"; - -const {TextArea} = Input; - -class ChatBox extends React.Component { - constructor(props) { - super(props); - this.state = { - inputValue: "", - }; - - this.listContainerRef = React.createRef(); - } - - componentDidUpdate(prevProps) { - if (prevProps.messages !== this.props.messages && this.props.messages !== undefined && this.props.messages !== null) { - this.scrollToListItem(this.props.messages.length); - } - } - - handleKeyDown = (e) => { - if (e.key === "Enter" && !e.shiftKey) { - e.preventDefault(); - - if (this.state.inputValue !== "") { - this.send(this.state.inputValue); - this.setState({inputValue: ""}); - } - } - }; - - scrollToListItem(index) { - const listContainerElement = this.listContainerRef.current; - - if (!listContainerElement) { - return; - } - - const targetItem = listContainerElement.querySelector( - `#chatbox-list-item-${index}` - ); - - if (!targetItem) { - return; - } - - const scrollDistance = targetItem.offsetTop - listContainerElement.offsetTop; - - listContainerElement.scrollTo({ - top: scrollDistance, - behavior: "smooth", - }); - } - - send = (text) => { - this.props.sendMessage(text); - this.setState({inputValue: ""}); - }; - - renderText(text) { - const lines = text.split("\n").map((line, index) => ( - - {line} -
-
- )); - return
{lines}
; - } - - renderList() { - if (this.props.messages === undefined || this.props.messages === null) { - return ( -
- -
- ); - } - - return ( -
- { - if (Object.keys(item).length === 0 && item.constructor === Object) { - return ; - } - - return ( - -
- } - title={ -
- { - !item.text.includes("#ERROR#") ? this.renderText(item.text) : ( - - ) - } -
- } - /> -
- - - -
-
-
- ); - }} - /> -
-
- ); - } - - renderInput() { - return ( -
-
-