Compare commits

...

69 Commits

Author SHA1 Message Date
wxy 4cca98a496
fix: solve the problem that docker can not run (#657)
* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model (#640)

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support ChatGLM model and remove redundant code about Claude

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* fix: solve the problem that docker can not run

* fix: solve the problem that docker can not run

* fix: solve the problem that docker can not run

* fix: solve the problem that docker can not run

* fix: solve the problem that docker can not run

* fix: solve the problem that docker can not run

* fix: solve the problem that docker can not run
2023-09-26 18:57:11 +08:00
wxy 7485cf4002
feat: support MiniMax model (#656)
* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model (#640)

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support ChatGLM model and remove redundant code about Claude

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model

* feat: support MiniMax model
2023-09-26 14:55:50 +08:00
Kelvin Chiu d2bd6cb3ab
feat: support Local model chat using openai format (#651)
* feat: support Private model chat

* fix: rename Private model to Local model

* fix: rename Private model to Local model
2023-09-25 08:29:42 +08:00
Kelvin Chiu ed1ed5d2e3
feat: support OpenRouter model parameters (#645)
* feat: support OpenRouter model parameters

* feat: support OpenRouter model parameters
2023-09-24 07:39:57 +08:00
Kelvin Chiu 65e5fdecca
feat: support Ernie model parameters (#647) 2023-09-24 07:38:53 +08:00
Yang Luo de2c9cb679 fix: improve code 2023-09-24 00:36:54 +08:00
yehong 28f752c1a5 feat: support HNSW vector search algorithm (#646)
Signed-off-by: yehong <239859435@qq.com>
2023-09-24 00:36:18 +08:00
Kelvin Chiu 55cc17fc4a
feat: support iFlytek model parameters (#644) 2023-09-22 23:58:36 +08:00
wxy eec95994e4
fix: add ChatGLM model provider (#643)
* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model (#640)

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support ChatGLM model and remove redundant code about Claude
2023-09-20 23:41:14 +08:00
Yang Luo e82fa95d34 Update casdoor-go-sdk to v0.30.0 2023-09-17 23:25:08 +08:00
Yang Luo 6ccf90feb1 Fix store file link bug 2023-09-17 23:25:07 +08:00
Kelvin Chiu 37c6b00673
feat: support OpenAI model parameters (#641)
* feat: support openai completion parameters

* fix: update providerEditPage

* fix: update providerEditPage
2023-09-17 21:49:58 +08:00
Yang Luo bccb50b705 Fix bug in PutObject() 2023-09-17 21:08:59 +08:00
wxy d6c7e21164 feat: support Claude model (#640)
* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model

* feat: support Claude model
2023-09-17 20:40:16 +08:00
Yang Luo 6c214475fd Fix bug in PutObject() 2023-09-17 20:28:34 +08:00
Yang Luo 9e9888d002 Remove modal in checkUploadFile() 2023-09-17 20:06:59 +08:00
Yang Luo 2bcc40a312 Serve storage provider files 2023-09-17 19:34:20 +08:00
Yang Luo 2b6a69ce0c Add local file system storage provider 2023-09-17 18:24:34 +08:00
Yang Luo 5c6cc48962 Add InitDb() 2023-09-17 15:57:45 +08:00
hsluoyz 9280de7b31
Update README.md 2023-09-17 11:58:19 +08:00
YunShu 1572e75bb9
fix: add preset max tokens for OpenAI model provider (#637) 2023-09-16 22:16:15 +08:00
YunShu 13d1659151
fix: fix lint command (#638) 2023-09-16 19:51:13 +08:00
Yang Luo fec86ef23d Use Casdoor demo site setting 2023-09-15 13:54:49 +08:00
Kelvin Chiu 34da6e6dee
fix: remove duplicated text (#636) 2023-09-14 16:01:06 +08:00
Kelvin Chiu 59acb72a59
feat: support iFlytek spark model (#635) 2023-09-14 15:04:10 +08:00
yehong d62d609456
feat: add more embedding providers (#632) 2023-09-13 16:52:59 +08:00
Yang Luo 6d84245786 Remove useless addFile() 2023-09-12 01:21:37 +08:00
Yang Luo 83ef92747e Fix admin owner issue 2023-09-12 01:21:17 +08:00
Palp1tate 3937f12c75
docs: perfect the README.md (#631)
* docs: perfect the README.md

* Update README.md

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-09-10 21:31:26 +08:00
YunShu fed3b24443
fix: switch language immediately (#630) 2023-09-10 21:06:45 +08:00
Yang Luo 5e22772e1c Improve ChatBox style 2023-09-10 20:13:22 +08:00
Yang Luo 821e00dae1 Add bg color and radius 2023-09-10 18:08:18 +08:00
Yang Luo 3815521180 Improve markdown images 2023-09-10 17:56:04 +08:00
Yang Luo 571e21176f Render markdown 2023-09-10 17:27:44 +08:00
Yang Luo dab87ae97e Improve file bar 2023-09-10 17:10:38 +08:00
Yang Luo 4b790440af Add chat to homepage 2023-09-10 16:52:44 +08:00
Yang Luo 5901996b99 Add chat to navbar 2023-09-10 16:41:29 +08:00
Yang Luo e71bb6d459 Fix frontend errors 2023-09-10 16:34:30 +08:00
Kelvin Chiu 5fda8b936b feat: add support of OpenRouter (#619) 2023-09-10 10:56:08 +08:00
Yang Luo 6d7921a669 Add queryVectorSafe() 2023-09-10 00:53:04 +08:00
Yang Luo 405eceb738 Fix GetMessageAnswer() errors 2023-09-10 00:39:50 +08:00
Yang Luo 2c8f6ac553 Add embedding provider 2023-09-10 00:38:21 +08:00
Yang Luo 12acd815d7 Refactor out vector_util.go 2023-09-09 22:50:56 +08:00
Yang Luo 2ab7e3011b Rename pkg to model 2023-09-09 22:39:00 +08:00
Yang Luo c47736c11c Add GetSupportedFileTypes() 2023-09-09 22:37:07 +08:00
Kelvin Chiu c5828138cc feat: refactor text extractor (#624) 2023-09-09 22:13:34 +08:00
yehong 553c2d2f76
feat: support more sub types in Ernie model (#625) 2023-09-09 19:23:59 +08:00
Yang Luo 078cdba1e8 Update go.mod, update gpt avatar 2023-09-09 00:20:27 +08:00
yehong bcdf30f53f feat: support Ernie model (#621)
Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-09-08 12:44:13 +08:00
Yang Luo b9cff77248 Add log to task 2023-09-08 02:03:44 +08:00
Yang Luo f66fc26b61 Add task pages 2023-09-08 01:55:37 +08:00
Yang Luo fdb5e01ec8 Remove useless Graph APIs 2023-09-08 01:55:06 +08:00
Yang Luo a5ce39674b Fix mask in UpdateProvider() 2023-09-08 01:25:55 +08:00
Yang Luo 4c7c5fe04a Don't add provider to chat 2023-09-08 01:20:04 +08:00
Yang Luo a80a385bd3 Rename to "OpenAI" type 2023-09-08 01:14:53 +08:00
Yang Luo 3a27f56531 Fix HuggingFaceModelProvider 2023-09-08 00:51:24 +08:00
Yang Luo c65baeba0b Allow no knowledge 2023-09-08 00:50:50 +08:00
Yang Luo f0fa71f141 Improve addVectorsForStore() 2023-09-07 23:55:53 +08:00
Kelvin Chiu 6edd86276b
feat: add api support of HuggingFace (#620) 2023-09-07 23:17:59 +08:00
Yang Luo ec9bcb6d78 Refactor to addVectorsForStore() 2023-09-07 23:05:20 +08:00
Yang Luo 9020043669 Fix links 2023-09-07 22:53:26 +08:00
Yang Luo 5cb0df3eb1 Add subType to provider 2023-09-07 18:41:51 +08:00
Yang Luo 6f2e6c28d0 Improve demo site link 2023-09-07 18:24:36 +08:00
Yang Luo ef1cf307b8 Add task struct 2023-09-06 22:43:04 +08:00
YunShu 5f6a63b5af
docs: fix dead links (#617)
* docs: fix dead links

https://github.com/Selflocking/linkchecker/actions/runs/6058177987

* docs: fix wrong badge
2023-09-03 17:34:12 +08:00
Yang Luo 9f32fbd998 Add Model interface 2023-09-02 21:20:36 +08:00
yehong 43000075c0
feat: demo mode (#616) 2023-08-31 23:53:25 +08:00
Kelvin Chiu d940bab0f5
feat: support .docx, .pdf file parsing (#614)
* feat: add .pdf\.docx text extraction

* feat: add .pdf\.docx text extraction
2023-08-27 15:02:20 +08:00
YunShu 8ec158399b
fix: add support for several databases (#613) 2023-08-19 01:00:40 +08:00
100 changed files with 5109 additions and 848 deletions

View File

@ -20,7 +20,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.18.0'
go-version: '^1.19.0'
cache-dependency-path: ./go.mod
- name: Tests
run: |
@ -49,7 +49,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.18.0'
go-version: '^1.19.0'
cache-dependency-path: ./go.mod
- run: go version
- name: Build
@ -65,7 +65,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.18.0'
go-version: '^1.19.0'
cache: false
# gen a dummy config file

117
README.md
View File

@ -1,6 +1,5 @@
<h1 align="center" style="border-bottom: none;">📦⚡️ Casibase</h1>
<h3 align="center">A pioneering customizable open-source Domain Knowledge Base (DKB)
powered by ChatGPT, Casbin, and Casdoor.</h3>
<h3 align="center">Open-source AIGC vector & knowledge database with beautiful web UI, similar to LangChain</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
@ -9,9 +8,9 @@
<img alt="docker pull casbin/casibase" src="https://img.shields.io/docker/pulls/casbin/casibase.svg">
</a>
<a href="https://github.com/casbin/casibase/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casbin/casibase/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casibase/casibase/releases/latest">
<a href="https://github.com/casbin/casibase/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casibase.svg">
</a>
<a href="https://hub.docker.com/repository/docker/casbin/casibase">
@ -20,7 +19,7 @@
<!-- waiting for changing -->
<!-- <a href="https://hub.docker.com/r/casbin/casibase"> -->
<!-- <a href="https://github.com/casbin/casibase/actions/workflows/build.yml"> -->
<!-- <a href="https://github.com/casibase/casibase/releases/latest"> -->
<!-- <a href="https://github.com/casbin/casibase/releases/latest"> -->
<!-- <a href="https://hub.docker.com/repository/docker/casbin/casibase"> -->
</p>
@ -50,110 +49,38 @@
## Architecture
casibase contains 4 parts:
Casibase contains 2 parts:
| **Name** | **Description** | **Language** |
|----------------|---------------------------------------------------|-----------------------------------------|
| Frontend | User interface for the casibase application | JavaScript + React |
| Backend | Server-side logic and API for casibase | Golang + Beego + Python + Flask + MySQL |
| AI Model | Artificial intelligence model | Python + OpenAI |
| Knowledge Base | Storage for casibase application domain knowledge | pgvector |
| Frontend | User interface for Casibase | JavaScript + React |
| Backend | Server-side logic and API for Casibase | Golang + Beego + Python + Flask + MySQL |
![0-Architecture-casibase](assets/0-Architecture-casibase.png)
## Demo Installation
## Online Demo
casibase uses Casdoor to manage members. So you need to create an organization and an application for casibase in a Casdoor instance.
<https://ai.casbin.com>
### Casdoor configuration
## Documentation
```shell
git clone https://github.com/casdoor/casdoor.git
```
<https://casibase.org>
refer to: https://casdoor.org/docs/basic/server-installation
## Install
Follow these steps to setup Casdoor for casibase:
<https://casibase.org/docs/basic/server-installation>
- Create an **Organization**![1-Add-organization](assets/1-Add-organization.png)
## How to contact?
- Configure information about the **Organization**![2-Configure-information-organization](assets/2-Configure-information-organization.png)
Discord: <https://discord.gg/5rPsrAzK7S>
- Add a member to a newly created organization![3-Check-user](assets/3-Check-user.png)![4-Add-member-to-organization](assets/4-Add-member-to-organization.png)
Forum: <https://forum.casbin.com>
- Configure member information (remember its **Name** as well as **Password**)![5-Configure-new-user](assets/5-Configure-new-user.png)
Contact: <https://tawk.to/chat/623352fea34c2456412b8c51/1fuc7od6e>
## Contribute
For Casibase, if you have any questions, you can give issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
- Create a new **Application**![6-Add-application](assets/6-Add-application.png)
- Configuring **Application** Information (Remember **Name, ClientID** and **ClientSecret**. Change **RedirectURLs** to http://localhost:14000/callback) ![7-Configure-new-application](assets/7-Configure-new-application.png)
### casibase configuration
#### Get the code
```shell
git clone https://github.com/casbin/casibase.git
```
#### Setup database
casibase will store its users, nodes and topics informations in a MySQL database named: `casibase`, will create it if not existed. The DB connection string can be specified at: https://github.com/casbin/casibase/blob/master/conf/app.conf
```ini
dataSourceName = root:123@tcp(localhost:3306)/
```
Casnode uses XORM to connect to DB, so all DBs supported by XORM can also be used.
#### Custom config
- #### Backend (`casibase\conf\app.conf`)
```ini
casdoorEndpoint = <Your_Casdoor_endpoint>
clientId = <Your_clientId_in_Casdoor_configuration>
clientSecret = <Your_clientSecret_in_Casdoor_configuration>
casdoorOrganization = "casibase"
casdoorApplication = "app-casibase"
```
- #### Frontend (`casibase\web\src\Conf.js`)
```ini
export const AuthConfig = {
......
clientId: <Your_clientId_in_Casdoor_configuration>,
......
};
```
#### Run casnode
- #### Backend (`casibase`)
```shell
go run main.go
```
- #### Frontend (`casibase\web`)
```shell
yarn install
yarn start
```
#### Preview
Access the login view via the following link:
```shell
http://localhost:13001
```
![8-Preview-base-wordsets](assets/8-Preview-base-wordsets.png)
![9-Preview-casibase-stores](assets/9-Preview-casibase-stores.png)
The **casibase** demo is shown above, and in the future users can upload various **knowledge** files, **wordsets**, and **factorsets** to achieve a **customized domain knowledge base**.
## License
[Apache-2.0](https://github.com/casbin/casibase/blob/master/LICENSE)

148
ai/ai.go
View File

@ -1,148 +0,0 @@
// Copyright 2023 The casbin 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
}
func GetQuestionWithKnowledge(knowledge string, question string) string {
return fmt.Sprintf(`paragraph: %s
You are a reading comprehension expert. Please answer the following questions based on the provided content. The content may be in a different language from the questions, so you need to understand the content according to the language of the questions and ensure that your answers are translated into the same language as the questions:
Q1: %s`, knowledge, question)
}

View File

@ -1,105 +0,0 @@
// Copyright 2023 The casbin 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 (
"bufio"
"context"
"fmt"
"io"
"time"
"github.com/sashabaranov/go-openai"
)
func splitTxt(f io.ReadCloser) []string {
const maxLength = 210 * 3
scanner := bufio.NewScanner(f)
var res []string
var temp string
for scanner.Scan() {
line := scanner.Text()
if len(temp)+len(line) <= maxLength {
temp += line
} else {
res = append(res, temp)
temp = line
}
}
if len(temp) > 0 {
res = append(res, temp)
}
return res
}
func GetSplitTxt(f io.ReadCloser) []string {
return splitTxt(f)
}
func getEmbedding(authToken string, text string, timeout int) ([]float32, error) {
client := getProxyClientFromToken(authToken)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(30+timeout*2)*time.Second)
defer cancel()
resp, err := client.CreateEmbeddings(ctx, openai.EmbeddingRequest{
Input: []string{text},
Model: openai.AdaEmbeddingV2,
})
if err != nil {
return nil, err
}
return resp.Data[0].Embedding, nil
}
func GetEmbeddingSafe(authToken string, text string) ([]float32, error) {
var embedding []float32
var err error
for i := 0; i < 10; i++ {
embedding, err = getEmbedding(authToken, text, i)
if err != nil {
if i > 0 {
fmt.Printf("\tFailed (%d): %s\n", i+1, err.Error())
}
} else {
break
}
}
if err != nil {
return nil, err
} else {
return embedding, nil
}
}
func GetNearestVectorIndex(target []float32, vectors [][]float32) int {
targetNorm := norm(target)
var res int
max := float32(-1.0)
for i, vector := range vectors {
similarity := cosineSimilarity(target, vector, targetNorm)
if similarity > max {
max = similarity
res = i
}
}
return res
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -7,8 +7,10 @@ driverName = mysql
dataSourceName = root:123@tcp(localhost:3306)/
dbName = casibase
redisEndpoint =
isDemoMode = false
landingFolder = casibase-landing
casdoorEndpoint = http://localhost:8000
casdoorEndpoint = https://door.casdoor.com
; casdoorEndpoint = http://localhost:8000
clientId = af6b5aa958822fb9dc33
clientSecret = 8bc3010c1c951c8d876b1f311a901ff8deeb93bc
casdoorOrganization = "casbin"

View File

@ -19,7 +19,6 @@ import (
"fmt"
"strings"
"github.com/casbin/casibase/ai"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/util"
)
@ -69,46 +68,6 @@ func (c *ApiController) GetMessage() {
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
}
}
func getModelProviderFromContext(owner string, name string) (*object.Provider, error) {
var providerName string
if name != "" {
providerName = name
} else {
store, err := object.GetDefaultStore(owner)
if err != nil {
return nil, err
}
if store.ModelProvider != "" {
providerName = store.ModelProvider
}
}
var provider *object.Provider
var err error
if providerName != "" {
providerId := util.GetIdFromOwnerAndName(owner, providerName)
provider, err = object.GetProvider(providerId)
} else {
provider, err = object.GetDefaultModelProvider()
}
if provider == nil && err == nil {
return nil, fmt.Errorf("The provider: %s is not found", providerName)
} else {
return provider, err
}
}
func (c *ApiController) GetMessageAnswer() {
id := c.Input().Get("id")
@ -118,7 +77,7 @@ func (c *ApiController) GetMessageAnswer() {
message, err := object.GetMessage(id)
if err != nil {
c.ResponseError(err.Error())
c.ResponseErrorStream(err.Error())
return
}
@ -135,7 +94,7 @@ func (c *ApiController) GetMessageAnswer() {
chatId := util.GetIdFromOwnerAndName("admin", message.Chat)
chat, err := object.GetChat(chatId)
if err != nil {
c.ResponseError(err.Error())
c.ResponseErrorStream(err.Error())
return
}
@ -155,13 +114,15 @@ func (c *ApiController) GetMessageAnswer() {
return
}
provider, err := getModelProviderFromContext(chat.Owner, chat.User2)
modelProviderObj, err := getModelProviderFromContext(chat.Owner, chat.User2)
if err != nil {
c.ResponseError(err.Error())
c.ResponseErrorStream(err.Error())
return
}
if provider.Category != "Model" || provider.ClientSecret == "" {
c.ResponseErrorStream(fmt.Sprintf("The provider: %s is invalid", provider.GetId()))
embeddingProviderObj, err := getEmbeddingProviderFromContext(chat.Owner, chat.User2)
if err != nil {
c.ResponseErrorStream(err.Error())
return
}
@ -169,23 +130,22 @@ func (c *ApiController) GetMessageAnswer() {
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
nearestText, err := object.GetNearestVectorText(authToken, chat.Owner, question)
if err != nil {
nearestText, err := object.GetNearestVectorText(embeddingProviderObj, chat.Owner, question)
if err != nil && err.Error() != "no knowledge vectors found" {
c.ResponseErrorStream(err.Error())
return
}
realQuestion := ai.GetQuestionWithKnowledge(nearestText, question)
realQuestion := object.GetRefinedQuestion(nearestText, question)
fmt.Printf("Question: [%s]\n", question)
fmt.Printf("Context: [%s]\n", nearestText)
fmt.Printf("Answer: [")
err = ai.QueryAnswerStream(authToken, realQuestion, c.Ctx.ResponseWriter, &stringBuilder)
err = modelProviderObj.QueryText(realQuestion, c.Ctx.ResponseWriter, &stringBuilder)
if err != nil {
c.ResponseErrorStream(err.Error())
return
@ -196,7 +156,7 @@ func (c *ApiController) GetMessageAnswer() {
event := fmt.Sprintf("event: end\ndata: %s\n\n", "end")
_, err = c.Ctx.ResponseWriter.Write([]byte(event))
if err != nil {
c.ResponseError(err.Error())
c.ResponseErrorStream(err.Error())
return
}
@ -205,7 +165,7 @@ func (c *ApiController) GetMessageAnswer() {
message.Text = answer
_, err = object.UpdateMessage(message.GetId(), message)
if err != nil {
c.ResponseError(err.Error())
c.ResponseErrorStream(err.Error())
return
}
}

111
controllers/message_util.go Normal file
View File

@ -0,0 +1,111 @@
// Copyright 2023 The casbin 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 (
"fmt"
"github.com/casbin/casibase/embedding"
"github.com/casbin/casibase/model"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/util"
)
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
}
}
func getModelProviderFromContext(owner string, name string) (model.ModelProvider, error) {
var providerName string
if name != "" {
providerName = name
} else {
store, err := object.GetDefaultStore(owner)
if err != nil {
return nil, err
}
if store != nil && store.ModelProvider != "" {
providerName = store.ModelProvider
}
}
var provider *object.Provider
var err error
if providerName != "" {
providerId := util.GetIdFromOwnerAndName(owner, providerName)
provider, err = object.GetProvider(providerId)
} else {
provider, err = object.GetDefaultModelProvider()
}
if provider == nil && err == nil {
return nil, fmt.Errorf("The model provider: %s is not found", providerName)
}
if provider.Category != "Model" || provider.ClientSecret == "" {
return nil, fmt.Errorf("The model provider: %s is invalid", providerName)
}
providerObj, err := provider.GetModelProvider()
if err != nil {
return nil, err
}
return providerObj, err
}
func getEmbeddingProviderFromContext(owner string, name string) (embedding.EmbeddingProvider, error) {
var providerName string
if name != "" {
providerName = name
} else {
store, err := object.GetDefaultStore(owner)
if err != nil {
return nil, err
}
if store != nil && store.EmbeddingProvider != "" {
providerName = store.EmbeddingProvider
}
}
var provider *object.Provider
var err error
if providerName != "" {
providerId := util.GetIdFromOwnerAndName(owner, providerName)
provider, err = object.GetProvider(providerId)
} else {
provider, err = object.GetDefaultEmbeddingProvider()
}
if provider == nil && err == nil {
return nil, fmt.Errorf("The embedding provider: %s is not found", providerName)
}
if provider.Category != "Embedding" || provider.ClientSecret == "" {
return nil, fmt.Errorf("The embedding provider: %s is invalid", providerName)
}
providerObj, err := provider.GetEmbeddingProvider()
if err != nil {
return nil, err
}
return providerObj, err
}

View File

@ -16,6 +16,9 @@ package controllers
import (
"encoding/json"
"fmt"
"net"
"strings"
"github.com/casbin/casibase/object"
)
@ -42,6 +45,34 @@ func (c *ApiController) GetStores() {
c.ResponseOk(stores)
}
func isIpAddress(host string) bool {
// Attempt to split the host and port, ignoring the error
hostWithoutPort, _, err := net.SplitHostPort(host)
if err != nil {
// If an error occurs, it might be because there's no port
// In that case, use the original host string
hostWithoutPort = host
}
// Attempt to parse the host as an IP address (both IPv4 and IPv6)
ip := net.ParseIP(hostWithoutPort)
// if host is not nil is an IP address else is not an IP address
return ip != nil
}
func getOriginFromHost(host string) string {
protocol := "https://"
if !strings.Contains(host, ".") {
// "localhost:14000"
protocol = "http://"
} else if isIpAddress(host) {
// "192.168.0.10"
protocol = "http://"
}
return fmt.Sprintf("%s%s", protocol, host)
}
func (c *ApiController) GetStore() {
id := c.Input().Get("id")
@ -61,7 +92,9 @@ func (c *ApiController) GetStore() {
return
}
err = store.Populate()
host := c.Ctx.Request.Host
origin := getOriginFromHost(host)
err = store.Populate(origin)
if err != nil {
// gentle error
c.ResponseOk(store, err.Error())
@ -132,11 +165,11 @@ func (c *ApiController) RefreshStoreVectors() {
return
}
success, err := object.RefreshStoreVectors(&store)
ok, err := object.RefreshStoreVectors(&store)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
c.ResponseOk(ok)
}

109
controllers/task.go Normal file
View File

@ -0,0 +1,109 @@
// Copyright 2023 The casbin 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/casbin/casibase/object"
)
func (c *ApiController) GetGlobalTasks() {
tasks, err := object.GetGlobalTasks()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedTasks(tasks, true))
}
func (c *ApiController) GetTasks() {
owner := "admin"
tasks, err := object.GetTasks(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedTasks(tasks, true))
}
func (c *ApiController) GetTask() {
id := c.Input().Get("id")
task, err := object.GetTask(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedTask(task, true))
}
func (c *ApiController) UpdateTask() {
id := c.Input().Get("id")
var task object.Task
err := json.Unmarshal(c.Ctx.Input.RequestBody, &task)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.UpdateTask(id, &task)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddTask() {
var task object.Task
err := json.Unmarshal(c.Ctx.Input.RequestBody, &task)
if err != nil {
c.ResponseError(err.Error())
return
}
task.Owner = "admin"
success, err := object.AddTask(&task)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteTask() {
var task object.Task
err := json.Unmarshal(c.Ctx.Input.RequestBody, &task)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.DeleteTask(&task)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

View File

@ -14,6 +14,8 @@
package controllers
import "github.com/astaxie/beego/context"
type Response struct {
Status string `json:"status"`
Msg string `json:"msg"`
@ -65,3 +67,23 @@ func (c *ApiController) RequireAdmin() bool {
return false
}
func DenyRequest(ctx *context.Context) {
responseError(ctx, "Unauthorized operation")
}
func responseError(ctx *context.Context, error string, data ...interface{}) {
resp := Response{Status: "error", Msg: error}
switch len(data) {
case 2:
resp.Data2 = data[1]
fallthrough
case 1:
resp.Data = data[0]
}
err := ctx.Output.JSON(resp, true, false)
if err != nil {
panic(err)
}
}

View File

@ -31,7 +31,7 @@ func (c *ApiController) GetGlobalVectors() {
}
func (c *ApiController) GetVectors() {
owner := c.Input().Get("owner")
owner := "admin"
vectors, err := object.GetVectors(owner)
if err != nil {

40
embedding/cohere.go Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2023 The casbin 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 embedding
import (
"context"
cohereembedder "github.com/henomis/lingoose/embedder/cohere"
)
type CohereEmbeddingProvider struct {
subType string
secretKey string
}
func NewCohereEmbeddingProvider(subType string, secretKey string) (*CohereEmbeddingProvider, error) {
return &CohereEmbeddingProvider{subType: subType, secretKey: secretKey}, nil
}
func (c *CohereEmbeddingProvider) QueryVector(text string, ctx context.Context) ([]float32, error) {
client := cohereembedder.New().WithModel(cohereembedder.EmbedderModel(c.subType)).WithAPIKey(c.secretKey)
embed, err := client.Embed(ctx, []string{text})
if err != nil {
return nil, err
}
return float64ToFloat32(embed[0]), nil
}

42
embedding/ernie.go Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2023 The casbin 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 embedding
import (
"context"
ernie "github.com/anhao/go-ernie"
)
type ErnieEmbeddingProvider struct {
subType string
apiKey string
secretKey string
}
func NewErnieEmbeddingProvider(subType string, apiKey string, secretKey string) (*ErnieEmbeddingProvider, error) {
return &ErnieEmbeddingProvider{subType: subType, apiKey: apiKey, secretKey: secretKey}, nil
}
func (e *ErnieEmbeddingProvider) QueryVector(text string, ctx context.Context) ([]float32, error) {
client := ernie.NewDefaultClient(e.apiKey, e.secretKey)
request := ernie.EmbeddingRequest{Input: []string{text}}
embeddings, err := client.CreateEmbeddings(ctx, request)
if err != nil {
return nil, err
}
return float64ToFloat32(embeddings.Data[0].Embedding), nil
}

49
embedding/huggingface.go Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2023 The casbin 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 embedding
import (
"context"
"github.com/casbin/casibase/proxy"
"github.com/henomis/lingoose/embedder/huggingface"
)
type HuggingFaceEmbeddingProvider struct {
subType string
secretKey string
}
func NewHuggingFaceEmbeddingProvider(subType string, secretKey string) (*HuggingFaceEmbeddingProvider, error) {
return &HuggingFaceEmbeddingProvider{subType: subType, secretKey: secretKey}, nil
}
func (h *HuggingFaceEmbeddingProvider) QueryVector(text string, ctx context.Context) ([]float32, error) {
client := huggingfaceembedder.New().WithToken(h.secretKey).WithModel(h.subType).WithHTTPClient(proxy.ProxyHttpClient)
embed, err := client.Embed(ctx, []string{text})
if err != nil {
return nil, err
}
return float64ToFloat32(embed[0]), nil
}
func float64ToFloat32(slice []float64) []float32 {
newSlice := make([]float32, len(slice))
for i, v := range slice {
newSlice[i] = float32(v)
}
return newSlice
}

54
embedding/openai.go Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2023 The casbin 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 embedding
import (
"context"
"github.com/casbin/casibase/proxy"
"github.com/casbin/casibase/util"
"github.com/sashabaranov/go-openai"
)
type OpenAiEmbeddingProvider struct {
subType string
secretKey string
}
func NewOpenAiEmbeddingProvider(subType string, secretKey string) (*OpenAiEmbeddingProvider, error) {
return &OpenAiEmbeddingProvider{subType: subType, secretKey: secretKey}, nil
}
func getProxyClientFromToken(authToken string) *openai.Client {
config := openai.DefaultConfig(authToken)
config.HTTPClient = proxy.ProxyHttpClient
c := openai.NewClientWithConfig(config)
return c
}
func (p *OpenAiEmbeddingProvider) QueryVector(text string, ctx context.Context) ([]float32, error) {
client := getProxyClientFromToken(p.secretKey)
resp, err := client.CreateEmbeddings(ctx, openai.EmbeddingRequest{
Input: []string{text},
Model: openai.EmbeddingModel(util.ParseInt(p.subType)),
})
if err != nil {
return nil, err
}
return resp.Data[0].Embedding, nil
}

40
embedding/provider.go Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2023 The casbin 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 embedding
import "context"
type EmbeddingProvider interface {
QueryVector(text string, ctx context.Context) ([]float32, error)
}
func GetEmbeddingProvider(typ string, subType string, clientId string, clientSecret string) (EmbeddingProvider, error) {
var p EmbeddingProvider
var err error
if typ == "OpenAI" {
p, err = NewOpenAiEmbeddingProvider(subType, clientSecret)
} else if typ == "Hugging Face" {
p, err = NewHuggingFaceEmbeddingProvider(subType, clientSecret)
} else if typ == "Cohere" {
p, err = NewCohereEmbeddingProvider(subType, clientSecret)
} else if typ == "Ernie" {
p, err = NewErnieEmbeddingProvider(subType, clientId, clientSecret)
}
if err != nil {
return nil, err
}
return p, nil
}

67
go.mod
View File

@ -1,23 +1,36 @@
module github.com/casbin/casibase
go 1.18
go 1.19
require (
github.com/ConnectAI-E/go-minimax v0.0.1
github.com/Lok-Lu/go-openrouter v0.0.0-20230807015935-ab5cee433ad3
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible
github.com/anhao/go-ernie v1.0.4
github.com/astaxie/beego v1.12.3
github.com/casdoor/casdoor-go-sdk v0.28.1
github.com/casdoor/casdoor-go-sdk v0.30.0
github.com/casibase/go-hnsw v1.0.0
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f
github.com/denisenkom/go-mssqldb v0.10.0
github.com/go-sql-driver/mysql v1.6.0
github.com/google/uuid v1.3.0
github.com/henomis/lingoose v0.0.11-alpha1
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80
github.com/leverly/ChatGLM v1.2.0
github.com/lib/pq v1.10.2
github.com/madebywelch/anthropic-go v1.0.1
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762
github.com/muesli/kmeans v0.3.0
github.com/pkoukk/tiktoken-go v0.1.1
github.com/sashabaranov/go-openai v1.12.0
github.com/tealeg/xlsx v1.0.5
golang.org/x/net v0.8.0
github.com/unidoc/unioffice v1.4.0
github.com/vogo/xfspark v0.1.2
golang.org/x/net v0.10.0
golang.org/x/time v0.3.0
gonum.org/v1/gonum v0.11.0
modernc.org/sqlite v1.18.1
xorm.io/core v0.7.3
xorm.io/xorm v1.2.5
)
@ -25,47 +38,73 @@ require (
require (
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.8.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dlclark/regexp2 v1.8.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v2.0.0+incompatible // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/henomis/cohere-go v1.0.1 // indirect
github.com/henomis/restclientgo v1.0.5 // indirect
github.com/imroc/req/v3 v3.35.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/moul/http2curl v1.0.0 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.27.1 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.1 // indirect
github.com/quic-go/quic-go v0.37.6 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.8.0 // indirect
github.com/vogo/gorun v1.1.0 // indirect
github.com/vogo/logger v1.5.1 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.9.1 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.55.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.36.3 // indirect
modernc.org/ccgo/v3 v3.16.9 // indirect
modernc.org/libc v1.17.1 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.2.1 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.18.1 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.0 // indirect
xorm.io/builder v0.3.9 // indirect
)

139
go.sum
View File

@ -35,9 +35,13 @@ gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGq
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ConnectAI-E/go-minimax v0.0.1 h1:sxz0kuRh+M5xjycpUmnBCrh+cctRSHMLBpdY/Wq2m8E=
github.com/ConnectAI-E/go-minimax v0.0.1/go.mod h1:c+9xxqMgmtwdpZEq/lBtrwkbwlK7d6SNfMO79Mg0mUM=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Lok-Lu/go-openrouter v0.0.0-20230807015935-ab5cee433ad3 h1:E15Zr1fu3QEIleqINqXpl4SlYuWkwWPJ4cx6UVaJITE=
github.com/Lok-Lu/go-openrouter v0.0.0-20230807015935-ab5cee433ad3/go.mod h1:nM0kITDAJEkwn9x2DQPdfJynThaLe0vGNpPcqJ8vjAI=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@ -54,6 +58,8 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585 h1:ECnkjykkSn3Gsibjd8FrcC+8SMD
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/anhao/go-ernie v1.0.4 h1:555OagLMbC6JfzFb7Xe7/O4k/WlxgEXKHqLJyy8eyuY=
github.com/anhao/go-ernie v1.0.4/go.mod h1:lNCznvV3M7RIQqzouq7UFC1sL8UPmCzIKDWvKV6ecQE=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@ -74,11 +80,15 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/casdoor/casdoor-go-sdk v0.28.1 h1:z0b36oEsU9PzCxHlYWmRY1ZMLSnUW3MVRDv6I7hWy9E=
github.com/casdoor/casdoor-go-sdk v0.28.1/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY=
github.com/casdoor/casdoor-go-sdk v0.30.0 h1:qUoDvmFyCLfLZpMG81XMkY/8h86z5fdoiy5rfmy+afo=
github.com/casdoor/casdoor-go-sdk v0.30.0/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY=
github.com/casibase/go-hnsw v1.0.0 h1:P0rQMvM/BudblFB83yj9yi9+wHVnYOuaPeL0e1gHwbM=
github.com/casibase/go-hnsw v1.0.0/go.mod h1:SVuCrv39V/GhBKdkNnRIiaper9UJhTErqvo5sA8P45g=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -105,18 +115,20 @@ github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:sr
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f h1:5M3/cWnsF9o5+7/PkKJXtZ0i5XZDnoxBzI8531mXJUM=
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f/go.mod h1:vQ+nFRPFDrDVbRneDNbXPObFFq4ZilZBhYdfNiqSr7k=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8=
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0=
github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
@ -152,6 +164,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@ -160,6 +173,8 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@ -173,9 +188,11 @@ github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptG
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -187,6 +204,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -224,7 +243,6 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -235,27 +253,38 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 h1:2XF1Vzq06X+inNqgJ9tRnGuw+ZVCB3FazXODD6JE1R8=
github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@ -271,9 +300,17 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/henomis/cohere-go v1.0.1 h1:a47gIN29tqAl4yBTAT+BzQMjsWG94Fz07u9AE4Md+a8=
github.com/henomis/cohere-go v1.0.1/go.mod h1:F6D33jlWle6pbGdf9Fm2bteaOOQOO1cQtFnlFfj+ZXY=
github.com/henomis/lingoose v0.0.11-alpha1 h1:6iXcdewIdTDJCNg7AxZF6onobLEh0BPFyHYTKSV8bAw=
github.com/henomis/lingoose v0.0.11-alpha1/go.mod h1:hOfRJswe3sA17uZSUJHJNrBiqPxEt2FM9wUFqFFOHSE=
github.com/henomis/restclientgo v1.0.5 h1:xMuznJLagE8nGrmFPyBkzsDztJm2A7uMLNGMBY5iWSg=
github.com/henomis/restclientgo v1.0.5/go.mod h1:xIeTCu2ZstvRn0fCukNpzXLN3m/kRTU0i0RwAbv7Zug=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imroc/req/v3 v3.35.1 h1:xrsuKq4FHWqxU2DM8lWbTwmxiObGfR7B/zgEBMmy8Wc=
github.com/imroc/req/v3 v3.35.1/go.mod h1:c8dXW9N3SJn/DuKVjHHmryV2WO7At9bFtnu1rloiFoo=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
@ -340,6 +377,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
@ -352,24 +390,28 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/leverly/ChatGLM v1.2.0 h1:CLXD0+sqUabADMwEDoZP22qoLInY9BjQl/jZ2hZG0M0=
github.com/leverly/ChatGLM v1.2.0/go.mod h1:DoxwOIyOup0Ct+dhm2FxKrakCB5AscJ0N0jkW+XuU8Q=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/madebywelch/anthropic-go v1.0.1 h1:LalIkikXbN53MIHGQekhwDWTs/x+/WHU71Ht1T4F0Ug=
github.com/madebywelch/anthropic-go v1.0.1/go.mod h1:ipU4SV1KHLcxo7lpR/O3JWq6985kaNcdYQgB46gaQCQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@ -406,6 +448,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/muesli/clusters v0.0.0-20180605185049-a07a36e67d36/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 h1:p4A2Jx7Lm3NV98VRMKlyWd3nqf8obft8NfXlAUmqd3I=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
@ -433,11 +477,12 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@ -500,14 +545,18 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg=
github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.37.6 h1:2IIUmQzT5YNxAiaPGjs++Z4hGOtIR0q79uS5qE9ccfY=
github.com/quic-go/quic-go v0.37.6/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
@ -532,8 +581,10 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
@ -549,8 +600,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@ -559,8 +611,16 @@ github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/unidoc/unioffice v1.4.0 h1:yl+TbZJu2GTVYAYvu51wppj0R+fPC67xzVcy91qgrzI=
github.com/unidoc/unioffice v1.4.0/go.mod h1:7wl8btOkZW1TfqfpDWoujRXkUpowwisGRYDo7COHBiI=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vogo/gorun v1.1.0 h1:i/8HhmNyjMa79bFn1ZHGTO3KyiWQcZPBsFGpvgkcap8=
github.com/vogo/gorun v1.1.0/go.mod h1:MyOjF/DbZSz40GQ5657Ou9NEfNlUbMhvpXjDvh4L8OY=
github.com/vogo/logger v1.5.1 h1:voyVY69TpM/x1lml4LYy4jMe5z0kDh5jW1oatcikajM=
github.com/vogo/logger v1.5.1/go.mod h1:9U+qupncHpWpt4ptlxFm9bvDb9EjbGIA+cY/tYtW4Kg=
github.com/vogo/xfspark v0.1.2 h1:QdW7jvFL6bgHQ74xTuAlP2IBj4sIVCpBE/LS0LW4ePE=
github.com/vogo/xfspark v0.1.2/go.mod h1:KHvAxw98fpLsFdmFYm9ps99eGaLbuLBTBa9rVG6SFyo=
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@ -568,6 +628,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
@ -607,8 +668,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -619,8 +680,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -642,7 +703,9 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -680,11 +743,12 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -692,8 +756,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -704,6 +768,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -755,7 +821,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -763,8 +831,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -776,8 +844,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -834,7 +902,9 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -900,6 +970,12 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e h1:Ao9GzfUMPH3zjVfzXG5rlWlk+Q8MXWKwWpwVQE1MXfw=
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -917,6 +993,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -937,7 +1015,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
@ -980,7 +1057,9 @@ modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM=
modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
@ -1008,9 +1087,11 @@ modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI=
modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@ -25,6 +25,7 @@ import (
func main() {
object.InitAdapter()
object.InitDb()
proxy.InitHttpClient()
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
@ -40,6 +41,7 @@ func main() {
// https://studygolang.com/articles/2303
beego.InsertFilter("/", beego.BeforeRouter, routers.TransparentStatic) // must has this for default page
beego.InsertFilter("/*", beego.BeforeRouter, routers.TransparentStatic)
beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter)
if beego.AppConfig.String("redisEndpoint") == "" {
beego.BConfig.WebConfig.Session.SessionProvider = "file"

65
model/chatglm.go Normal file
View File

@ -0,0 +1,65 @@
// Copyright 2023 The casbin 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 model
import (
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/leverly/ChatGLM/client"
)
type ChatGLMModelProvider struct {
subType string
clientSecret string
}
func NewChatGLMModelProvider(subType string, clientSecret string) (*ChatGLMModelProvider, error) {
return &ChatGLMModelProvider{subType: subType, clientSecret: clientSecret}, nil
}
func (p *ChatGLMModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
proxy := client.NewChatGLMClient(p.clientSecret, 30*time.Second)
prompt := []client.Message{{Role: "user", Content: question}}
taskId, err := proxy.AsyncInvoke(p.subType, 0.2, prompt)
if err != nil {
return err
}
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
flushData := func(data string) error {
if _, err := fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
builder.WriteString(data)
return nil
}
response, err := proxy.AsyncInvokeTask(p.subType, taskId)
if err != nil {
return err
}
content := (*response.Choices)[0].Content
err = flushData(content)
if err != nil {
return err
}
return nil
}

63
model/claude.go Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2023 The casbin 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 model
import (
"fmt"
"io"
"net/http"
"strings"
"github.com/madebywelch/anthropic-go/pkg/anthropic"
)
type ClaudeModelProvider struct {
subType string
secretKey string
}
func NewClaudeModelProvider(subType string, secretKey string) (*ClaudeModelProvider, error) {
return &ClaudeModelProvider{subType: subType, secretKey: secretKey}, nil
}
func (p *ClaudeModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
client, err := anthropic.NewClient(p.secretKey)
if err != nil {
panic(err)
}
response, _ := client.Complete(&anthropic.CompletionRequest{
Prompt: anthropic.GetPrompt(question),
Model: anthropic.Model(p.subType),
MaxTokensToSample: 100,
StopSequences: []string{"\r", "Human:"},
}, nil)
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
flushData := func(data string) error {
if _, err := fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
builder.WriteString(data)
return nil
}
err = flushData(response.Completion)
if err != nil {
return err
}
return nil
}

179
model/ernie.go Normal file
View File

@ -0,0 +1,179 @@
// Copyright 2023 The casbin 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 model
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"strings"
ernie "github.com/anhao/go-ernie"
)
type ErnieModelProvider struct {
subType string
apiKey string
secretKey string
temperature float32
topP float32
presencePenalty float32
}
func NewErnieModelProvider(subType string, apiKey string, secretKey string, temperature float32, topP float32, presencePenalty float32) (*ErnieModelProvider, error) {
return &ErnieModelProvider{
subType: subType,
apiKey: apiKey,
secretKey: secretKey,
temperature: temperature,
topP: topP,
presencePenalty: presencePenalty,
}, nil
}
func (p *ErnieModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
client := ernie.NewDefaultClient(p.apiKey, p.secretKey)
ctx := context.Background()
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
messages := []ernie.ChatCompletionMessage{
{
Role: "user",
Content: question,
},
}
flushData := func(data string) error {
if _, err := fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
builder.WriteString(data)
return nil
}
temperature := p.temperature
topP := p.topP
presencePenalty := p.presencePenalty
if p.subType == "ERNIE-Bot" {
stream, err := client.CreateErnieBotChatCompletionStream(ctx,
ernie.ErnieBotRequest{
Messages: messages,
Temperature: temperature,
TopP: topP,
PresencePenalty: presencePenalty,
})
if err != nil {
return err
}
defer stream.Close()
for {
response, err := stream.Recv()
if errors.Is(err, io.EOF) {
return nil
}
if err != nil {
return err
}
err = flushData(response.Result)
if err != nil {
return err
}
}
} else if p.subType == "ERNIE-Bot-turbo" {
stream, err := client.CreateErnieBotTurboChatCompletionStream(ctx,
ernie.ErnieBotTurboRequest{
Messages: messages,
Temperature: temperature,
TopP: topP,
PresencePenalty: presencePenalty,
})
if err != nil {
return err
}
defer stream.Close()
for {
response, err := stream.Recv()
if errors.Is(err, io.EOF) {
return nil
}
if err != nil {
return err
}
err = flushData(response.Result)
if err != nil {
return err
}
}
} else if p.subType == "BLOOMZ-7B" {
stream, err := client.CreateBloomz7b1ChatCompletionStream(ctx, ernie.Bloomz7b1Request{Messages: messages})
if err != nil {
return err
}
defer stream.Close()
for {
response, err := stream.Recv()
if errors.Is(err, io.EOF) {
return nil
}
if err != nil {
return err
}
err = flushData(response.Result)
if err != nil {
return err
}
}
} else if p.subType == "Llama-2" {
stream, err := client.CreateLlamaChatCompletionStream(ctx, ernie.LlamaChatRequest{Messages: messages})
if err != nil {
return err
}
defer stream.Close()
for {
response, err := stream.Recv()
if errors.Is(err, io.EOF) {
return nil
}
if err != nil {
return err
}
err = flushData(response.Result)
if err != nil {
return err
}
}
}
return nil
}

49
model/huggingface.go Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2023 The casbin 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 model
import (
"context"
"fmt"
"io"
"strings"
"github.com/casbin/casibase/proxy"
"github.com/henomis/lingoose/llm/huggingface"
)
type HuggingFaceModelProvider struct {
subType string
secretKey string
}
func NewHuggingFaceModelProvider(subType string, secretKey string) (*HuggingFaceModelProvider, error) {
return &HuggingFaceModelProvider{subType: subType, secretKey: secretKey}, nil
}
func (p *HuggingFaceModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
client := huggingface.New(p.subType, 1, false).WithToken(p.secretKey).WithHTTPClient(proxy.ProxyHttpClient).WithMode(huggingface.HuggingFaceModeTextGeneration)
ctx := context.Background()
resp, err := client.Completion(ctx, question)
if err != nil {
return err
}
resp = strings.Split(resp, "\n")[0]
fmt.Println(resp)
return nil
}

85
model/iflytek.go Normal file
View File

@ -0,0 +1,85 @@
// Copyright 2023 The casbin 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 model
import (
"fmt"
"io"
"net/http"
"strings"
iflytek "github.com/vogo/xfspark/chat"
)
type iFlytekModelProvider struct {
subType string
appID string
apiKey string
secretKey string
temperature string
topK int
}
func NewiFlytekModelProvider(subType string, secretKey string, temperature float32, topK int) (*iFlytekModelProvider, error) {
p := &iFlytekModelProvider{
subType: subType,
appID: "",
apiKey: "",
secretKey: secretKey,
temperature: fmt.Sprintf("%f", temperature),
topK: topK,
}
return p, nil
}
func (p *iFlytekModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
client := iflytek.NewServer(p.appID, p.apiKey, p.secretKey)
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
session, err := client.GetSession("1")
if err != nil {
return fmt.Errorf("iflytek get session error: %v", err)
}
if session == nil {
return fmt.Errorf("iflytek get session error: session is nil")
}
session.Req.Parameter.Chat.Temperature = p.temperature
session.Req.Parameter.Chat.TopK = p.topK
response, err := session.Send(question)
if err != nil {
return fmt.Errorf("iflytek send error: %v", err)
}
flushData := func(data string) error {
if _, err := fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
builder.WriteString(data)
return nil
}
err = flushData(response)
if err != nil {
return err
}
return nil
}

119
model/local.go Normal file
View File

@ -0,0 +1,119 @@
// Copyright 2023 The casbin 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 model
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"github.com/sashabaranov/go-openai"
)
type LocalModelProvider struct {
subType string
secretKey string
temperature float32
topP float32
frequencyPenalty float32
presencePenalty float32
providerUrl string
}
func NewLocalModelProvider(subType string, secretKey string, temperature float32, topP float32, frequencyPenalty float32, presencePenalty float32, providerUrl string) (*LocalModelProvider, error) {
p := &LocalModelProvider{
subType: subType,
secretKey: secretKey,
temperature: temperature,
topP: topP,
frequencyPenalty: frequencyPenalty,
presencePenalty: presencePenalty,
providerUrl: providerUrl,
}
return p, nil
}
func getLocalClientFromUrl(authToken string, url string) *openai.Client {
config := openai.DefaultConfig(authToken)
config.BaseURL = url
c := openai.NewClientWithConfig(config)
return c
}
func (p *LocalModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
client := getLocalClientFromUrl(p.secretKey, p.providerUrl)
ctx := context.Background()
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
model := p.subType
temperature := p.temperature
topP := p.topP
frequencyPenalty := p.frequencyPenalty
presencePenalty := p.presencePenalty
respStream, err := client.CreateCompletionStream(
ctx,
openai.CompletionRequest{
Model: model,
Prompt: question,
Stream: true,
Temperature: temperature,
TopP: topP,
FrequencyPenalty: frequencyPenalty,
PresencePenalty: presencePenalty,
},
)
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
}
}
// 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
}

64
model/minimax.go Normal file
View File

@ -0,0 +1,64 @@
package model
import (
"context"
"fmt"
"io"
"net/http"
"strings"
textv1 "github.com/ConnectAI-E/go-minimax/gen/go/minimax/text/v1"
"github.com/ConnectAI-E/go-minimax/minimax"
)
type MiniMaxModelProvider struct {
subType string
groupID string
apiKey string
temperature float32
}
func NewMiniMaxModelProvider(subType string, groupID string, apiKey string, temperature float32) (*MiniMaxModelProvider, error) {
return &MiniMaxModelProvider{
subType: subType,
groupID: groupID,
apiKey: apiKey,
temperature: temperature,
}, nil
}
func (p *MiniMaxModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
ctx := context.Background()
client, _ := minimax.New(
minimax.WithApiToken(p.apiKey),
minimax.WithGroupId(p.groupID),
)
req := &textv1.ChatCompletionsRequest{
Messages: []*textv1.Message{
{
SenderType: "USER",
Text: question,
},
},
Model: p.subType,
Temperature: p.temperature,
}
res, _ := client.ChatCompletions(ctx, req)
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
flushData := func(data string) error {
if _, err := fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
builder.WriteString(data)
return nil
}
err := flushData(res.Choices[0].Text)
if err != nil {
return err
}
return nil
}

165
model/openai.go Normal file
View File

@ -0,0 +1,165 @@
// Copyright 2023 The casbin 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 model
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"github.com/casbin/casibase/proxy"
"github.com/sashabaranov/go-openai"
)
// https://pkg.go.dev/github.com/sashabaranov/go-openai@v1.12.0#pkg-constants
// https://platform.openai.com/docs/models/overview
var __maxTokens = map[string]int{
openai.GPT4: 8192,
openai.GPT40613: 8192,
openai.GPT432K: 32768,
openai.GPT432K0613: 32768,
openai.GPT40314: 8192,
openai.GPT432K0314: 32768,
openai.GPT3Dot5Turbo: 4097,
openai.GPT3Dot5Turbo16K: 16385,
openai.GPT3Dot5Turbo0613: 4097,
openai.GPT3Dot5Turbo16K0613: 16385,
openai.GPT3Dot5Turbo0301: 4097,
openai.GPT3TextDavinci003: 4097,
openai.GPT3TextDavinci002: 4097,
openai.GPT3TextCurie001: 2049,
openai.GPT3TextBabbage001: 2049,
openai.GPT3TextAda001: 2049,
openai.GPT3Davinci: 2049,
openai.GPT3Curie: 2049,
openai.GPT3Ada: 2049,
openai.GPT3Babbage: 2049,
}
type OpenAiModelProvider struct {
subType string
secretKey string
temperature float32
topP float32
frequencyPenalty float32
presencePenalty float32
}
func NewOpenAiModelProvider(subType string, secretKey string, temperature float32, topP float32, frequencyPenalty float32, presencePenalty float32) (*OpenAiModelProvider, error) {
p := &OpenAiModelProvider{
subType: subType,
secretKey: secretKey,
temperature: temperature,
topP: topP,
frequencyPenalty: frequencyPenalty,
presencePenalty: presencePenalty,
}
return p, nil
}
func getProxyClientFromToken(authToken string) *openai.Client {
config := openai.DefaultConfig(authToken)
config.HTTPClient = proxy.ProxyHttpClient
c := openai.NewClientWithConfig(config)
return c
}
// GetMaxTokens returns the max tokens for a given openai model.
func (p *OpenAiModelProvider) GetMaxTokens() int {
res, ok := __maxTokens[p.subType]
if !ok {
return 4097
}
return res
}
func (p *OpenAiModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
client := getProxyClientFromToken(p.secretKey)
ctx := context.Background()
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
model := p.subType
if model == "" {
model = openai.GPT3TextDavinci003
}
// https://platform.openai.com/tokenizer
// https://github.com/pkoukk/tiktoken-go#available-encodings
promptTokens, err := GetTokenSize(model, question)
if err != nil {
return err
}
maxTokens := p.GetMaxTokens() - promptTokens
temperature := p.temperature
topP := p.topP
frequencyPenalty := p.frequencyPenalty
presencePenalty := p.presencePenalty
respStream, err := client.CreateCompletionStream(
ctx,
openai.CompletionRequest{
Model: model,
Prompt: question,
MaxTokens: maxTokens,
Stream: true,
Temperature: temperature,
TopP: topP,
FrequencyPenalty: frequencyPenalty,
PresencePenalty: presencePenalty,
},
)
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
}
}
// 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
}

136
model/openrouter.go Normal file
View File

@ -0,0 +1,136 @@
// Copyright 2023 The casbin 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 model
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"github.com/Lok-Lu/go-openrouter"
"github.com/casbin/casibase/proxy"
)
type OpenRouterModelProvider struct {
subType string
secretKey string
siteName string
siteUrl string
temperature *float32
topP *float32
}
func NewOpenRouterModelProvider(subType string, secretKey string, temperature float32, topP float32) (*OpenRouterModelProvider, error) {
p := &OpenRouterModelProvider{
subType: subType,
secretKey: secretKey,
siteName: "Casibase",
siteUrl: "https://casibase.org",
temperature: &temperature,
topP: &topP,
}
return p, nil
}
func (p *OpenRouterModelProvider) getProxyClientFromToken() *openrouter.Client {
config, err := openrouter.DefaultConfig(p.secretKey, p.siteName, p.siteUrl)
if err != nil {
panic(err)
}
config.HTTPClient = proxy.ProxyHttpClient
c := openrouter.NewClientWithConfig(config)
return c
}
func (p *OpenRouterModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error {
client := p.getProxyClientFromToken()
ctx := context.Background()
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
model := p.subType
if model == "" {
model = openrouter.Gpt35Turbo
}
promptTokens, err := GetTokenSize(model, question)
if err != nil {
return err
}
maxTokens := 4097 - promptTokens
temperature := p.temperature
topP := p.topP
respStream, err := client.CreateChatCompletionStream(
ctx,
&openrouter.ChatCompletionRequest{
Model: p.subType,
Messages: []openrouter.ChatCompletionMessage{
{
Role: openrouter.ChatMessageRoleSystem,
Content: "You are a helpful assistant.",
},
{
Role: openrouter.ChatMessageRoleUser,
Content: question,
},
},
Stream: false,
Temperature: temperature,
TopP: topP,
MaxTokens: maxTokens,
},
)
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].Message.Content
if isLeadingReturn && len(data) != 0 {
if strings.Count(data, "\n") == len(data) {
continue
} else {
isLeadingReturn = false
}
}
if _, err = fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
builder.WriteString(data)
}
return nil
}

53
model/provider.go Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2023 The casbin 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 model
import (
"io"
"strings"
)
type ModelProvider interface {
QueryText(question string, writer io.Writer, builder *strings.Builder) error
}
func GetModelProvider(typ string, subType string, clientId string, clientSecret string, temperature float32, topP float32, topK int, frequencyPenalty float32, presencePenalty float32, providerUrl string) (ModelProvider, error) {
var p ModelProvider
var err error
if typ == "OpenAI" {
p, err = NewOpenAiModelProvider(subType, clientSecret, temperature, topP, frequencyPenalty, presencePenalty)
} else if typ == "Hugging Face" {
p, err = NewHuggingFaceModelProvider(subType, clientSecret)
} else if typ == "Claude" {
p, err = NewClaudeModelProvider(subType, clientSecret)
} else if typ == "OpenRouter" {
p, err = NewOpenRouterModelProvider(subType, clientSecret, temperature, topP)
} else if typ == "Ernie" {
p, err = NewErnieModelProvider(subType, clientId, clientSecret, temperature, topP, presencePenalty)
} else if typ == "iFlytek" {
p, err = NewiFlytekModelProvider(subType, clientSecret, temperature, topK)
} else if typ == "ChatGLM" {
p, err = NewChatGLMModelProvider(subType, clientSecret)
} else if typ == "MiniMax" {
p, err = NewMiniMaxModelProvider(subType, clientId, clientSecret, temperature)
} else if typ == "Local" {
p, err = NewLocalModelProvider(subType, clientSecret, temperature, topP, frequencyPenalty, presencePenalty, providerUrl)
}
if err != nil {
return nil, err
}
return p, nil
}

74
model/query.go Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2023 The casbin 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 model
import (
"context"
"fmt"
"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
}

View File

@ -15,12 +15,12 @@
//go:build !skipCi
// +build !skipCi
package ai_test
package model_test
import (
"testing"
"github.com/casbin/casibase/ai"
"github.com/casbin/casibase/model"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/proxy"
"github.com/sashabaranov/go-openai"
@ -30,10 +30,10 @@ func TestRun(t *testing.T) {
object.InitConfig()
proxy.InitHttpClient()
text := ai.QueryAnswerSafe("", "hi")
text := model.QueryAnswerSafe("", "hi")
println(text)
}
func TestToken(t *testing.T) {
println(ai.GetTokenSize(openai.GPT3TextDavinci003, ""))
println(model.GetTokenSize(openai.GPT3TextDavinci003, ""))
}

28
model/util.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2023 The casbin 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 model
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
}

View File

@ -19,7 +19,10 @@ import (
"runtime"
"github.com/astaxie/beego"
_ "github.com/go-sql-driver/mysql"
_ "github.com/denisenkom/go-mssqldb" // mssql
_ "github.com/go-sql-driver/mysql" // mysql
_ "github.com/lib/pq" // postgres
_ "modernc.org/sqlite" // sqlite
"xorm.io/xorm"
)
@ -84,10 +87,6 @@ func (a *Adapter) createDatabase() error {
}
func (a *Adapter) open() {
if err := a.createDatabase(); err != nil {
panic(err)
}
engine, err := xorm.NewEngine(a.driverName, a.dataSourceName+beego.AppConfig.String("dbName"))
if err != nil {
panic(err)
@ -142,4 +141,9 @@ func (a *Adapter) createTable() {
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Task))
if err != nil {
panic(err)
}
}

View File

@ -96,16 +96,16 @@ func UpdateChat(id string, chat *Chat) (bool, error) {
}
func AddChat(chat *Chat) (bool, error) {
if chat.Type == "AI" && chat.User2 == "" {
provider, err := GetDefaultModelProvider()
if err != nil {
return false, err
}
if provider != nil {
chat.User2 = provider.Name
}
}
//if chat.Type == "AI" && chat.User2 == "" {
// provider, err := GetDefaultModelProvider()
// if err != nil {
// return false, err
// }
//
// if provider != nil {
// chat.User2 = provider.Name
// }
//}
affected, err := adapter.engine.Insert(chat)
if err != nil {

View File

@ -20,8 +20,6 @@ import (
"io"
"mime/multipart"
"strings"
"github.com/casbin/casibase/storage"
)
func UpdateFile(storeId string, key string, file *File) bool {
@ -37,6 +35,11 @@ func AddFile(storeId string, userName string, key string, isLeaf bool, filename
return false, nil, nil
}
storageProviderObj, err := store.GetStorageProviderObj()
if err != nil {
return false, nil, err
}
var objectKey string
var fileBuffer *bytes.Buffer
if isLeaf {
@ -49,7 +52,7 @@ func AddFile(storeId string, userName string, key string, isLeaf bool, filename
}
bs := fileBuffer.Bytes()
err = storage.PutObject(store.StorageProvider, userName, store.Name, objectKey, fileBuffer)
err = storageProviderObj.PutObject(userName, store.Name, objectKey, fileBuffer)
if err != nil {
return false, nil, err
}
@ -60,7 +63,7 @@ func AddFile(storeId string, userName string, key string, isLeaf bool, filename
objectKey = strings.TrimLeft(objectKey, "/")
fileBuffer = bytes.NewBuffer(nil)
bs := fileBuffer.Bytes()
err = storage.PutObject(store.StorageProvider, userName, store.Name, objectKey, fileBuffer)
err = storageProviderObj.PutObject(userName, store.Name, objectKey, fileBuffer)
if err != nil {
return false, nil, err
}
@ -78,19 +81,24 @@ func DeleteFile(storeId string, key string, isLeaf bool) (bool, error) {
return false, nil
}
storageProviderObj, err := store.GetStorageProviderObj()
if err != nil {
return false, err
}
if isLeaf {
err = storage.DeleteObject(store.StorageProvider, key)
err = storageProviderObj.DeleteObject(key)
if err != nil {
return false, err
}
} else {
objects, err := storage.ListObjects(store.StorageProvider, key)
objects, err := storageProviderObj.ListObjects(key)
if err != nil {
return false, err
}
for _, object := range objects {
err = storage.DeleteObject(store.StorageProvider, object.Key)
err = storageProviderObj.DeleteObject(object.Key)
if err != nil {
return false, err
}

76
object/init.go Normal file
View File

@ -0,0 +1,76 @@
// Copyright 2023 The casbin 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 "github.com/casbin/casibase/util"
func InitDb() {
existed := initBuiltInStore()
if !existed {
initBuiltInProvider()
}
}
func initBuiltInStore() bool {
store, err := getStore("admin", "store-built-in")
if err != nil {
panic(err)
}
if store != nil {
return true
}
store = &Store{
Owner: "admin",
Name: "store-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Store",
StorageProvider: "provider-storage-built-in",
ModelProvider: "",
EmbeddingProvider: "",
}
_, err = AddStore(store)
if err != nil {
panic(err)
}
return false
}
func initBuiltInProvider() {
provider, err := GetProvider(util.GetId("admin", "provider-storage-local-built-in"))
if err != nil {
panic(err)
}
if provider != nil {
return
}
provider = &Provider{
Owner: "admin",
Name: "provider-storage-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Storage Provider",
Category: "Storage",
Type: "Local File System",
ClientId: "C:/casibase_storage",
}
_, err = AddProvider(provider)
if err != nil {
panic(err)
}
}

28
object/message_ai.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2023 The casbin 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"
func GetRefinedQuestion(knowledge string, question string) string {
if knowledge == "" {
return question
}
return fmt.Sprintf(`paragraph: %s
You are a reading comprehension expert. Please answer the following questions based on the provided content. The content may be in a different language from the questions, so you need to understand the content according to the language of the questions and ensure that your answers are translated into the same language as the questions:
Question: %s`, knowledge, question)
}

View File

@ -17,6 +17,9 @@ package object
import (
"fmt"
"github.com/casbin/casibase/embedding"
"github.com/casbin/casibase/model"
"github.com/casbin/casibase/storage"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
@ -29,9 +32,16 @@ type Provider struct {
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Category string `xorm:"varchar(100)" json:"category"`
Type string `xorm:"varchar(100)" json:"type"`
SubType string `xorm:"varchar(100)" json:"subType"`
ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
ProviderUrl string `xorm:"varchar(200)" json:"providerUrl"`
Temperature float32 `xorm:"float" json:"temperature"`
TopP float32 `xorm:"float" json:"topP"`
TopK int `xorm:"int" json:"topK"`
FrequencyPenalty float32 `xorm:"float" json:"frequencyPenalty"`
PresencePenalty float32 `xorm:"float" json:"presencePenalty"`
}
func GetMaskedProvider(provider *Provider, isMaskEnabled bool) *Provider {
@ -100,6 +110,20 @@ func GetProvider(id string) (*Provider, error) {
return getProvider(owner, name)
}
func GetDefaultStorageProvider() (*Provider, error) {
provider := Provider{Owner: "admin", Category: "Storage"}
existed, err := adapter.engine.Get(&provider)
if err != nil {
return &provider, err
}
if !existed {
return nil, nil
}
return &provider, nil
}
func GetDefaultModelProvider() (*Provider, error) {
provider := Provider{Owner: "admin", Category: "Model"}
existed, err := adapter.engine.Get(&provider)
@ -114,9 +138,23 @@ func GetDefaultModelProvider() (*Provider, error) {
return &provider, nil
}
func GetDefaultEmbeddingProvider() (*Provider, error) {
provider := Provider{Owner: "admin", Category: "Embedding"}
existed, err := adapter.engine.Get(&provider)
if err != nil {
return &provider, err
}
if !existed {
return nil, nil
}
return &provider, nil
}
func UpdateProvider(id string, provider *Provider) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getProvider(owner, name)
p, err := getProvider(owner, name)
if err != nil {
return false, err
}
@ -124,6 +162,10 @@ func UpdateProvider(id string, provider *Provider) (bool, error) {
return false, nil
}
if provider.ClientSecret == "***" {
provider.ClientSecret = p.ClientSecret
}
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(provider)
if err != nil {
return false, err
@ -154,3 +196,42 @@ func DeleteProvider(provider *Provider) (bool, error) {
func (provider *Provider) GetId() string {
return fmt.Sprintf("%s/%s", provider.Owner, provider.Name)
}
func (p *Provider) GetStorageProviderObj() (storage.StorageProvider, error) {
pProvider, err := storage.GetStorageProvider(p.Type, p.ClientId, p.Name)
if err != nil {
return nil, err
}
if pProvider == nil {
return nil, fmt.Errorf("the storage provider type: %s is not supported", p.Type)
}
return pProvider, nil
}
func (p *Provider) GetModelProvider() (model.ModelProvider, error) {
pProvider, err := model.GetModelProvider(p.Type, p.SubType, p.ClientId, p.ClientSecret, p.Temperature, p.TopP, p.TopK, p.FrequencyPenalty, p.PresencePenalty, p.ProviderUrl)
if err != nil {
return nil, err
}
if pProvider == nil {
return nil, fmt.Errorf("the model provider type: %s is not supported", p.Type)
}
return pProvider, nil
}
func (p *Provider) GetEmbeddingProvider() (embedding.EmbeddingProvider, error) {
pProvider, err := embedding.GetEmbeddingProvider(p.Type, p.SubType, p.ClientId, p.ClientSecret)
if err != nil {
return nil, err
}
if pProvider == nil {
return nil, fmt.Errorf("the embedding provider type: %s is not supported", p.Type)
}
return pProvider, nil
}

34
object/search.go Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2023 The casbin 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
type SearchProvider interface {
Search(qVector []float32) (string, error)
}
func GetSearchProvider(typ string, owner string) (SearchProvider, error) {
var p SearchProvider
var err error
if typ == "Default" {
p, err = NewDefaultSearchProvider(owner)
} else if typ == "HNSW" {
p, err = NewHnswSearchProvider()
}
if err != nil {
return nil, err
}
return p, nil
}

38
object/search_default.go Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2023 The casbin 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
type DefaultSearchProvider struct {
owner string
}
func NewDefaultSearchProvider(owner string) (*DefaultSearchProvider, error) {
return &DefaultSearchProvider{owner: owner}, nil
}
func (p *DefaultSearchProvider) Search(qVector []float32) (string, error) {
vectors, err := getRelatedVectors(p.owner)
if err != nil {
return "", err
}
var nVectors [][]float32
for _, candidate := range vectors {
nVectors = append(nVectors, candidate.Data)
}
i := getNearestVectorIndex(qVector, nVectors)
return vectors[i].Text, nil
}

127
object/search_hnsw.go Normal file
View File

@ -0,0 +1,127 @@
// Copyright 2023 The casbin 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 (
"encoding/json"
"io/ioutil"
"sync"
"github.com/casbin/casibase/util"
"github.com/casibase/go-hnsw"
)
type HnswSearchProvider struct{}
func NewHnswSearchProvider() (*HnswSearchProvider, error) {
return &HnswSearchProvider{}, nil
}
func (p *HnswSearchProvider) Search(qVector []float32) (string, error) {
search, err := Index.Search(qVector)
if err != nil {
return "", err
}
return search.Text, nil
}
var Index *HNSWIndex
const (
M = 64
efConstruction = 400
)
type HNSWIndex struct {
Hnsw *hnsw.Hnsw `json:"-"`
Lock sync.RWMutex `json:"-"`
Id uint32 `json:"id,omitempty"`
IdToStr map[uint32]string `json:"id_to_str,omitempty"`
StrToId map[string]uint32 `json:"str_to_id,omitempty"`
}
func InitHNSW() {
Index = &HNSWIndex{}
err := Index.load()
if err != nil {
Index.IdToStr = make(map[uint32]string)
Index.StrToId = make(map[string]uint32)
Index.Hnsw = hnsw.New(M, efConstruction, make([]float32, 128))
}
}
func (h *HNSWIndex) Add(name string, vector []float32) error {
h.Lock.Lock()
h.Id++
id := h.Id
h.IdToStr[id] = name
h.StrToId[name] = id
h.Lock.Unlock()
h.Hnsw.Grow(int(id + 1))
h.Hnsw.Add(vector, id)
return h.save()
}
func (h *HNSWIndex) Search(vector []float32) (*Vector, error) {
result := h.Hnsw.Search(vector, 100, 4)
item := result.Pop()
owner, name := util.GetOwnerAndNameFromId(h.IdToStr[item.ID])
return getVector(owner, name)
}
func (h *HNSWIndex) save() error {
h.Lock.RLock()
defer h.Lock.RUnlock()
data, err := json.Marshal(h)
if err != nil {
return err
}
err = ioutil.WriteFile("./hnsw", data, 0o644)
if err != nil {
return err
}
err = h.Hnsw.Save("./index")
if err != nil {
return err
}
return nil
}
func (h *HNSWIndex) load() error {
h.Lock.Lock()
defer h.Lock.Unlock()
data, err := ioutil.ReadFile("./hnsw")
if err != nil {
return err
}
err = json.Unmarshal(data, h)
if err != nil {
return err
}
h.Hnsw, _, err = hnsw.Load("./index")
if err != nil {
return err
}
return nil
}

View File

@ -17,6 +17,7 @@ package object
import (
"fmt"
"github.com/casbin/casibase/storage"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
@ -44,8 +45,9 @@ type Store struct {
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
StorageProvider string `xorm:"varchar(100)" json:"storageProvider"`
ModelProvider string `xorm:"varchar(100)" json:"modelProvider"`
StorageProvider string `xorm:"varchar(100)" json:"storageProvider"`
ModelProvider string `xorm:"varchar(100)" json:"modelProvider"`
EmbeddingProvider string `xorm:"varchar(100)" json:"embeddingProvider"`
FileTree *File `xorm:"mediumtext" json:"fileTree"`
PropertiesMap map[string]*Properties `xorm:"mediumtext" json:"propertiesMap"`
@ -150,19 +152,51 @@ func (store *Store) GetId() string {
return fmt.Sprintf("%s/%s", store.Owner, store.Name)
}
func (store *Store) GetStorageProviderObj() (storage.StorageProvider, error) {
var provider *Provider
var err error
if store.StorageProvider == "" {
provider, err = GetDefaultStorageProvider()
} else {
providerId := util.GetIdFromOwnerAndName(store.Owner, store.StorageProvider)
provider, err = GetProvider(providerId)
}
if err != nil {
return nil, err
}
if provider != nil {
return provider.GetStorageProviderObj()
} else {
return storage.NewCasdoorProvider(store.StorageProvider)
}
}
func (store *Store) GetEmbeddingProvider() (*Provider, error) {
if store.EmbeddingProvider == "" {
return GetDefaultEmbeddingProvider()
}
providerId := util.GetIdFromOwnerAndName(store.Owner, store.EmbeddingProvider)
return GetProvider(providerId)
}
func RefreshStoreVectors(store *Store) (bool, error) {
provider, err := GetDefaultModelProvider()
storageProviderObj, err := store.GetStorageProviderObj()
if err != nil {
return false, err
}
authToken := provider.ClientSecret
success, err := setTxtObjectVector(authToken, store.StorageProvider, "", store.Name)
embeddingProvider, err := store.GetEmbeddingProvider()
if err != nil {
return false, err
}
if !success {
return false, nil
embeddingProviderObj, err := embeddingProvider.GetEmbeddingProvider()
if err != nil {
return false, err
}
return true, nil
ok, err := addVectorsForStore(storageProviderObj, embeddingProviderObj, "", store.Name)
return ok, err
}

View File

@ -16,6 +16,7 @@ package object
import (
"fmt"
urllib "net/url"
"strings"
"github.com/casbin/casibase/storage"
@ -79,8 +80,13 @@ func isObjectLeaf(object *storage.Object) bool {
return isLeaf
}
func (store *Store) Populate() error {
objects, err := storage.ListObjects(store.StorageProvider, "")
func (store *Store) Populate(origin string) error {
storageProviderObj, err := store.GetStorageProviderObj()
if err != nil {
return err
}
objects, err := storageProviderObj.ListObjects("")
if err != nil {
return err
}
@ -113,7 +119,11 @@ func (store *Store) Populate() error {
lastModifiedTime := object.LastModified
isLeaf := isObjectLeaf(object)
size := object.Size
url := object.Url
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url, _ = urllib.JoinPath(origin, object.Url)
}
tokens := strings.Split(strings.Trim(object.Key, "/"), "/")
store.createPathIfNotExisted(tokens, size, url, lastModifiedTime, isLeaf)
@ -125,7 +135,12 @@ func (store *Store) Populate() error {
}
func (store *Store) GetVideoData() ([]string, error) {
objects, err := storage.ListObjects(store.StorageProvider, "2023/视频附件")
storageProviderObj, err := store.GetStorageProviderObj()
if err != nil {
return nil, err
}
objects, err := storageProviderObj.ListObjects("2023/视频附件")
if err != nil {
return nil, err
}

137
object/task.go Normal file
View File

@ -0,0 +1,137 @@
// Copyright 2023 The casbin 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/casbin/casibase/util"
"xorm.io/core"
)
type Task 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"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Provider string `xorm:"varchar(100)" json:"provider"`
Application string `xorm:"varchar(100)" json:"application"`
Path string `xorm:"varchar(100)" json:"path"`
Log string `xorm:"mediumtext" json:"log"`
}
func GetMaskedTask(task *Task, isMaskEnabled bool) *Task {
if !isMaskEnabled {
return task
}
if task == nil {
return nil
}
return task
}
func GetMaskedTasks(tasks []*Task, isMaskEnabled bool) []*Task {
if !isMaskEnabled {
return tasks
}
for _, task := range tasks {
task = GetMaskedTask(task, isMaskEnabled)
}
return tasks
}
func GetGlobalTasks() ([]*Task, error) {
tasks := []*Task{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&tasks)
if err != nil {
return tasks, err
}
return tasks, nil
}
func GetTasks(owner string) ([]*Task, error) {
tasks := []*Task{}
err := adapter.engine.Desc("created_time").Find(&tasks, &Task{Owner: owner})
if err != nil {
return tasks, err
}
return tasks, nil
}
func getTask(owner string, name string) (*Task, error) {
task := Task{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&task)
if err != nil {
return &task, err
}
if existed {
return &task, nil
} else {
return nil, nil
}
}
func GetTask(id string) (*Task, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getTask(owner, name)
}
func UpdateTask(id string, task *Task) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getTask(owner, name)
if err != nil {
return false, err
}
if task == nil {
return false, nil
}
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(task)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddTask(task *Task) (bool, error) {
affected, err := adapter.engine.Insert(task)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteTask(task *Task) (bool, error) {
affected, err := adapter.engine.ID(core.PK{task.Owner, task.Name}).Delete(&Task{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (task *Task) GetId() string {
return fmt.Sprintf("%s/%s", task.Owner, task.Name)
}

View File

@ -92,6 +92,11 @@ func UpdateVector(id string, vector *Vector) (bool, error) {
}
func AddVector(vector *Vector) (bool, error) {
//err := Index.Add(util.GetId(vector.Owner, vector.Name), vector.Data)
//if err != nil {
// return false, err
//}
affected, err := adapter.engine.Insert(vector)
if err != nil {
return false, err

View File

@ -17,52 +17,35 @@ package object
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"path/filepath"
"time"
"github.com/casbin/casibase/ai"
"github.com/casbin/casibase/embedding"
"github.com/casbin/casibase/storage"
"github.com/casbin/casibase/txt"
"github.com/casbin/casibase/util"
"golang.org/x/time/rate"
)
func filterTextFiles(files []*storage.Object) []*storage.Object {
var res []*storage.Object
fileTypes := txt.GetSupportedFileTypes()
fileTypeMap := map[string]bool{}
for _, fileType := range fileTypes {
fileTypeMap[fileType] = true
}
res := []*storage.Object{}
for _, file := range files {
if strings.HasSuffix(file.Key, ".txt") || strings.HasSuffix(file.Key, ".md") {
ext := filepath.Ext(file.Key)
if fileTypeMap[ext] {
res = append(res, file)
}
}
return res
}
func getTextFiles(provider string, prefix string) ([]*storage.Object, error) {
files, err := storage.ListObjects(provider, prefix)
if err != nil {
return nil, err
}
return filterTextFiles(files), nil
}
func getObjectReadCloser(object *storage.Object) (io.ReadCloser, error) {
resp, err := http.Get(object.Url)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
return nil, fmt.Errorf("HTTP request failed with status code: %d", resp.StatusCode)
}
return resp.Body, nil
}
func addEmbeddedVector(authToken string, text string, storeName string, fileName string) (bool, error) {
embedding, err := ai.GetEmbeddingSafe(authToken, text)
func addEmbeddedVector(embeddingProviderObj embedding.EmbeddingProvider, text string, storeName string, fileName string) (bool, error) {
data, err := queryVectorSafe(embeddingProviderObj, text)
if err != nil {
return false, err
}
@ -80,56 +63,48 @@ func addEmbeddedVector(authToken string, text string, storeName string, fileName
Store: storeName,
File: fileName,
Text: text,
Data: embedding,
Data: data,
}
return AddVector(vector)
}
func setTxtObjectVector(authToken string, provider string, key string, storeName string) (bool, error) {
lb := rate.NewLimiter(rate.Every(time.Minute), 3)
func addVectorsForStore(storageProviderObj storage.StorageProvider, embeddingProviderObj embedding.EmbeddingProvider, prefix string, storeName string) (bool, error) {
var affected bool
txtObjects, err := getTextFiles(provider, key)
files, err := storageProviderObj.ListObjects(prefix)
if err != nil {
return false, err
}
if len(txtObjects) == 0 {
return false, nil
}
for _, txtObject := range txtObjects {
readCloser, err := getObjectReadCloser(txtObject)
files = filterTextFiles(files)
timeLimiter := rate.NewLimiter(rate.Every(time.Minute), 3)
for _, file := range files {
var text string
fileExt := filepath.Ext(file.Key)
text, err = txt.GetParsedTextFromUrl(file.Url, fileExt)
if err != nil {
return false, err
}
defer readCloser.Close()
splitTxts := ai.GetSplitTxt(readCloser)
for _, splitTxt := range splitTxts {
if lb.Allow() {
success, err := addEmbeddedVector(authToken, splitTxt, storeName, txtObject.Key)
if err != nil {
return false, err
}
if !success {
return false, nil
}
textSections := txt.GetTextSections(text)
for i, textSection := range textSections {
if timeLimiter.Allow() {
fmt.Printf("[%d/%d] Generating embedding for store: [%s]'s text section: %s\n", i+1, len(textSections), storeName, textSection)
affected, err = addEmbeddedVector(embeddingProviderObj, textSection, storeName, file.Key)
} else {
err := lb.Wait(context.Background())
err = timeLimiter.Wait(context.Background())
if err != nil {
return false, err
}
success, err := addEmbeddedVector(authToken, splitTxt, storeName, txtObject.Key)
if err != nil {
return false, err
}
if !success {
return false, nil
}
fmt.Printf("[%d/%d] Generating embedding for store: [%s]'s text section: %s\n", i+1, len(textSections), storeName, textSection)
affected, err = addEmbeddedVector(embeddingProviderObj, textSection, storeName, file.Key)
}
}
}
return true, nil
return affected, err
}
func getRelatedVectors(owner string) ([]*Vector, error) {
@ -144,8 +119,35 @@ func getRelatedVectors(owner string) ([]*Vector, error) {
return vectors, nil
}
func GetNearestVectorText(authToken string, owner string, question string) (string, error) {
qVector, err := ai.GetEmbeddingSafe(authToken, question)
func queryVectorWithContext(embeddingProvider embedding.EmbeddingProvider, text string, timeout int) ([]float32, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(30+timeout*2)*time.Second)
defer cancel()
return embeddingProvider.QueryVector(text, ctx)
}
func queryVectorSafe(embeddingProvider embedding.EmbeddingProvider, text string) ([]float32, error) {
var res []float32
var err error
for i := 0; i < 10; i++ {
res, err = queryVectorWithContext(embeddingProvider, text, i)
if err != nil {
if i > 0 {
fmt.Printf("\tFailed (%d): %s\n", i+1, err.Error())
}
} else {
break
}
}
if err != nil {
return nil, err
} else {
return res, nil
}
}
func GetNearestVectorText(embeddingProvider embedding.EmbeddingProvider, owner string, text string) (string, error) {
qVector, err := queryVectorSafe(embeddingProvider, text)
if err != nil {
return "", err
}
@ -153,16 +155,10 @@ func GetNearestVectorText(authToken string, owner string, question string) (stri
return "", fmt.Errorf("no qVector found")
}
vectors, err := getRelatedVectors(owner)
searchProvider, err := GetSearchProvider("Default", owner)
if err != nil {
return "", err
}
var nVectors [][]float32
for _, candidate := range vectors {
nVectors = append(nVectors, candidate.Data)
}
i := ai.GetNearestVectorIndex(qVector, nVectors)
return vectors[i].Text, nil
return searchProvider.Search(qVector)
}

View File

@ -12,33 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package ai
package object
import (
"math"
"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
}
func cosineSimilarity(vec1, vec2 []float32, vec1Norm float32) float32 {
dotProduct := dot(vec1, vec2)
vec2Norm := norm(vec2)
if vec2Norm == 0 {
return 0.0
}
return dotProduct / (vec1Norm * vec2Norm)
}
import "math"
func dot(vec1, vec2 []float32) float32 {
if len(vec1) != len(vec2) {
@ -59,3 +35,27 @@ func norm(vec []float32) float32 {
}
return float32(math.Sqrt(float64(normSquared)))
}
func cosineSimilarity(vec1, vec2 []float32, vec1Norm float32) float32 {
dotProduct := dot(vec1, vec2)
vec2Norm := norm(vec2)
if vec2Norm == 0 {
return 0.0
}
return dotProduct / (vec1Norm * vec2Norm)
}
func getNearestVectorIndex(target []float32, vectors [][]float32) int {
targetNorm := norm(target)
var res int
max := float32(-1.0)
for i, vector := range vectors {
similarity := cosineSimilarity(target, vector, targetNorm)
if similarity > max {
max = similarity
res = i
}
}
return res
}

View File

@ -21,9 +21,17 @@ import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/casbin/casibase/conf"
"github.com/casbin/casibase/controllers"
"github.com/casbin/casibase/util"
)
const (
headerAllowOrigin = "Access-Control-Allow-Origin"
headerAllowMethods = "Access-Control-Allow-Methods"
headerAllowHeaders = "Access-Control-Allow-Headers"
)
func TransparentStatic(ctx *context.Context) {
urlPath := ctx.Request.URL.Path
if strings.HasPrefix(urlPath, "/api/") {
@ -44,6 +52,17 @@ func TransparentStatic(ctx *context.Context) {
}
}
if strings.HasPrefix(urlPath, "/storage") {
ctx.Output.Header(headerAllowOrigin, "*")
ctx.Output.Header(headerAllowMethods, "POST, GET, OPTIONS, DELETE")
ctx.Output.Header(headerAllowHeaders, "Content-Type, Authorization")
urlPath = strings.TrimPrefix(urlPath, "/storage/")
urlPath = strings.Replace(urlPath, "|", ":", 1)
http.ServeFile(ctx.ResponseWriter, ctx.Request, urlPath)
return
}
path := "web/build"
if urlPath == "/" {
path += "/index.html"
@ -57,3 +76,38 @@ func TransparentStatic(ctx *context.Context) {
http.ServeFile(ctx.ResponseWriter, ctx.Request, "web/build/index.html")
}
}
func ApiFilter(ctx *context.Context) {
method := ctx.Request.Method
urlPath := getUrlPath(ctx.Request.URL.Path)
if conf.IsDemoMode() {
if !isAllowedInDemoMode(method, urlPath) {
controllers.DenyRequest(ctx)
}
}
}
func getUrlPath(urlPath string) string {
if strings.HasPrefix(urlPath, "/cas") && (strings.HasSuffix(urlPath, "/serviceValidate") || strings.HasSuffix(urlPath, "/proxy") || strings.HasSuffix(urlPath, "/proxyValidate") || strings.HasSuffix(urlPath, "/validate") || strings.HasSuffix(urlPath, "/p3/serviceValidate") || strings.HasSuffix(urlPath, "/p3/proxyValidate") || strings.HasSuffix(urlPath, "/samlValidate")) {
return "/cas"
}
if strings.HasPrefix(urlPath, "/api/login/oauth") {
return "/api/login/oauth"
}
if strings.HasPrefix(urlPath, "/api/webauthn") {
return "/api/webauthn"
}
return urlPath
}
func isAllowedInDemoMode(method string, urlPath string) bool {
if method == "POST" && !(strings.HasPrefix(urlPath, "/api/signin") || urlPath == "/api/signout") {
return false
}
return true
}

View File

@ -98,6 +98,13 @@ func initAPI() {
beego.Router("/api/add-message", &controllers.ApiController{}, "POST:AddMessage")
beego.Router("/api/delete-message", &controllers.ApiController{}, "POST:DeleteMessage")
beego.Router("/api/get-global-tasks", &controllers.ApiController{}, "GET:GetGlobalTasks")
beego.Router("/api/get-tasks", &controllers.ApiController{}, "GET:GetTasks")
beego.Router("/api/get-task", &controllers.ApiController{}, "GET:GetTask")
beego.Router("/api/update-task", &controllers.ApiController{}, "POST:UpdateTask")
beego.Router("/api/add-task", &controllers.ApiController{}, "POST:AddTask")
beego.Router("/api/delete-task", &controllers.ApiController{}, "POST:DeleteTask")
beego.Router("/api/update-file", &controllers.ApiController{}, "POST:UpdateFile")
beego.Router("/api/add-file", &controllers.ApiController{}, "POST:AddFile")
beego.Router("/api/delete-file", &controllers.ApiController{}, "POST:DeleteFile")

View File

@ -22,21 +22,22 @@ import (
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
type Object struct {
Key string
LastModified string
Size int64
Url string
type CasdoorProvider struct {
providerName string
}
func ListObjects(provider string, prefix string) ([]*Object, error) {
if provider == "" {
return nil, fmt.Errorf("storage provider is empty")
func NewCasdoorProvider(providerName string) (*CasdoorProvider, error) {
if providerName == "" {
return nil, fmt.Errorf("storage provider name: [%s] doesn't exist", providerName)
}
return &CasdoorProvider{providerName: providerName}, nil
}
func (p *CasdoorProvider) ListObjects(prefix string) ([]*Object, error) {
casdoorOrganization := beego.AppConfig.String("casdoorOrganization")
casdoorApplication := beego.AppConfig.String("casdoorApplication")
resources, err := casdoorsdk.GetResources(casdoorOrganization, casdoorApplication, "provider", provider, "Direct", prefix)
resources, err := casdoorsdk.GetResources(casdoorOrganization, casdoorApplication, "provider", p.providerName, "Direct", prefix)
if err != nil {
return nil, err
}
@ -53,24 +54,16 @@ func ListObjects(provider string, prefix string) ([]*Object, error) {
return res, nil
}
func PutObject(provider string, user string, parent string, key string, fileBuffer *bytes.Buffer) error {
if provider == "" {
return fmt.Errorf("storage provider is empty")
}
_, _, err := casdoorsdk.UploadResource(user, "Casibase", parent, fmt.Sprintf("Direct/%s/%s", provider, key), fileBuffer.Bytes())
func (p *CasdoorProvider) PutObject(user string, parent string, key string, fileBuffer *bytes.Buffer) error {
_, _, err := casdoorsdk.UploadResource(user, "Casibase", parent, fmt.Sprintf("Direct/%s/%s", p.providerName, key), fileBuffer.Bytes())
if err != nil {
return err
}
return nil
}
func DeleteObject(provider string, key string) error {
if provider == "" {
return fmt.Errorf("storage provider is empty")
}
_, err := casdoorsdk.DeleteResource(fmt.Sprintf("Direct/%s/%s", provider, key))
func (p *CasdoorProvider) DeleteObject(key string) error {
_, err := casdoorsdk.DeleteResource(fmt.Sprintf("Direct/%s/%s", p.providerName, key))
if err != nil {
return err
}

View File

@ -0,0 +1,89 @@
// Copyright 2023 The casbin 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 storage
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
)
type LocalFileSystemStorageProvider struct {
path string
}
func NewLocalFileSystemStorageProvider(path string) (*LocalFileSystemStorageProvider, error) {
path = strings.ReplaceAll(path, "\\", "/")
return &LocalFileSystemStorageProvider{path: path}, nil
}
func (p *LocalFileSystemStorageProvider) ListObjects(prefix string) ([]*Object, error) {
objects := []*Object{}
fullPath := p.path
filepath.Walk(fullPath, func(path string, info os.FileInfo, err error) error {
if path == fullPath {
return nil
}
base := filepath.Base(path)
if info.IsDir() && (strings.HasPrefix(base, ".") || base == "node_modules") {
return filepath.SkipDir
}
if err == nil && !info.IsDir() {
modTime := info.ModTime()
path = strings.ReplaceAll(path, "\\", "/")
relativePath := strings.TrimPrefix(path, fullPath)
relativePath = strings.TrimPrefix(relativePath, "/")
url := strings.Replace(path, ":", "|", 1)
url = fmt.Sprintf("storage/%s", url)
objects = append(objects, &Object{
Key: relativePath,
LastModified: modTime.Format(time.RFC3339),
Size: info.Size(),
Url: url,
})
}
return nil
})
return objects, nil
}
func (p *LocalFileSystemStorageProvider) PutObject(user string, parent string, key string, fileBuffer *bytes.Buffer) error {
fullPath := filepath.Join(p.path, key)
err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm)
if err != nil {
return fmt.Errorf("Casdoor fails to create folder: \"%s\" for local file system storage provider: %s. Make sure Casdoor process has correct permission to create/access it, or you can create it manually in advance", filepath.Dir(fullPath), err.Error())
}
dst, err := os.Create(filepath.Clean(fullPath))
if err == nil {
_, err = io.Copy(dst, fileBuffer)
}
return err
}
func (p *LocalFileSystemStorageProvider) DeleteObject(key string) error {
return os.Remove(filepath.Join(p.path, key))
}

45
storage/provider.go Normal file
View File

@ -0,0 +1,45 @@
// Copyright 2023 The casbin 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 storage
import "bytes"
type Object struct {
Key string
LastModified string
Size int64
Url string
}
type StorageProvider interface {
ListObjects(prefix string) ([]*Object, error)
PutObject(user string, parent string, key string, fileBuffer *bytes.Buffer) error
DeleteObject(key string) error
}
func GetStorageProvider(typ string, clientId string, providerName string) (StorageProvider, error) {
var p StorageProvider
var err error
if typ == "Local File System" {
p, err = NewLocalFileSystemStorageProvider(clientId)
} else {
p, err = NewCasdoorProvider(providerName)
}
if err != nil {
return nil, err
}
return p, nil
}

View File

@ -31,7 +31,8 @@ func TestStorage(t *testing.T) {
controllers.InitAuthConfig()
provider := "provider_storage_casibase"
objects, err := storage.ListObjects(provider, "")
providerObj, err := storage.NewCasdoorProvider(provider)
objects, err := providerObj.ListObjects("")
if err != nil {
panic(err)
}

51
txt/docx.go Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2023 The casbin 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 txt
import (
"fmt"
"strings"
"github.com/unidoc/unioffice/document"
)
func getTextFromDocx(path string) (string, error) {
docx, err := document.Open(path)
if err != nil {
return "", err
}
var paragraphs []string
for _, para := range docx.Paragraphs() {
var paraText string
for _, run := range para.Runs() {
paraText += run.Text()
}
if len(para.Runs()) > 1 {
paragraphs = append(paragraphs, paraText+"\n\n")
} else {
paragraphs = append(paragraphs, paraText+"\n")
}
}
if len(paragraphs) == 0 {
return "", fmt.Errorf(".docx file is empty")
}
text := strings.Join(paragraphs, "")
return text, nil
}

View File

@ -12,17 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package ai
package txt
import (
"github.com/casbin/casibase/proxy"
"github.com/sashabaranov/go-openai"
"os"
)
func getProxyClientFromToken(authToken string) *openai.Client {
config := openai.DefaultConfig(authToken)
config.HTTPClient = proxy.ProxyHttpClient
func getTextFromPlain(path string) (string, error) {
bs, err := os.ReadFile(path)
if err != nil {
return "", err
}
c := openai.NewClientWithConfig(config)
return c
res := string(bs)
return res, nil
}

60
txt/pdf.go Normal file
View File

@ -0,0 +1,60 @@
// Copyright 2023 The casbin 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 txt
import (
"strings"
"github.com/ledongthuc/pdf"
)
func getTextFromPdf(path string) (string, error) {
f, r, err := pdf.Open(path)
if err != nil {
return "", err
}
defer f.Close()
totalPage := r.NumPage()
var mergedTexts []string
for pageIndex := 1; pageIndex <= totalPage; pageIndex++ {
p := r.Page(pageIndex)
if p.V.IsNull() {
continue
}
var lastTextStyle pdf.Text
var mergedSentence string
texts := p.Content().Text
for _, text := range texts {
if text.Y == lastTextStyle.Y {
mergedSentence += text.S
} else {
if mergedSentence != "" {
mergedTexts = append(mergedTexts, mergedSentence)
}
lastTextStyle = text
mergedSentence = text.S
}
}
if mergedSentence != "" {
mergedTexts = append(mergedTexts, mergedSentence)
}
}
mergedText := strings.Join(mergedTexts, "\n")
return mergedText, nil
}

75
txt/text.go Normal file
View File

@ -0,0 +1,75 @@
// Copyright 2023 The casbin 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 txt
import (
"fmt"
"os"
"strings"
)
func GetTextSections(text string) []string {
const maxLength = 210 * 3
var res []string
var temp string
for _, line := range strings.Split(text, "\n") {
if len(temp)+len(line) <= maxLength {
temp += line
} else {
res = append(res, temp)
temp = line
}
}
if len(temp) > 0 {
res = append(res, temp)
}
return res
}
func GetSupportedFileTypes() []string {
return []string{".txt", ".md", ".docx", ".pdf"}
}
func GetParsedTextFromUrl(url string, ext string) (string, error) {
path, err := getTempFilePathFromUrl(url)
if err != nil {
return "", err
}
defer func() {
err = os.Remove(path)
if err != nil {
fmt.Printf("%v\n", err.Error())
}
}()
var res string
if ext == ".txt" || ext == ".md" {
res, err = getTextFromPlain(path)
} else if ext == ".docx" {
res, err = getTextFromDocx(path)
} else if ext == ".pdf" {
res, err = getTextFromPdf(path)
} else {
return "", fmt.Errorf("unsupported file type: %s", ext)
}
if err != nil {
return "", err
}
return res, nil
}

61
txt/util.go Normal file
View File

@ -0,0 +1,61 @@
// Copyright 2023 The casbin 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 txt
import (
"bytes"
"io"
"io/ioutil"
"path/filepath"
"github.com/casbin/casibase/proxy"
)
func downloadFile(url string) (*bytes.Buffer, error) {
httpClient := proxy.GetHttpClient(url)
resp, err := httpClient.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
fileBuffer := bytes.NewBuffer(nil)
_, err = io.Copy(fileBuffer, resp.Body)
if err != nil {
return nil, err
}
return fileBuffer, nil
}
func getTempFilePathFromUrl(url string) (string, error) {
buffer, err := downloadFile(url)
if err != nil {
return "", err
}
file, err := ioutil.TempFile("", filepath.Base(url))
if err != nil {
return "", err
}
_, err = io.Copy(file, buffer)
if err != nil {
return "", err
}
return file.Name(), nil
}

View File

@ -33,8 +33,11 @@
"react-force-graph-2d": "^1.23.8",
"react-force-graph-3d": "^1.21.10",
"react-i18next": "^11.8.7",
"react-markdown": "^8.0.7",
"react-router-dom": "^5.3.3",
"react-scripts": "5.0.1",
"remark-frontmatter": "^4.0.1",
"remark-gfm": "^3.0.1",
"xlsx": "^0.16.9"
},
"scripts": {
@ -44,8 +47,10 @@
"eject": "craco eject",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
"fix": "eslint --fix src/**/*.{js,jsx,ts,tsx}",
"lint:css": "stylelint src/**/*.{css,less} --fix"
"fix": "eslint --fix src/ --ext .js",
"lint:js": "eslint --fix src/ --ext .js",
"lint:css": "stylelint src/**/*.{css,less} --fix",
"lint": "yarn lint:js && yarn lint:css"
},
"eslintConfig": {
"extends": "react-app"

View File

@ -40,11 +40,14 @@ import VectorListPage from "./VectorListPage";
import VectorEditPage from "./VectorEditPage";
import SigninPage from "./SigninPage";
import i18next from "i18next";
import {withTranslation} from "react-i18next";
import LanguageSelect from "./LanguageSelect";
import ChatEditPage from "./ChatEditPage";
import ChatListPage from "./ChatListPage";
import MessageListPage from "./MessageListPage";
import MessageEditPage from "./MessageEditPage";
import TaskListPage from "./TaskListPage";
import TaskEditPage from "./TaskEditPage";
import ChatPage from "./ChatPage";
const {Header, Footer, Content} = Layout;
@ -104,6 +107,10 @@ class App extends Component {
this.setState({selectedMenuKey: "/chats"});
} else if (uri.includes("/messages")) {
this.setState({selectedMenuKey: "/messages"});
} else if (uri.includes("/tasks")) {
this.setState({selectedMenuKey: "/tasks"});
} else if (uri.includes("/chat")) {
this.setState({selectedMenuKey: "/chat"});
} else {
this.setState({selectedMenuKey: "null"});
}
@ -269,39 +276,25 @@ class App extends Component {
res.push(Setting.getItem(<Link to="/">{i18next.t("general:Home")}</Link>, "/"));
if (this.state.account.tag === "Video") {
res.push(Setting.getItem(<Link to="/videos">{i18next.t("general:Videos")}</Link>,
"/videos"));
res.push(Setting.getItem(<Link to="/videos">{i18next.t("general:Videos")}</Link>, "/videos"));
return res;
}
res.push(Setting.getItem(<Link to="/stores">{i18next.t("general:Stores")}</Link>,
"/stores"));
res.push(Setting.getItem(<Link to="/chat">{i18next.t("general:Chat")}</Link>, "/chat"));
res.push(Setting.getItem(<Link to="/stores">{i18next.t("general:Stores")}</Link>, "/stores"));
if (Conf.EnableExtraPages) {
res.push(Setting.getItem(<Link to="/clustering">{i18next.t("general:Clustering")}</Link>,
"/clustering"));
res.push(Setting.getItem(<Link to="/wordsets">{i18next.t("general:Wordsets")}</Link>,
"/wordsets"));
res.push(Setting.getItem(<Link to="/factorsets">{i18next.t("general:Factorsets")}</Link>,
"/factorsets"));
res.push(Setting.getItem(<Link to="/videos">{i18next.t("general:Videos")}</Link>,
"/videos"));
res.push(Setting.getItem(<Link to="/clustering">{i18next.t("general:Clustering")}</Link>, "/clustering"));
res.push(Setting.getItem(<Link to="/wordsets">{i18next.t("general:Wordsets")}</Link>, "/wordsets"));
res.push(Setting.getItem(<Link to="/factorsets">{i18next.t("general:Factorsets")}</Link>, "/factorsets"));
res.push(Setting.getItem(<Link to="/videos">{i18next.t("general:Videos")}</Link>, "/videos"));
}
res.push(Setting.getItem(<Link to="/providers">{i18next.t("general:Providers")}</Link>,
"/providers"));
res.push(Setting.getItem(<Link to="/vectors">{i18next.t("general:Vectors")}</Link>,
"/vectors"));
res.push(Setting.getItem(<Link to="/chats">{i18next.t("general:Chats")}</Link>,
"/chats"));
res.push(Setting.getItem(<Link to="/messages">{i18next.t("general:Messages")}</Link>,
"/messages"));
res.push(Setting.getItem(<Link to="/providers">{i18next.t("general:Providers")}</Link>, "/providers"));
res.push(Setting.getItem(<Link to="/vectors">{i18next.t("general:Vectors")}</Link>, "/vectors"));
res.push(Setting.getItem(<Link to="/chats">{i18next.t("general:Chats")}</Link>, "/chats"));
res.push(Setting.getItem(<Link to="/messages">{i18next.t("general:Messages")}</Link>, "/messages"));
res.push(Setting.getItem(<Link to="/tasks">{i18next.t("general:Tasks")}</Link>, "/tasks"));
if (Setting.isLocalAdminUser(this.state.account)) {
res.push(Setting.getItem(
@ -374,6 +367,8 @@ class App extends Component {
<Route exact path="/chats/:chatName" render={(props) => this.renderSigninIfNotSignedIn(<ChatEditPage account={this.state.account} {...props} />)} />
<Route exact path="/messages" render={(props) => this.renderSigninIfNotSignedIn(<MessageListPage account={this.state.account} {...props} />)} />
<Route exact path="/messages/:messageName" render={(props) => this.renderSigninIfNotSignedIn(<MessageEditPage account={this.state.account} {...props} />)} />
<Route exact path="/tasks" render={(props) => this.renderSigninIfNotSignedIn(<TaskListPage account={this.state.account} {...props} />)} />
<Route exact path="/tasks/:taskName" render={(props) => this.renderSigninIfNotSignedIn(<TaskEditPage account={this.state.account} {...props} />)} />
<Route exact path="/chat" render={(props) => this.renderSigninIfNotSignedIn(<ChatPage account={this.state.account} {...props} />)} />
</Switch>
);
@ -439,7 +434,7 @@ class App extends Component {
renderFooter() {
// How to keep your footer where it belongs ?
// https://www.freecodecamp.org/neyarnws/how-to-keep-your-footer-where-it-belongs-59c6aa05c59c/
// https://www.freecodecamp.org/news/how-to-keep-your-footer-where-it-belongs-59c6aa05c59c
return (
<React.Fragment>
@ -493,4 +488,4 @@ class App extends Component {
}
}
export default withRouter(App);
export default withRouter(withTranslation()(App));

View File

@ -101,16 +101,20 @@ img {
}
}
.cs-conversation-header__content .cs-conversation-header__user-name {
background-color: rgb(246,240,255) !important;
}
.cs-message--incoming .cs-message__content {
background-color: #f3ecfc !important;
background-color: rgb(246,240,255) !important;
}
.cs-message-input__content-editor-wrapper {
background-color: #f3ecfc !important;
background-color: rgb(242,242,242) !important;
}
.cs-message-input__content-editor {
background-color: #f3ecfc !important;
background-color: rgb(242,242,242) !important;
}
.cs-button--send {
@ -118,5 +122,5 @@ img {
}
.cs-message--outgoing .cs-message__content {
background-color: #f3ecfc !important;
background-color: rgb(242,242,242) !important;
}

View File

@ -16,7 +16,7 @@ import React from "react";
import {Avatar, ChatContainer, ConversationHeader, MainContainer, Message, MessageInput, MessageList} from "@chatscope/chat-ui-kit-react";
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
const robot = "https://cdn.casbin.com/casdoor/resource/built-in/admin/gpt.png";
const aiAvatar = "https://cdn.casbin.com/casdoor/static/gpt.png";
class ChatBox extends React.Component {
constructor(props) {
@ -33,10 +33,10 @@ class ChatBox extends React.Component {
messages = [];
}
return (
<MainContainer style={{display: "flex", width: "100%", height: "100%"}} >
<MainContainer style={{display: "flex", width: "100%", height: "100%", border: "1px solid rgb(242,242,242)", borderRadius: "6px"}} >
<ChatContainer style={{display: "flex", width: "100%", height: "100%"}}>
<ConversationHeader>
<Avatar src={robot} name="AI" />
<ConversationHeader style={{backgroundColor: "rgb(246,240,255)"}}>
<Avatar src={aiAvatar} name="AI" />
<ConversationHeader.Content userName="AI" />
</ConversationHeader>
<MessageList>
@ -47,7 +47,7 @@ class ChatBox extends React.Component {
sender: message.name,
direction: message.author === "AI" ? "incoming" : "outgoing",
}} avatarPosition={message.author === "AI" ? "tl" : "tr"}>
<Avatar src={message.author === "AI" ? robot : this.props.account.avatar} name="GPT" />
<Avatar src={message.author === "AI" ? aiAvatar : this.props.account.avatar} name="GPT" />
</Message>
))}
</MessageList>

View File

@ -49,7 +49,7 @@ class ChatListPage extends React.Component {
newChat() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `chat_${randomName}`,
createdTime: moment().format(),
updatedTime: moment().format(),

View File

@ -41,7 +41,7 @@ class ChatPage extends BaseListPage {
newChat(chat) {
const randomName = Setting.getRandomName();
return {
owner: "admin", // this.props.account.applicationName,
owner: "admin",
name: `chat_${randomName}`,
createdTime: moment().format(),
updatedTime: moment().format(),
@ -59,7 +59,7 @@ class ChatPage extends BaseListPage {
newMessage(text) {
const randomName = Setting.getRandomName();
return {
owner: "admin", // this.props.account.messagename,
owner: "admin",
name: `message_${randomName}`,
createdTime: moment().format(),
// organization: this.props.account.owner,

View File

@ -13,8 +13,8 @@
// limitations under the License.
export const AuthConfig = {
// serverUrl: "https://door.casdoor.com",
serverUrl: "http://localhost:7001",
serverUrl: "https://door.casdoor.com",
// serverUrl: "http://localhost:7001",
clientId: "af6b5aa958822fb9dc33",
appName: "app-casibase",
organizationName: "casbin",
@ -30,6 +30,7 @@ export const ForceLanguage = "";
export const DefaultLanguage = "en";
export const AppUrl = "";
export const IsDemoMode = false;
export const ThemeDefault = {
themeType: "default",

View File

@ -49,11 +49,11 @@ class FactorsetListPage extends React.Component {
newFactorset() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `factorset_${randomName}`,
createdTime: moment().format(),
displayName: `New Factorset - ${randomName}`,
url: "https://github.com/Embedding/Chinese-Word-Factors",
url: "https://github.com/Embedding/Chinese-Word-Vectors",
fileName: "sgns.target.word-word.dynwin5.thr10.neg5.dim300.iter5",
fileSize: "1.69 GB",
dimension: 128,

View File

@ -21,6 +21,9 @@ import * as Setting from "./Setting";
import * as FileBackend from "./backend/FileBackend";
import DocViewer, {DocViewerRenderers} from "@cyntler/react-doc-viewer";
import FileViewer from "react-file-viewer";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkFrontmatter from "remark-frontmatter";
import i18next from "i18next";
import * as PermissionBackend from "./backend/PermissionBackend";
import * as PermissionUtil from "./PermissionUtil";
@ -100,10 +103,12 @@ class FileTree extends React.Component {
}
checkUploadFile(info) {
for (let i = 0; i < info.fileList.length; i++) {
const filename = info.fileList[i].name;
if (this.getCacheApp(filename) === "" && filename.endsWith(".txt")) {
return true;
if (Conf.EnableExtraPages) {
for (let i = 0; i < info.fileList.length; i++) {
const filename = info.fileList[i].name;
if (this.getCacheApp(filename) === "" && filename.endsWith(".txt")) {
return true;
}
}
}
return false;
@ -117,7 +122,7 @@ class FileTree extends React.Component {
{" " + i18next.t("store:Please choose the type of your data")}
</div>
}
visible={this.state.isUploadFileModalVisible}
open={this.state.isUploadFileModalVisible}
onCancel={() => {
this.setState({
isUploadFileModalVisible: false,
@ -171,11 +176,16 @@ class FileTree extends React.Component {
Promise.all(promises)
.then((values) => {
Setting.showMessage("success", "File uploaded successfully");
this.props.onRefresh();
const res = values[0];
if (res.status === "ok") {
Setting.showMessage("success", "File added successfully");
this.props.onRefresh();
} else {
Setting.showMessage("error", `File failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `File failed to upload: ${error}`);
Setting.showMessage("error", `File failed to add: ${error}`);
});
}
@ -530,7 +540,6 @@ class FileTree extends React.Component {
}>
<span onClick={(e) => e.stopPropagation()}>
<Button style={{marginRight: "5px"}} icon={<FolderAddOutlined />} size="small" onClick={(e) => {
this.addFile();
e.stopPropagation();
}} />
</span>
@ -635,6 +644,10 @@ class FileTree extends React.Component {
return ["png", "jpg", "jpeg", "gif", "bmp", "pdf", "xlsx", "docx", "mp4", "webm", "mp3"].includes(ext);
}
isExtForMarkdownViewer(ext) {
return ["md"].includes(ext);
}
renderFileViewer(store) {
if (this.state.checkedFiles.length !== 0) {
const outerFile = {children: this.state.checkedFiles};
@ -683,7 +696,7 @@ class FileTree extends React.Component {
return (
<DocViewer
key={path}
style={{height: this.getEditorHeightCss()}}
style={{height: this.getEditorHeightCss(), border: "1px solid rgb(242,242,242)", borderRadius: "6px"}}
pluginRenderers={DocViewerRenderers}
documents={[{uri: url}]}
theme={{
@ -719,6 +732,18 @@ class FileTree extends React.Component {
/>
</a>
);
} else if (this.isExtForMarkdownViewer(ext)) {
// https://github.com/remarkjs/react-markdown
return (
<div className="markdownContainer" style={{height: this.getEditorHeightCss(), overflow: "auto", border: "1px solid rgb(242,242,242)", borderRadius: "6px"}}>
<ReactMarkdown
key={path}
remarkPlugins={[remarkGfm, remarkFrontmatter]}
>
{this.state.text}
</ReactMarkdown>
</div>
);
} else {
// https://github.com/scniro/react-codemirror2
if (this.state.loading) {
@ -811,30 +836,40 @@ class FileTree extends React.Component {
<Descriptions.Item label={i18next.t("factorset:File name")}>
{file.title}
</Descriptions.Item>
<Descriptions.Item label={i18next.t("store:File type")}>
{Setting.getExtFromFile(file)}
</Descriptions.Item>
{
!Conf.EnableExtraPages ? null : (
<Descriptions.Item label={i18next.t("store:File type")}>
{Setting.getExtFromFile(file)}
</Descriptions.Item>
)
}
<Descriptions.Item label={i18next.t("factorset:File size")}>
{Setting.getFriendlyFileSize(file.size)}
</Descriptions.Item>
<Descriptions.Item label={i18next.t("general:Created time")}>
{Setting.getFormattedDate(file.createdTime)}
</Descriptions.Item>
<Descriptions.Item label={i18next.t("store:Collected time")}>
{Setting.getFormattedDate(Setting.getCollectedTime(file.title))}
<DatePicker key={file.key} showTime defaultValue={this.getMomentTime(this.getPropertyValue(file, "collectedTime"))} onChange={(value, dateString) => {
this.setPropertyValue(file, "collectedTime", value.format());
}} onOk={(value) => {}} />
</Descriptions.Item>
<Descriptions.Item label={i18next.t("store:Subject")}>
<Select virtual={false} style={{width: "120px"}} value={getSubjectDisplayName(this.getPropertyValue(file, "subject"))} onChange={(value => {
this.setPropertyValue(file, "subject", value);
})}>
{
subjectOptions.map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
</Descriptions.Item>
{
!Conf.EnableExtraPages ? null : (
<React.Fragment>
<Descriptions.Item label={i18next.t("store:Collected time")}>
{Setting.getFormattedDate(Setting.getCollectedTime(file.title))}
<DatePicker key={file.key} showTime defaultValue={this.getMomentTime(this.getPropertyValue(file, "collectedTime"))} onChange={(value, dateString) => {
this.setPropertyValue(file, "collectedTime", value.format());
}} onOk={(value) => {}} />
</Descriptions.Item>
<Descriptions.Item label={i18next.t("store:Subject")}>
<Select virtual={false} style={{width: "120px"}} value={getSubjectDisplayName(this.getPropertyValue(file, "subject"))} onChange={(value => {
this.setPropertyValue(file, "subject", value);
})}>
{
subjectOptions.map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
</Descriptions.Item>
</React.Fragment>
)
}
</Descriptions>
</div>
);
@ -842,8 +877,12 @@ class FileTree extends React.Component {
getEditorHeightCss() {
// 79, 123
const filePaneHeight = this.filePane.current?.offsetHeight;
return `calc(100vh - ${filePaneHeight + 186}px)`;
let filePaneHeight = this.filePane.current?.offsetHeight;
if (!filePaneHeight) {
filePaneHeight = 0;
}
return `calc(100vh - ${filePaneHeight + 186 - (Conf.EnableExtraPages ? 0 : 50)}px)`;
}
render() {
@ -881,7 +920,7 @@ class FileTree extends React.Component {
<Col span={16}>
<Card className="content-warp-card-filetreeright">
<div style={{margin: "-25px"}}>
<div style={{height: this.getEditorHeightCss()}}>
<div style={{height: this.getEditorHeightCss(), border: "1px solid rgb(242,242,242)", borderRadius: "6px"}}>
{
this.renderFileViewer(this.props.store)
}

View File

@ -13,11 +13,12 @@
// limitations under the License.
import React from "react";
import {Spin} from "antd";
import {Col, Row, Spin} from "antd";
import * as StoreBackend from "./backend/StoreBackend";
import FileTree from "./FileTree";
import i18next from "i18next";
import * as Setting from "./Setting";
import ChatPage from "./ChatPage";
class FileTreePage extends React.Component {
constructor(props) {
@ -61,12 +62,21 @@ class FileTreePage extends React.Component {
}
return (
<FileTree account={this.props.account} store={this.state.store} onUpdateStore={(store) => {
this.setState({
store: store,
});
Setting.submitStoreEdit(store);
}} onRefresh={() => this.getStore()} />
<div>
<Row>
<Col span={14}>
<FileTree account={this.props.account} store={this.state.store} onUpdateStore={(store) => {
this.setState({
store: store,
});
Setting.submitStoreEdit(store);
}} onRefresh={() => this.getStore()} />
</Col>
<Col span={10}>
<ChatPage account={this.props.account} />
</Col>
</Row>
</div>
);
}
}

View File

@ -27,7 +27,6 @@ class LanguageSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
languages: props.languages ?? Setting.Countries.map(item => item.key),
};

View File

@ -49,7 +49,7 @@ class MessageListPage extends React.Component {
newMessage() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `message_${randomName}`,
createdTime: moment().format(),
// organization: "Message Organization - 1",

View File

@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import {Button, Card, Col, Input, Row, Select} from "antd";
import {Button, Card, Col, Input, InputNumber, Row, Select, Slider} from "antd";
import * as ProviderBackend from "./backend/ProviderBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
@ -49,8 +49,10 @@ class ProviderEditPage extends React.Component {
}
parseProviderField(key, value) {
if ([""].includes(key)) {
if (["topK"].includes(key)) {
value = Setting.myParseInt(value);
} else if (["temperature", "topP", "frequencyPenalty", "presencePenalty"].includes(key)) {
value = Setting.myParseFloat(value);
}
return value;
}
@ -65,6 +67,44 @@ class ProviderEditPage extends React.Component {
});
}
InputSlider(props) {
const {
min,
max,
step,
value,
onChange,
} = props;
return (
<>
<Col span={2}>
<InputNumber
min={min}
max={max}
step={step}
style={{width: "100%"}}
value={value}
onChange={onChange}
/>
</Col>
<Col span={20}>
<Slider
min={min}
max={max}
step={step}
style={{
marginLeft: "1%",
marginRight: "1%",
}}
value={value}
onChange={onChange}
/>
</Col>
</>
);
}
renderProvider() {
return (
<Card size="small" title={
@ -101,9 +141,9 @@ class ProviderEditPage extends React.Component {
<Select virtual={false} style={{width: "100%"}} value={this.state.provider.category} onChange={(value => {this.updateProviderField("category", value);})}>
{
[
{id: "Model", name: "Model"},
{id: "Vector Database", name: "Vector Database"},
{id: "Storage", name: "Storage"},
{id: "Model", name: "Model"},
{id: "Embedding", name: "Embedding"},
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
@ -116,24 +156,284 @@ class ProviderEditPage extends React.Component {
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.provider.type} onChange={(value => {this.updateProviderField("type", value);})}>
{
[
{id: "OpenAI API - GPT 3.5", name: "OpenAI API - GPT 3.5"},
{id: "OpenAI API - GPT 4", name: "OpenAI API - GPT 4"},
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
Setting.getProviderTypeOptions(this.state.provider.category)
// .sort((a, b) => a.name.localeCompare(b.name))
.map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Secret key")}:
</Col>
<Col span={22} >
<Input value={this.state.provider.clientSecret} onChange={e => {
this.updateProviderField("clientSecret", e.target.value);
}} />
</Col>
</Row>
{
this.state.provider.category === "Storage" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Sub type")}:
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.provider.subType} onChange={(value => {this.updateProviderField("subType", value);})}>
{
Setting.getProviderSubTypeOptions(this.state.provider.category, this.state.provider.type)
// .sort((a, b) => a.name.localeCompare(b.name))
.map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
</Col>
</Row>
)
}
{
(this.state.provider.type !== "Ernie" && this.state.provider.category !== "Storage") ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{
(this.state.provider.category !== "Storage") ? i18next.t("provider:API key") :
i18next.t("provider:Path")}:
</Col>
<Col span={22} >
<Input value={this.state.provider.clientId} onChange={e => {
this.updateProviderField("clientId", e.target.value);
}} />
</Col>
</Row>
)
}
{
this.state.provider.category === "Storage" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Secret key")}:
</Col>
<Col span={22} >
<Input value={this.state.provider.clientSecret} onChange={e => {
this.updateProviderField("clientSecret", e.target.value);
}} />
</Col>
</Row>
)
}
{
(this.state.provider.category === "Model" && this.state.provider.type === "OpenAI") ? (
<>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Temperature")}:
</Col>
<this.InputSlider
min={0}
max={2}
step={0.01}
value={this.state.provider.temperature}
onChange={(value) => {
this.updateProviderField("temperature", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Top P")}:
</Col>
<this.InputSlider
min={0}
max={1}
step={0.01}
value={this.state.provider.topP}
onChange={(value) => {
this.updateProviderField("topP", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Frequency penalty")}:
</Col>
<this.InputSlider
label={i18next.t("provider:Frequency penalty")}
min={-2}
max={2}
step={0.01}
value={this.state.provider.frequencyPenalty}
onChange={(value) => {
this.updateProviderField("frequencyPenalty", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Presence penalty")}:
</Col>
<this.InputSlider
label={i18next.t("provider:Presence penalty")}
min={-2}
max={2}
step={0.01}
value={this.state.provider.presencePenalty}
onChange={(value) => {
this.updateProviderField("presencePenalty", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
</>
) : null
}
{
(this.state.provider.category === "Model" && this.state.provider.type === "OpenRouter") ? (
<>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Temperature")}:
</Col>
<this.InputSlider
min={0}
max={2}
step={0.01}
value={this.state.provider.temperature}
onChange={(value) => {
this.updateProviderField("temperature", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Top P")}:
</Col>
<this.InputSlider
min={0}
max={1}
step={0.01}
value={this.state.provider.topP}
onChange={(value) => {
this.updateProviderField("topP", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
</>
) : null
}
{
(this.state.provider.category === "Model" && this.state.provider.type === "iFlytek") ? (
<>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Temperature")}:
</Col>
<this.InputSlider
min={0}
max={1}
step={0.01}
value={this.state.provider.temperature}
onChange={(value) => {
this.updateProviderField("temperature", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Top K")}:
</Col>
<this.InputSlider
min={1}
max={6}
step={1}
value={this.state.provider.topK}
onChange={(value) => {
this.updateProviderField("topK", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
</>
) : null
}
{
(this.state.provider.category === "Model" && this.state.provider.type === "Ernie") ? (
<>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Temperature")}:
</Col>
<this.InputSlider
min={0.01}
max={1}
step={0.01}
value={this.state.provider.temperature}
onChange={(value) => {
this.updateProviderField("temperature", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Top P")}:
</Col>
<this.InputSlider
min={0}
max={1}
step={0.01}
value={this.state.provider.topP}
onChange={(value) => {
this.updateProviderField("topP", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Presence penalty")}:
</Col>
<this.InputSlider
label={i18next.t("provider:Presence penalty")}
min={1}
max={2}
step={0.01}
value={this.state.provider.presencePenalty}
onChange={(value) => {
this.updateProviderField("presencePenalty", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
</>
) : null
}
{
(this.state.provider.category === "Model" && this.state.provider.type === "MiniMax") ? (
<>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:groupID")}:
</Col>
<Col span={22} >
<Input value={this.state.provider.clientId} onChange={e => {
this.updateProviderField("clientId", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("provider:Temperature")}:
</Col>
<this.InputSlider
min={0.1}
max={1}
step={0.1}
value={this.state.provider.temperature || 0.7}
onChange={(value) => {
this.updateProviderField("temperature", value);
}}
isMobile={Setting.isMobile()}
/>
</Row>
</>
) : null
}
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Provider URL")}:

View File

@ -49,14 +49,20 @@ class ProviderListPage extends React.Component {
newProvider() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `provider_${randomName}`,
createdTime: moment().format(),
displayName: `New Provider - ${randomName}`,
category: "Model",
type: "OpenAI API - GPT 3.5",
type: "OpenAI",
subType: "text-davinci-003",
clientId: "",
clientSecret: "",
temperature: 1,
topP: 1,
topK: 4,
frequencyPenalty: 0,
presencePenalty: 0,
providerUrl: "https://platform.openai.com/account/api-keys",
};
}
@ -102,7 +108,7 @@ class ProviderListPage extends React.Component {
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "140px",
width: "180px",
sorter: (a, b) => a.name.localeCompare(b.name),
render: (text, record, index) => {
return (
@ -116,41 +122,55 @@ class ProviderListPage extends React.Component {
title: i18next.t("general:Display name"),
dataIndex: "displayName",
key: "displayName",
width: "200px",
width: "220px",
sorter: (a, b) => a.displayName.localeCompare(b.displayName),
},
{
title: i18next.t("provider:Category"),
dataIndex: "category",
key: "category",
width: "160px",
width: "110px",
sorter: (a, b) => a.category.localeCompare(b.category),
},
{
title: i18next.t("provider:Type"),
dataIndex: "type",
key: "type",
width: "160px",
width: "150px",
sorter: (a, b) => a.type.localeCompare(b.type),
},
{
title: i18next.t("provider:Sub type"),
dataIndex: "subType",
key: "subType",
width: "180px",
sorter: (a, b) => a.subType.localeCompare(b.subType),
},
{
title: i18next.t("provider:API key"),
dataIndex: "clientId",
key: "clientId",
width: "240px",
sorter: (a, b) => a.clientId.localeCompare(b.clientId),
},
{
title: i18next.t("provider:Secret key"),
dataIndex: "clientSecret",
key: "clientSecret",
width: "160px",
width: "120px",
sorter: (a, b) => a.clientSecret.localeCompare(b.clientSecret),
},
{
title: i18next.t("provider:Provider URL"),
dataIndex: "providerUrl",
key: "providerUrl",
width: "250px",
// width: "250px",
sorter: (a, b) => a.providerUrl.localeCompare(b.providerUrl),
render: (text, record, index) => {
return (
<a target="_blank" rel="noreferrer" href={text}>
{
Setting.getShortText(text)
Setting.getShortText(text, 80)
}
</a>
);

View File

@ -77,6 +77,11 @@ export function myParseInt(i) {
return isNaN(res) ? 0 : res;
}
export function myParseFloat(f) {
const res = parseFloat(f);
return isNaN(res) ? 0.0 : res;
}
export function openLink(link) {
// this.props.history.push(link);
const w = window.open("about:blank");
@ -217,41 +222,14 @@ export function getLanguage() {
export function setLanguage(language) {
localStorage.setItem("language", language);
changeMomentLanguage(language);
i18next.changeLanguage(language);
}
export function changeLanguage(language) {
localStorage.setItem("language", language);
changeMomentLanguage(language);
i18next.changeLanguage(language);
setLanguage(language);
window.location.reload(true);
}
export function changeMomentLanguage(lng) {
return;
// if (lng === "zh") {
// moment.locale("zh", {
// relativeTime: {
// future: "%s内",
// past: "%s前",
// s: "几秒",
// ss: "%d秒",
// m: "1分钟",
// mm: "%d分钟",
// h: "1小时",
// hh: "%d小时",
// d: "1天",
// dd: "%d天",
// M: "1个月",
// MM: "%d个月",
// y: "1年",
// yy: "%d年",
// },
// });
// }
}
export function getTag(text, type, state) {
let icon = null;
let style = {};
@ -610,8 +588,6 @@ export const Countries = [{label: "English", key: "en", country: "US", alt: "Eng
{label: "日本語", key: "ja", country: "JP", alt: "日本語"},
{label: "한국어", key: "ko", country: "KR", alt: "한국어"},
{label: "Русский", key: "ru", country: "RU", alt: "Русский"},
{label: "TiếngViệt", key: "vi", country: "VN", alt: "TiếngViệt"},
{label: "Português", key: "pt", country: "BR", alt: "Português"},
];
export function getItem(label, key, icon, children, type) {
@ -648,3 +624,227 @@ export function renderExternalLink() {
</svg>
);
}
export function isResponseDenied(data) {
return data.msg === "Unauthorized operation";
}
export function getProviderTypeOptions(category) {
if (category === "Storage") {
return (
[
{id: "Local File System", name: "Local File System"},
]
);
} else if (category === "Model") {
return (
[
{id: "OpenAI", name: "OpenAI"},
{id: "Hugging Face", name: "Hugging Face"},
{id: "Claude", name: "Claude"},
{id: "OpenRouter", name: "OpenRouter"},
{id: "Ernie", name: "Ernie"},
{id: "iFlytek", name: "iFlytek"},
{id: "ChatGLM", name: "ChatGLM"},
{id: "MiniMax", name: "MiniMax"},
{id: "Local", name: "Local"},
]
);
} else if (category === "Embedding") {
return (
[
{id: "OpenAI", name: "OpenAI"},
{id: "Hugging Face", name: "Hugging Face"},
{id: "Cohere", name: "Cohere"},
{id: "Ernie", name: "Ernie"},
]
);
} else {
return [];
}
}
export function getProviderSubTypeOptions(category, type) {
if (type === "OpenAI") {
if (category === "Model") {
return (
[
{id: "gpt-4-32k-0613", name: "gpt-4-32k-0613"},
{id: "gpt-4-32k-0314", name: "gpt-4-32k-0314"},
{id: "gpt-4-32k", name: "gpt-4-32k"},
{id: "gpt-4-0613", name: "gpt-4-0613"},
{id: "gpt-4-0314", name: "gpt-4-0314"},
{id: "gpt-4", name: "gpt-4"},
{id: "gpt-3.5-turbo-0613", name: "gpt-3.5-turbo-0613"},
{id: "gpt-3.5-turbo-0301", name: "gpt-3.5-turbo-0301"},
{id: "gpt-3.5-turbo-16k", name: "gpt-3.5-turbo-16k"},
{id: "gpt-3.5-turbo-16k-0613", name: "gpt-3.5-turbo-16k-0613"},
{id: "gpt-3.5-turbo", name: "gpt-3.5-turbo"},
{id: "text-davinci-003", name: "text-davinci-003"},
{id: "text-davinci-002", name: "text-davinci-002"},
{id: "text-curie-001", name: "text-curie-001"},
{id: "text-babbage-001", name: "text-babbage-001"},
{id: "text-ada-001", name: "text-ada-001"},
{id: "text-davinci-001", name: "text-davinci-001"},
{id: "davinci-instruct-beta", name: "davinci-instruct-beta"},
{id: "davinci", name: "davinci"},
{id: "curie-instruct-beta", name: "curie-instruct-beta"},
{id: "curie", name: "curie"},
{id: "ada", name: "ada"},
{id: "babbage", name: "babbage"},
]
);
} else if (category === "Embedding") {
return (
[
{id: "1", name: "AdaSimilarity"},
{id: "2", name: "BabbageSimilarity"},
{id: "3", name: "CurieSimilarity"},
{id: "4", name: "DavinciSimilarity"},
{id: "5", name: "AdaSearchDocument"},
{id: "6", name: "AdaSearchQuery"},
{id: "7", name: "BabbageSearchDocument"},
{id: "8", name: "BabbageSearchQuery"},
{id: "9", name: "CurieSearchDocument"},
{id: "10", name: "CurieSearchQuery"},
{id: "11", name: "DavinciSearchDocument"},
{id: "12", name: "DavinciSearchQuery"},
{id: "13", name: "AdaCodeSearchCode"},
{id: "14", name: "AdaCodeSearchText"},
{id: "15", name: "BabbageCodeSearchCode"},
{id: "16", name: "BabbageCodeSearchText"},
{id: "17", name: "AdaEmbeddingV2"},
]
);
} else {
return [];
}
} else if (type === "Hugging Face") {
if (category === "Model") {
return (
[
{id: "meta-llama/Llama-2-7b", name: "meta-llama/Llama-2-7b"},
{id: "tiiuae/falcon-180B", name: "tiiuae/falcon-180B"},
{id: "bigscience/bloom", name: "bigscience/bloom"},
{id: "gpt2", name: "gpt2"},
{id: "baichuan-inc/Baichuan2-13B-Chat", name: "baichuan-inc/Baichuan2-13B-Chat"},
{id: "THUDM/chatglm2-6b", name: "THUDM/chatglm2-6b"},
]
);
} else if (category === "Embedding") {
return (
[
{id: "sentence-transformers/all-MiniLM-L6-v2", name: "sentence-transformers/all-MiniLM-L6-v2"},
]
);
} else {
return [];
}
} else if (type === "Claude") {
return (
[
{id: "claude-2", name: "claude-2"},
{id: "claude-v1", name: "claude-v1"},
{id: "claude-v1-100k", name: "claude-v1-100k"},
{id: "claude-instant-v1", name: "claude-instant-v1"},
{id: "claude-instant-v1-100k", name: "claude-instant-v1-100k"},
{id: "claude-v1.3", name: "claude-v1.3"},
{id: "claude-v1.3-100k", name: "claude-v1.3-100k"},
{id: "claude-v1.2", name: "claude-v1.2"},
{id: "claude-v1.0", name: "claude-v1.0"},
{id: "claude-instant-v1.1", name: "claude-instant-v1.1"},
{id: "claude-instant-v1.1-100k", name: "claude-instant-v1.1-100k"},
{id: "claude-instant-v1.0", name: "claude-instant-v1.0"},
]
);
} else if (type === "OpenRouter") {
return (
[
{id: "google/palm-2-codechat-bison", name: "google/palm-2-codechat-bison"},
{id: "google/palm-2-chat-bison", name: "google/palm-2-chat-bison"},
{id: "openai/gpt-3.5-turbo", name: "openai/gpt-3.5-turbo"},
{id: "openai/gpt-3.5-turbo-16k", name: "openai/gpt-3.5-turbo-16k"},
{id: "openai/gpt-4", name: "openai/gpt-4"},
{id: "openai/gpt-4-32k", name: "openai/gpt-4-32k"},
{id: "anthropic/claude-2", name: "anthropic/claude-2"},
{id: "anthropic/claude-instant-v1", name: "anthropic/claude-instant-v1"},
{id: "meta-llama/llama-2-13b-chat", name: "meta-llama/llama-2-13b-chat"},
{id: "meta-llama/llama-2-70b-chat", name: "meta-llama/llama-2-70b-chat"},
{id: "palm-2-codechat-bison", name: "palm-2-codechat-bison"},
{id: "palm-2-chat-bison", name: "palm-2-chat-bison"},
{id: "gpt-3.5-turbo", name: "gpt-3.5-turbo"},
{id: "gpt-3.5-turbo-16k", name: "gpt-3.5-turbo-16k"},
{id: "gpt-4", name: "gpt-4"},
{id: "gpt-4-32k", name: "gpt-4-32k"},
{id: "claude-2", name: "claude-2"},
{id: "claude-instant-v1", name: "claude-instant-v1"},
{id: "llama-2-13b-chat", name: "llama-2-13b-chat"},
{id: "llama-2-70b-chat", name: "llama-2-70b-chat"},
]
);
} else if (type === "Ernie") {
if (category === "Model") {
return (
[
{id: "ERNIE-Bot", name: "ERNIE-Bot"},
{id: "ERNIE-Bot-turbo", name: "ERNIE-Bot-turbo"},
{id: "BLOOMZ-7B", name: "BLOOMZ-7B"},
{id: "Llama-2", name: "Llama-2"},
]
);
} else if (category === "Embedding") {
return (
[
{id: "default", name: "default"},
]
);
} else {
return [];
}
} else if (type === "Cohere") {
return (
[
{id: "embed-english-v2.0", name: "embed-english-v2.0"},
{id: "embed-english-light-v2.0", name: "embed-english-light-v2.0"},
{id: "embed-multilingual-v2.0", name: "embed-multilingual-v2.0"},
]
);
} else if (type === "iFlytek") {
return (
[
{id: "spark-v1.5", name: "spark-v1.5"},
{id: "spark-v2.0", name: "spark-v2.0"},
]
);
} else if (type === "ChatGLM") {
return (
[
{id: "chatglm2-6b", name: "chatglm2-6b"},
]
);
} else if (type === "MiniMax") {
return (
[
{id: "abab5-chat", name: "abab5-chat"},
]
);
} else if (type === "Local") {
if (category === "Model") {
return (
[
{id: "custom-model", name: "custom-model"},
]
);
} else if (category === "Embedding") {
return (
[
{id: "custom-embedding", name: "custom-embedding"},
]
);
} else {
return [];
}
} else {
return [];
}
}

View File

@ -30,6 +30,7 @@ class StoreEditPage extends React.Component {
storeName: props.match.params.storeName,
storageProviders: [],
modelProviders: [],
embeddingProviders: [],
store: null,
};
}
@ -37,7 +38,7 @@ class StoreEditPage extends React.Component {
UNSAFE_componentWillMount() {
this.getStore();
this.getStorageProviders();
this.getModelProviders();
this.getProviders();
}
getStore() {
@ -70,12 +71,13 @@ class StoreEditPage extends React.Component {
});
}
getModelProviders() {
getProviders() {
ProviderBackend.getProviders(this.props.account.name)
.then((res) => {
if (res.status === "ok") {
this.setState({
modelProviders: res.data.filter(provider => provider.category === "Model"),
embeddingProviders: res.data.filter(provider => provider.category === "Embedding"),
});
} else {
Setting.showMessage("error", `Failed to get providers: ${res.msg}`);
@ -148,6 +150,16 @@ class StoreEditPage extends React.Component {
} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("store:Embedding provider")}:
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.store.embeddingProvider} onChange={(value => {this.updateStoreField("embeddingProvider", value);})}
options={this.state.embeddingProviders.map((provider) => Setting.getOption(`${provider.displayName} (${provider.name})`, `${provider.name}`))
} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("store:File tree")}:

View File

@ -50,12 +50,13 @@ class StoreListPage extends React.Component {
newStore() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `store_${randomName}`,
createdTime: moment().format(),
displayName: `New Store - ${randomName}`,
storageProvider: "",
modelProvider: "",
embeddingProvider: "",
propertiesMap: {},
};
}
@ -139,11 +140,23 @@ class StoreListPage extends React.Component {
title: i18next.t("store:Storage provider"),
dataIndex: "storageProvider",
key: "storageProvider",
width: "250px",
width: "290px",
sorter: (a, b) => a.storageProvider.localeCompare(b.storageProvider),
render: (text, record, index) => {
if (text === "") {
return null;
}
if (text.includes("local") || text.includes("built-in")) {
return (
<Link to={`/providers/${text}`}>
{text}
</Link>
);
}
return (
<a target="_blank" rel="noreferrer" href={Setting.getMyProfileUrl(this.state.account).replace("/account", `/providers/admin/${text}`)}>
<a target="_blank" rel="noreferrer" href={Setting.getMyProfileUrl(this.props.account).replace("/account", `/providers/admin/${text}`)}>
{text}
{Setting.renderExternalLink()}
</a>
@ -164,11 +177,25 @@ class StoreListPage extends React.Component {
);
},
},
{
title: i18next.t("store:Embedding provider"),
dataIndex: "embeddingProvider",
key: "embeddingProvider",
width: "250px",
sorter: (a, b) => a.embeddingProvider.localeCompare(b.embeddingProvider),
render: (text, record, index) => {
return (
<Link to={`/providers/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Action"),
dataIndex: "action",
key: "action",
width: "400px",
width: "380px",
render: (text, record, index) => {
return (
<div>

211
web/src/TaskEditPage.js Normal file
View File

@ -0,0 +1,211 @@
// Copyright 2023 The casbin 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 {Button, Card, Col, Input, Row, Select} from "antd";
import * as TaskBackend from "./backend/TaskBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import * as ProviderBackend from "./backend/ProviderBackend";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/javascript/javascript");
const {Option} = Select;
class TaskEditPage extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
taskName: props.match.params.taskName,
modelProviders: [],
task: null,
};
}
UNSAFE_componentWillMount() {
this.getTask();
this.getModelProviders();
}
getTask() {
TaskBackend.getTask(this.props.account.name, this.state.taskName)
.then((res) => {
if (res.status === "ok") {
this.setState({
task: res.data,
});
} else {
Setting.showMessage("error", `Failed to get task: ${res.msg}`);
}
});
}
getModelProviders() {
ProviderBackend.getProviders(this.props.account.name)
.then((res) => {
if (res.status === "ok") {
this.setState({
modelProviders: res.data.filter(provider => provider.category === "Model"),
});
} else {
Setting.showMessage("error", `Failed to get providers: ${res.msg}`);
}
});
}
parseTaskField(key, value) {
if ([""].includes(key)) {
value = Setting.myParseInt(value);
}
return value;
}
updateTaskField(key, value) {
value = this.parseTaskField(key, value);
const task = this.state.task;
task[key] = value;
this.setState({
task: task,
});
}
renderTask() {
return (
<Card size="small" title={
<div>
{i18next.t("task:Edit Task")}&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" onClick={this.submitTaskEdit.bind(this)}>{i18next.t("general:Save")}</Button>
</div>
} style={{marginLeft: "5px"}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Name")}:
</Col>
<Col span={22} >
<Input value={this.state.task.name} onChange={e => {
this.updateTaskField("name", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Display name")}:
</Col>
<Col span={22} >
<Input value={this.state.task.displayName} onChange={e => {
this.updateTaskField("displayName", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("store:Model provider")}:
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.task.provider} onChange={(value => {this.updateTaskField("provider", value);})}
options={this.state.modelProviders.map((provider) => Setting.getOption(`${provider.displayName} (${provider.name})`, `${provider.name}`))
} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("task:Application")}:
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.task.application} onChange={(value => {this.updateTaskField("application", value);})}>
{
[
{id: "Docs-Polish", name: "Docs-Polish"},
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("task:Path")}:
</Col>
<Col span={22} >
<Input value={this.state.task.path} onChange={e => {
this.updateTaskField("path", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("task:Log")}:
</Col>
<Col span={22} >
<Button style={{marginBottom: "20px", width: "100px"}} type="primary" onClick={this.runTask.bind(this)}>{i18next.t("general:Run")}</Button>
<div style={{height: "600px"}}>
<CodeMirror
value={this.state.task.log}
options={{mode: "javascript", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {}}
/>
</div>
</Col>
</Row>
</Card>
);
}
runTask() {
alert("runTask");
}
submitTaskEdit() {
const task = Setting.deepCopy(this.state.task);
TaskBackend.updateTask(this.state.task.owner, this.state.taskName, task)
.then((res) => {
if (res.status === "ok") {
if (res.data) {
Setting.showMessage("success", "Successfully saved");
this.setState({
taskName: this.state.task.name,
});
this.props.history.push(`/tasks/${this.state.task.name}`);
} else {
Setting.showMessage("error", "failed to save: server side failure");
this.updateTaskField("name", this.state.taskName);
}
} else {
Setting.showMessage("error", `failed to save: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `failed to save: ${error}`);
});
}
render() {
return (
<div>
{
this.state.task !== null ? this.renderTask() : null
}
<div style={{marginTop: "20px", marginLeft: "40px"}}>
<Button type="primary" size="large" onClick={this.submitTaskEdit.bind(this)}>{i18next.t("general:Save")}</Button>
</div>
</div>
);
}
}
export default TaskEditPage;

197
web/src/TaskListPage.js Normal file
View File

@ -0,0 +1,197 @@
// Copyright 2023 The casbin 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 {Link} from "react-router-dom";
import {Button, Popconfirm, Table} from "antd";
import moment from "moment";
import * as Setting from "./Setting";
import * as TaskBackend from "./backend/TaskBackend";
import i18next from "i18next";
class TaskListPage extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
tasks: null,
};
}
UNSAFE_componentWillMount() {
this.getTasks();
}
getTasks() {
TaskBackend.getTasks(this.props.account.name)
.then((res) => {
if (res.status === "ok") {
this.setState({
tasks: res.data,
});
} else {
Setting.showMessage("error", `Failed to get tasks: ${res.msg}`);
}
});
}
newTask() {
const randomName = Setting.getRandomName();
return {
owner: "admin",
name: `task_${randomName}`,
createdTime: moment().format(),
displayName: `New Task - ${randomName}`,
provider: "provider_openai",
application: "Docs-Polish",
path: "F:/github_repos/casdoor-website",
};
}
addTask() {
const newTask = this.newTask();
TaskBackend.addTask(newTask)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Task added successfully");
this.setState({
tasks: Setting.prependRow(this.state.tasks, newTask),
});
} else {
Setting.showMessage("error", `Failed to add task: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Task failed to add: ${error}`);
});
}
deleteTask(i) {
TaskBackend.deleteTask(this.state.tasks[i])
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Task deleted successfully");
this.setState({
tasks: Setting.deleteRow(this.state.tasks, i),
});
} else {
Setting.showMessage("error", `Task failed to delete: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Task failed to delete: ${error}`);
});
}
renderTable(tasks) {
const columns = [
{
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "160px",
sorter: (a, b) => a.name.localeCompare(b.name),
render: (text, record, index) => {
return (
<Link to={`/tasks/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Display name"),
dataIndex: "displayName",
key: "displayName",
width: "200px",
sorter: (a, b) => a.displayName.localeCompare(b.displayName),
},
{
title: i18next.t("store:Model provider"),
dataIndex: "provider",
key: "provider",
width: "250px",
sorter: (a, b) => a.provider.localeCompare(b.provider),
render: (text, record, index) => {
return (
<Link to={`/providers/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("task:Application"),
dataIndex: "application",
key: "application",
width: "180px",
sorter: (a, b) => a.application.localeCompare(b.application),
},
{
title: i18next.t("task:Path"),
dataIndex: "path",
key: "path",
// width: "160px",
sorter: (a, b) => a.path.localeCompare(b.path),
},
{
title: i18next.t("general:Action"),
dataIndex: "action",
key: "action",
width: "180px",
render: (text, record, index) => {
return (
<div>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/tasks/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<Popconfirm
title={`Sure to delete task: ${record.name} ?`}
onConfirm={() => this.deleteTask(index)}
okText="OK"
cancelText="Cancel"
>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);
},
},
];
return (
<div>
<Table scroll={{x: "max-content"}} columns={columns} dataSource={tasks} rowKey="name" size="middle" bordered pagination={{pageSize: 100}}
title={() => (
<div>
{i18next.t("general:Tasks")}&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" size="small" onClick={this.addTask.bind(this)}>{i18next.t("general:Add")}</Button>
</div>
)}
loading={tasks === null}
/>
</div>
);
}
render() {
return (
<div>
{
this.renderTable(this.state.tasks)
}
</div>
);
}
}
export default TaskListPage;

View File

@ -49,7 +49,7 @@ class VectorListPage extends React.Component {
newVector() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `vector_${randomName}`,
createdTime: moment().format(),
displayName: `New Vector - ${randomName}`,

View File

@ -50,7 +50,7 @@ class VideoListPage extends React.Component {
newVideo() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `video_${randomName}`,
createdTime: moment().format(),
displayName: `New Video - ${randomName}`,

View File

@ -393,7 +393,6 @@ class WordsetGraph extends React.Component {
renderGraph() {
if (this.state.loading) {
return (
// https://codesandbox.io/s/antd-reproduction-template-q2dwk
<div className="App">
<Spin size="large" tip={i18next.t("general:Loading...")} style={{paddingTop: "10%"}} />
</div>

View File

@ -49,7 +49,7 @@ class WordsetListPage extends React.Component {
newWordset() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
owner: "admin",
name: `wordset_${randomName}`,
createdTime: moment().format(),
displayName: `New Wordset - ${randomName}`,

View File

@ -35,13 +35,6 @@ export function getFactorset(owner, name) {
}).then(res => res.json());
}
export function getFactorsetGraph(owner, name, clusterNumber, distanceLimit) {
return fetch(`${Setting.ServerUrl}/api/get-factorset-graph?id=${owner}/${encodeURIComponent(name)}&clusterNumber=${clusterNumber}&distanceLimit=${distanceLimit}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function updateFactorset(owner, name, factorset) {
const newFactorset = Setting.deepCopy(factorset);
return fetch(`${Setting.ServerUrl}/api/update-factorset?id=${owner}/${encodeURIComponent(name)}`, {

View File

@ -0,0 +1,62 @@
// Copyright 2023 The casbin 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 {Modal} from "antd";
import {ExclamationCircleFilled} from "@ant-design/icons";
import i18next from "i18next";
import * as Conf from "../Conf";
import * as Setting from "../Setting";
const {confirm} = Modal;
const {fetch: originalFetch} = window;
const demoModeCallback = (res) => {
res.json().then(data => {
if (Setting.isResponseDenied(data)) {
confirm({
title: i18next.t("general:This is a read-only demo site!"),
icon: <ExclamationCircleFilled />,
content: i18next.t("general:Go to writable demo site?"),
okText: i18next.t("general:OK"),
cancelText: i18next.t("general:Cancel"),
onOk() {
Setting.openLink(`https://demo-ai.casbin.com${location.pathname}${location.search}?username=built-in/admin&password=123`);
},
onCancel() {},
});
}
});
};
const requestFilters = [];
const responseFilters = [];
if (Conf.IsDemoMode) {
responseFilters.push(demoModeCallback);
}
window.fetch = async(url, option = {}) => {
requestFilters.forEach(filter => filter(url, option));
return new Promise((resolve, reject) => {
originalFetch(url, option)
.then(res => {
responseFilters.forEach(filter => filter(res.clone()));
resolve(res);
})
.catch(error => {
reject(error);
});
});
};

View File

@ -1,17 +1,17 @@
// Copyright 2023 The casbin 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.
// Copyright 2023 The casbin 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 * as Setting from "../Setting";
export function getGlobalProviders() {
@ -35,13 +35,6 @@ export function getProvider(owner, name) {
}).then(res => res.json());
}
export function getProviderGraph(owner, name, clusterNumber, distanceLimit) {
return fetch(`${Setting.ServerUrl}/api/get-provider-graph?id=${owner}/${encodeURIComponent(name)}&clusterNumber=${clusterNumber}&distanceLimit=${distanceLimit}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function updateProvider(owner, name, provider) {
const newProvider = Setting.deepCopy(provider);
return fetch(`${Setting.ServerUrl}/api/update-provider?id=${owner}/${encodeURIComponent(name)}`, {

View File

@ -0,0 +1,63 @@
// Copyright 2023 The casbin 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 * as Setting from "../Setting";
export function getGlobalTasks() {
return fetch(`${Setting.ServerUrl}/api/get-global-tasks`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function getTasks(owner) {
return fetch(`${Setting.ServerUrl}/api/get-tasks?owner=${owner}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function getTask(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-task?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function updateTask(owner, name, task) {
const newTask = Setting.deepCopy(task);
return fetch(`${Setting.ServerUrl}/api/update-task?id=${owner}/${encodeURIComponent(name)}`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newTask),
}).then(res => res.json());
}
export function addTask(task) {
const newTask = Setting.deepCopy(task);
return fetch(`${Setting.ServerUrl}/api/add-task`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newTask),
}).then(res => res.json());
}
export function deleteTask(task) {
const newTask = Setting.deepCopy(task);
return fetch(`${Setting.ServerUrl}/api/delete-task`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newTask),
}).then(res => res.json());
}

View File

@ -35,13 +35,6 @@ export function getVector(owner, name) {
}).then(res => res.json());
}
export function getVectorGraph(owner, name, clusterNumber, distanceLimit) {
return fetch(`${Setting.ServerUrl}/api/get-vector-graph?id=${owner}/${encodeURIComponent(name)}&clusterNumber=${clusterNumber}&distanceLimit=${distanceLimit}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function updateVector(owner, name, vector) {
const newVector = Setting.deepCopy(vector);
return fetch(`${Setting.ServerUrl}/api/update-vector?id=${owner}/${encodeURIComponent(name)}`, {

View File

@ -1,17 +1,17 @@
// Copyright 2023 The casbin 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.
// Copyright 2023 The casbin 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 * as Setting from "../Setting";
export function getGlobalVideos() {
@ -35,13 +35,6 @@ export function getVideo(owner, name) {
}).then(res => res.json());
}
export function getVideoGraph(owner, name, clusterNumber, distanceLimit) {
return fetch(`${Setting.ServerUrl}/api/get-video-graph?id=${owner}/${encodeURIComponent(name)}&clusterNumber=${clusterNumber}&distanceLimit=${distanceLimit}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function updateVideo(owner, name, video) {
const newVideo = Setting.deepCopy(video);
return fetch(`${Setting.ServerUrl}/api/update-video?id=${owner}/${encodeURIComponent(name)}`, {

View File

@ -15,12 +15,26 @@
import i18n from "i18next";
import zh from "./locales/zh/data.json";
import en from "./locales/en/data.json";
import es from "./locales/es/data.json";
import fr from "./locales/fr/data.json";
import de from "./locales/de/data.json";
import id from "./locales/id/data.json";
import ja from "./locales/ja/data.json";
import ko from "./locales/ko/data.json";
import ru from "./locales/ru/data.json";
import * as Conf from "./Conf";
import * as Setting from "./Setting";
import {initReactI18next} from "react-i18next";
const resources = {
en: en,
zh: zh,
es: es,
fr: fr,
de: de,
id: id,
ja: ja,
ko: ko,
ru: ru,
};
function initLanguage() {
@ -31,29 +45,49 @@ function initLanguage() {
} else {
const userLanguage = navigator.language;
switch (userLanguage) {
case "zh-CN":
language = "zh";
break;
case "zh":
language = "zh";
break;
case "en":
language = "en";
break;
case "en-US":
language = "en";
break;
case "zh-CN":
language = "zh";
break;
case "zh":
language = "zh";
break;
case "es":
language = "es";
break;
case "fr":
language = "fr";
break;
case "de":
language = "de";
break;
case "id":
language = "id";
break;
case "ja":
language = "ja";
break;
case "ko":
language = "ko";
break;
case "ru":
language = "ru";
break;
default:
language = Conf.DefaultLanguage;
}
}
}
Setting.changeMomentLanguage(language);
return language;
}
i18n.init({
i18n.use(initReactI18next).init({
lng: initLanguage(),
resources: resources,

View File

@ -17,7 +17,7 @@ code {
background-size: 108px, 33px;
width: 108px;
height: 27px;
/*background: rgba(0, 0, 0, 0.2);*/
/* background: rgba(0, 0, 0, 0.2); */
margin: 17px 10px 16px 20px;
float: left;
}
@ -38,12 +38,13 @@ code {
background: rgba(92,48,125,0.55);
}
/*http://react-china.org/t/topic/33846/3*/
/* http://react-china.org/t/topic/33846/3 */
.ant-table-header {
scrollbar-color:transparent transparent
scrollbar-color: transparent transparent;
}
.ant-table-header::-webkit-scrollbar {
background-color:transparent
background-color: transparent;
}
.import-output {
@ -74,10 +75,11 @@ code {
box-shadow: 0 0 4px #888;
}
/*https://stackoverflow.com/questions/64961752/how-do-i-change-the-color-of-selected-menu-item-in-ant-design*/
/*.conferenceMenu > .ant-menu-item-selected {*/
/* background-color: rgb(230,247,255) !important;*/
/*}*/
/* https://stackoverflow.com/questions/64961752/how-do-i-change-the-color-of-selected-menu-item-in-ant-design */
/* .conferenceMenu > .ant-menu-item-selected {
background-color: rgb(230,247,255) !important;
} */
.conferenceMenu {
background-color: rgb(242,242,242) !important;
@ -92,3 +94,15 @@ code {
.anticon-file {
visibility: hidden;
}
.markdownContainer {
width: 100%;
overflow: hidden;
background-color: rgb(251,240,217);
padding: 10px;
}
.markdownContainer img {
max-width: 100%;
height: auto;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
// create-react-app + IE9
// https://www.cnblogs.com/xuexia/p/12092768.html
// https://www.cnblogs.com/yeduweichengzhaoyu/p/12092768.html
// react-app-polyfill
// https://www.npmjs.com/package/react-app-polyfill
import "react-app-polyfill/ie9";
@ -28,6 +28,7 @@ import * as serviceWorker from "./serviceWorker";
// import 'antd/dist/antd.min.css';
import {BrowserRouter} from "react-router-dom";
import "./i18n";
import "./backend/FetchFilter";
const container = document.getElementById("root");

View File

@ -2216,6 +2216,13 @@
dependencies:
"@types/node" "*"
"@types/debug@^4.0.0":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317"
integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==
dependencies:
"@types/ms" "*"
"@types/eslint-scope@^3.7.3":
version "3.7.4"
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16"
@ -2269,6 +2276,13 @@
dependencies:
"@types/node" "*"
"@types/hast@^2.0.0":
version "2.3.5"
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.5.tgz#08caac88b44d0fdd04dc17a19142355f43bd8a7a"
integrity sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg==
dependencies:
"@types/unist" "^2"
"@types/html-minifier-terser@^6.0.0":
version "6.1.0"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35"
@ -2315,6 +2329,13 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/mdast@^3.0.0":
version "3.0.12"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.12.tgz#beeb511b977c875a5b0cc92eab6fcac2f0895514"
integrity sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==
dependencies:
"@types/unist" "^2"
"@types/mime@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
@ -2330,6 +2351,11 @@
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
"@types/ms@*":
version "0.7.31"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/mustache@^4.2.2":
version "4.2.2"
resolved "https://registry.yarnpkg.com/@types/mustache/-/mustache-4.2.2.tgz#825bf5c214c3ab84d0b23fef2c8eb898f3ff8717"
@ -2362,7 +2388,7 @@
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f"
integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==
"@types/prop-types@*":
"@types/prop-types@*", "@types/prop-types@^15.0.0":
version "15.7.5"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
@ -2454,6 +2480,11 @@
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311"
integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==
"@types/unist@^2", "@types/unist@^2.0.0":
version "2.0.8"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.8.tgz#bb197b9639aa1a04cf464a617fe800cccd92ad5c"
integrity sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==
"@types/ws@^8.5.5":
version "8.5.5"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb"
@ -3301,6 +3332,11 @@ babel-preset-react-app@^10.0.1:
babel-plugin-macros "^3.1.0"
babel-plugin-transform-react-remove-prop-types "^0.4.24"
bail@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d"
integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@ -3530,6 +3566,11 @@ case-sensitive-paths-webpack-plugin@^2.4.0:
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==
ccount@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5"
integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==
cfb@^1.1.4:
version "1.2.2"
resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
@ -3578,6 +3619,11 @@ char-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-2.0.1.tgz#6dafdb25f9d3349914079f010ba8d0e6ff9cd01e"
integrity sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==
character-entities@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22"
integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==
check-types@^11.1.1:
version "11.2.2"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.2.tgz#7afc0b6a860d686885062f2dba888ba5710335b4"
@ -3749,6 +3795,11 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
comma-separated-tokens@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee"
integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==
comma-separated-values@^3.6.4:
version "3.6.4"
resolved "https://registry.yarnpkg.com/comma-separated-values/-/comma-separated-values-3.6.4.tgz#c309ec7024f74b7ae19223372054242617e35bd2"
@ -4378,7 +4429,7 @@ debug@2.6.9, debug@^2.6.0:
dependencies:
ms "2.0.0"
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -4410,6 +4461,13 @@ decimal.js@^10.2.1:
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
decode-named-character-reference@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e"
integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==
dependencies:
character-entities "^2.0.0"
dedent@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
@ -4460,7 +4518,7 @@ depd@~1.1.2:
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
dequal@^2.0.3:
dequal@^2.0.0, dequal@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
@ -4503,6 +4561,11 @@ diff@^4.0.1:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
diff@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@ -4848,6 +4911,11 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
escape-string-regexp@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
escodegen@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17"
@ -5282,6 +5350,11 @@ express@^4.17.3:
utils-merge "1.0.1"
vary "~1.1.2"
extend@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
fast-deep-equal@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
@ -5325,6 +5398,13 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
fault@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fault/-/fault-2.0.1.tgz#d47ca9f37ca26e4bd38374a7c500b5a384755b6c"
integrity sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==
dependencies:
format "^0.2.0"
faye-websocket@^0.11.3:
version "0.11.4"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da"
@ -5513,6 +5593,11 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
format@^0.2.0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@ -5825,6 +5910,11 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hast-util-whitespace@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557"
integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==
he@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@ -6145,6 +6235,11 @@ ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inline-style-parser@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
internal-slot@^1.0.3, internal-slot@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986"
@ -6205,6 +6300,11 @@ is-boolean-object@^1.1.0:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
is-buffer@^2.0.0:
version "2.0.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
@ -6298,6 +6398,11 @@ is-plain-obj@^3.0.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7"
integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==
is-plain-obj@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
@ -7116,6 +7221,11 @@ kleur@^3.0.3:
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
kleur@^4.0.3:
version "4.1.5"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
klona@^2.0.4, klona@^2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22"
@ -7340,6 +7450,11 @@ log-update@^4.0.0:
slice-ansi "^4.0.0"
wrap-ansi "^6.2.0"
longest-streak@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@ -7456,11 +7571,163 @@ markdown-it@^13.0.1:
mdurl "^1.0.1"
uc.micro "^1.0.5"
markdown-table@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd"
integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==
mathml-tag-names@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
mdast-util-definitions@^5.0.0:
version "5.1.2"
resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7"
integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==
dependencies:
"@types/mdast" "^3.0.0"
"@types/unist" "^2.0.0"
unist-util-visit "^4.0.0"
mdast-util-find-and-replace@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz#cc2b774f7f3630da4bd592f61966fecade8b99b1"
integrity sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==
dependencies:
"@types/mdast" "^3.0.0"
escape-string-regexp "^5.0.0"
unist-util-is "^5.0.0"
unist-util-visit-parents "^5.0.0"
mdast-util-from-markdown@^1.0.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0"
integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==
dependencies:
"@types/mdast" "^3.0.0"
"@types/unist" "^2.0.0"
decode-named-character-reference "^1.0.0"
mdast-util-to-string "^3.1.0"
micromark "^3.0.0"
micromark-util-decode-numeric-character-reference "^1.0.0"
micromark-util-decode-string "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
unist-util-stringify-position "^3.0.0"
uvu "^0.5.0"
mdast-util-frontmatter@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-frontmatter/-/mdast-util-frontmatter-1.0.1.tgz#79c46d7414eb9d3acabe801ee4a70a70b75e5af1"
integrity sha512-JjA2OjxRqAa8wEG8hloD0uTU0kdn8kbtOWpPP94NBkfAlbxn4S8gCGf/9DwFtEeGPXrDcNXdiDjVaRdUFqYokw==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.3.0"
micromark-extension-frontmatter "^1.0.0"
mdast-util-gfm-autolink-literal@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz#67a13abe813d7eba350453a5333ae1bc0ec05c06"
integrity sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==
dependencies:
"@types/mdast" "^3.0.0"
ccount "^2.0.0"
mdast-util-find-and-replace "^2.0.0"
micromark-util-character "^1.0.0"
mdast-util-gfm-footnote@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz#ce5e49b639c44de68d5bf5399877a14d5020424e"
integrity sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.3.0"
micromark-util-normalize-identifier "^1.0.0"
mdast-util-gfm-strikethrough@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz#5470eb105b483f7746b8805b9b989342085795b7"
integrity sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.3.0"
mdast-util-gfm-table@^1.0.0:
version "1.0.7"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz#3552153a146379f0f9c4c1101b071d70bbed1a46"
integrity sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==
dependencies:
"@types/mdast" "^3.0.0"
markdown-table "^3.0.0"
mdast-util-from-markdown "^1.0.0"
mdast-util-to-markdown "^1.3.0"
mdast-util-gfm-task-list-item@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz#b280fcf3b7be6fd0cc012bbe67a59831eb34097b"
integrity sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.3.0"
mdast-util-gfm@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz#e92f4d8717d74bdba6de57ed21cc8b9552e2d0b6"
integrity sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==
dependencies:
mdast-util-from-markdown "^1.0.0"
mdast-util-gfm-autolink-literal "^1.0.0"
mdast-util-gfm-footnote "^1.0.0"
mdast-util-gfm-strikethrough "^1.0.0"
mdast-util-gfm-table "^1.0.0"
mdast-util-gfm-task-list-item "^1.0.0"
mdast-util-to-markdown "^1.0.0"
mdast-util-phrasing@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz#c7c21d0d435d7fb90956038f02e8702781f95463"
integrity sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==
dependencies:
"@types/mdast" "^3.0.0"
unist-util-is "^5.0.0"
mdast-util-to-hast@^12.1.0:
version "12.3.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49"
integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==
dependencies:
"@types/hast" "^2.0.0"
"@types/mdast" "^3.0.0"
mdast-util-definitions "^5.0.0"
micromark-util-sanitize-uri "^1.1.0"
trim-lines "^3.0.0"
unist-util-generated "^2.0.0"
unist-util-position "^4.0.0"
unist-util-visit "^4.0.0"
mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz#c13343cb3fc98621911d33b5cd42e7d0731171c6"
integrity sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==
dependencies:
"@types/mdast" "^3.0.0"
"@types/unist" "^2.0.0"
longest-streak "^3.0.0"
mdast-util-phrasing "^3.0.0"
mdast-util-to-string "^3.0.0"
micromark-util-decode-string "^1.0.0"
unist-util-visit "^4.0.0"
zwitch "^2.0.0"
mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz#66f7bb6324756741c5f47a53557f0cbf16b6f789"
integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==
dependencies:
"@types/mdast" "^3.0.0"
mdn-data@2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
@ -7538,6 +7805,289 @@ methods@~1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz#1386628df59946b2d39fb2edfd10f3e8e0a75bb8"
integrity sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==
dependencies:
decode-named-character-reference "^1.0.0"
micromark-factory-destination "^1.0.0"
micromark-factory-label "^1.0.0"
micromark-factory-space "^1.0.0"
micromark-factory-title "^1.0.0"
micromark-factory-whitespace "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-chunked "^1.0.0"
micromark-util-classify-character "^1.0.0"
micromark-util-html-tag-name "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-resolve-all "^1.0.0"
micromark-util-subtokenize "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.1"
uvu "^0.5.0"
micromark-extension-frontmatter@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/micromark-extension-frontmatter/-/micromark-extension-frontmatter-1.1.1.tgz#2946643938e491374145d0c9aacc3249e38a865f"
integrity sha512-m2UH9a7n3W8VAH9JO9y01APpPKmNNNs71P0RbknEmYSaZU5Ghogv38BYO94AI5Xw6OYfxZRdHZZ2nYjs/Z+SZQ==
dependencies:
fault "^2.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-extension-gfm-autolink-literal@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz#5853f0e579bbd8ef9e39a7c0f0f27c5a063a66e7"
integrity sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-sanitize-uri "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-extension-gfm-footnote@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz#05e13034d68f95ca53c99679040bc88a6f92fe2e"
integrity sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==
dependencies:
micromark-core-commonmark "^1.0.0"
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-sanitize-uri "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm-strikethrough@^1.0.0:
version "1.0.7"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz#c8212c9a616fa3bf47cb5c711da77f4fdc2f80af"
integrity sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==
dependencies:
micromark-util-chunked "^1.0.0"
micromark-util-classify-character "^1.0.0"
micromark-util-resolve-all "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm-table@^1.0.0:
version "1.0.7"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz#dcb46074b0c6254c3fc9cc1f6f5002c162968008"
integrity sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm-tagfilter@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz#aa7c4dd92dabbcb80f313ebaaa8eb3dac05f13a7"
integrity sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==
dependencies:
micromark-util-types "^1.0.0"
micromark-extension-gfm-task-list-item@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz#b52ce498dc4c69b6a9975abafc18f275b9dde9f4"
integrity sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz#e517e8579949a5024a493e49204e884aa74f5acf"
integrity sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==
dependencies:
micromark-extension-gfm-autolink-literal "^1.0.0"
micromark-extension-gfm-footnote "^1.0.0"
micromark-extension-gfm-strikethrough "^1.0.0"
micromark-extension-gfm-table "^1.0.0"
micromark-extension-gfm-tagfilter "^1.0.0"
micromark-extension-gfm-task-list-item "^1.0.0"
micromark-util-combine-extensions "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-destination@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz#eb815957d83e6d44479b3df640f010edad667b9f"
integrity sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-label@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz#cc95d5478269085cfa2a7282b3de26eb2e2dec68"
integrity sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-factory-space@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz#c8f40b0640a0150751d3345ed885a080b0d15faf"
integrity sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-title@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz#dd0fe951d7a0ac71bdc5ee13e5d1465ad7f50ea1"
integrity sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-whitespace@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz#798fb7489f4c8abafa7ca77eed6b5745853c9705"
integrity sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-character@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.2.0.tgz#4fedaa3646db249bc58caeb000eb3549a8ca5dcc"
integrity sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-chunked@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz#37a24d33333c8c69a74ba12a14651fd9ea8a368b"
integrity sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-classify-character@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz#6a7f8c8838e8a120c8e3c4f2ae97a2bff9190e9d"
integrity sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-combine-extensions@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz#192e2b3d6567660a85f735e54d8ea6e3952dbe84"
integrity sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==
dependencies:
micromark-util-chunked "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-decode-numeric-character-reference@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz#b1e6e17009b1f20bc652a521309c5f22c85eb1c6"
integrity sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-decode-string@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz#dc12b078cba7a3ff690d0203f95b5d5537f2809c"
integrity sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==
dependencies:
decode-named-character-reference "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-decode-numeric-character-reference "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz#92e4f565fd4ccb19e0dcae1afab9a173bbeb19a5"
integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==
micromark-util-html-tag-name@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz#48fd7a25826f29d2f71479d3b4e83e94829b3588"
integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==
micromark-util-normalize-identifier@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz#7a73f824eb9f10d442b4d7f120fecb9b38ebf8b7"
integrity sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-resolve-all@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz#4652a591ee8c8fa06714c9b54cd6c8e693671188"
integrity sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==
dependencies:
micromark-util-types "^1.0.0"
micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz#613f738e4400c6eedbc53590c67b197e30d7f90d"
integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-encode "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-subtokenize@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz#941c74f93a93eaf687b9054aeb94642b0e92edb1"
integrity sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==
dependencies:
micromark-util-chunked "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-util-symbol@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz#813cd17837bdb912d069a12ebe3a44b6f7063142"
integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==
micromark-util-types@^1.0.0, micromark-util-types@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.1.0.tgz#e6676a8cae0bb86a2171c498167971886cb7e283"
integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==
micromark@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.2.0.tgz#1af9fef3f995ea1ea4ac9c7e2f19c48fd5c006e9"
integrity sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==
dependencies:
"@types/debug" "^4.0.0"
debug "^4.0.0"
decode-named-character-reference "^1.0.0"
micromark-core-commonmark "^1.0.1"
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-chunked "^1.0.0"
micromark-util-combine-extensions "^1.0.0"
micromark-util-decode-numeric-character-reference "^1.0.0"
micromark-util-encode "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-resolve-all "^1.0.0"
micromark-util-sanitize-uri "^1.0.0"
micromark-util-subtokenize "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.1"
uvu "^0.5.0"
micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
@ -7630,6 +8180,11 @@ moment@^2.29.1:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
mri@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@ -8850,7 +9405,7 @@ prompts@^2.0.1, prompts@^2.4.2:
kleur "^3.0.3"
sisteransi "^1.0.5"
prop-types@15, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
prop-types@15, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -8859,6 +9414,11 @@ prop-types@15, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop
object-assign "^4.1.1"
react-is "^16.13.1"
property-information@^6.0.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.3.0.tgz#ba4a06ec6b4e1e90577df9931286953cdf4282c3"
integrity sha512-gVNZ74nqhRMiIUYWGQdosYetaKc83x8oT41a0LlV3AAFCAZwCpg4vmGkq8t34+cUhp3cnM4XDiU/7xlgK7HGrg==
proxy-addr@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
@ -9472,6 +10032,27 @@ react-kapsule@2:
fromentries "^1.3.2"
jerrypick "^1.1.1"
react-markdown@^8.0.7:
version "8.0.7"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.7.tgz#c8dbd1b9ba5f1c5e7e5f2a44de465a3caafdf89b"
integrity sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==
dependencies:
"@types/hast" "^2.0.0"
"@types/prop-types" "^15.0.0"
"@types/unist" "^2.0.0"
comma-separated-tokens "^2.0.0"
hast-util-whitespace "^2.0.0"
prop-types "^15.0.0"
property-information "^6.0.0"
react-is "^18.0.0"
remark-parse "^10.0.0"
remark-rehype "^10.0.0"
space-separated-tokens "^2.0.0"
style-to-object "^0.4.0"
unified "^10.0.0"
unist-util-visit "^4.0.0"
vfile "^5.0.0"
react-pdf@5.7.2:
version "5.7.2"
resolved "https://registry.yarnpkg.com/react-pdf/-/react-pdf-5.7.2.tgz#c458dedf7983822668b40dcac1eae052c1f6e056"
@ -9727,6 +10308,45 @@ relateurl@^0.2.7:
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
remark-frontmatter@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/remark-frontmatter/-/remark-frontmatter-4.0.1.tgz#84560f7ccef114ef076d3d3735be6d69f8922309"
integrity sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-frontmatter "^1.0.0"
micromark-extension-frontmatter "^1.0.0"
unified "^10.0.0"
remark-gfm@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f"
integrity sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-gfm "^2.0.0"
micromark-extension-gfm "^2.0.0"
unified "^10.0.0"
remark-parse@^10.0.0:
version "10.0.2"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.2.tgz#ca241fde8751c2158933f031a4e3efbaeb8bc262"
integrity sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-from-markdown "^1.0.0"
unified "^10.0.0"
remark-rehype@^10.0.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279"
integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==
dependencies:
"@types/hast" "^2.0.0"
"@types/mdast" "^3.0.0"
mdast-util-to-hast "^12.1.0"
unified "^10.0.0"
renderkid@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a"
@ -9875,6 +10495,13 @@ rxjs@^7.8.0:
dependencies:
tslib "^2.1.0"
sade@^1.7.3:
version "1.8.1"
resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701"
integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==
dependencies:
mri "^1.1.0"
safe-array-concat@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060"
@ -10242,6 +10869,11 @@ sourcemap-codec@^1.4.8:
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
space-separated-tokens@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f"
integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==
spdx-correct@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"
@ -10511,6 +11143,13 @@ style-search@^0.1.0:
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==
style-to-object@^0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.2.tgz#a8247057111dea8bd3b8a1a66d2d0c9cf9218a54"
integrity sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA==
dependencies:
inline-style-parser "0.1.1"
styled-components@^5.3.6:
version "5.3.11"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.11.tgz#9fda7bf1108e39bf3f3e612fcc18170dedcd57a8"
@ -10956,11 +11595,21 @@ tr46@^2.1.0:
dependencies:
punycode "^2.1.1"
trim-lines@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338"
integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==
trim-newlines@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
trough@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876"
integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==
tryer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
@ -11141,6 +11790,19 @@ unicode-property-aliases-ecmascript@^2.0.0:
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd"
integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==
unified@^10.0.0:
version "10.1.2"
resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df"
integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==
dependencies:
"@types/unist" "^2.0.0"
bail "^2.0.0"
extend "^3.0.0"
is-buffer "^2.0.0"
is-plain-obj "^4.0.0"
trough "^2.0.0"
vfile "^5.0.0"
unique-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
@ -11148,6 +11810,49 @@ unique-string@^2.0.0:
dependencies:
crypto-random-string "^2.0.0"
unist-util-generated@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae"
integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==
unist-util-is@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.2.1.tgz#b74960e145c18dcb6226bc57933597f5486deae9"
integrity sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==
dependencies:
"@types/unist" "^2.0.0"
unist-util-position@^4.0.0:
version "4.0.4"
resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.4.tgz#93f6d8c7d6b373d9b825844645877c127455f037"
integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==
dependencies:
"@types/unist" "^2.0.0"
unist-util-stringify-position@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz#03ad3348210c2d930772d64b489580c13a7db39d"
integrity sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==
dependencies:
"@types/unist" "^2.0.0"
unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1:
version "5.1.3"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb"
integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==
dependencies:
"@types/unist" "^2.0.0"
unist-util-is "^5.0.0"
unist-util-visit@^4.0.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.2.tgz#125a42d1eb876283715a3cb5cceaa531828c72e2"
integrity sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==
dependencies:
"@types/unist" "^2.0.0"
unist-util-is "^5.0.0"
unist-util-visit-parents "^5.1.1"
universalify@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
@ -11226,6 +11931,16 @@ uuid@^8.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
uvu@^0.5.0:
version "0.5.6"
resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"
integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==
dependencies:
dequal "^2.0.0"
diff "^5.0.0"
kleur "^4.0.3"
sade "^1.7.3"
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
@ -11263,6 +11978,24 @@ vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
vfile-message@^3.0.0:
version "3.1.4"
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.4.tgz#15a50816ae7d7c2d1fa87090a7f9f96612b59dea"
integrity sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==
dependencies:
"@types/unist" "^2.0.0"
unist-util-stringify-position "^3.0.0"
vfile@^5.0.0:
version "5.3.7"
resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.7.tgz#de0677e6683e3380fafc46544cfe603118826ab7"
integrity sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==
dependencies:
"@types/unist" "^2.0.0"
is-buffer "^2.0.0"
unist-util-stringify-position "^3.0.0"
vfile-message "^3.0.0"
voc@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/voc/-/voc-1.0.0.tgz#5465c0ce11d0881f7d8e36d8ca587043f33a25ae"
@ -11871,3 +12604,8 @@ zrender@5.4.3:
integrity sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==
dependencies:
tslib "2.3.0"
zwitch@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"
integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==