Browse Source

Rename vector to factor

HEAD
Yang Luo 2 years ago
parent
commit
fb87ef67a3
31 changed files with 460 additions and 480 deletions
  1. +1
    -1
      README.md
  2. +21
    -21
      controllers/factorset.go
  3. +1
    -1
      object/adapter.go
  4. +3
    -3
      object/factor.go
  5. +31
    -31
      object/factorset.go
  6. +8
    -8
      object/factorset_tsne.go
  7. +11
    -11
      object/factorset_tsne_test.go
  8. +22
    -22
      object/factorset_upload.go
  9. +5
    -5
      object/factorset_upload_test.go
  10. +13
    -13
      object/kmeans.go
  11. +2
    -2
      object/kmeans_test.go
  12. +2
    -2
      object/wordset.go
  13. +24
    -24
      object/wordset_graph.go
  14. +7
    -7
      object/wordset_match.go
  15. +8
    -8
      object/wordset_upload.go
  16. +2
    -2
      object/wordset_upload_test.go
  17. +6
    -6
      routers/router.go
  18. +3
    -3
      util/file.go
  19. +9
    -9
      web/src/App.js
  20. +3
    -3
      web/src/FactorTable.js
  21. +67
    -67
      web/src/FactorsetEditPage.js
  22. +60
    -60
      web/src/FactorsetListPage.js
  23. +3
    -3
      web/src/FileTable.js
  24. +2
    -2
      web/src/FileTree.js
  25. +30
    -30
      web/src/Setting.js
  26. +15
    -15
      web/src/VideoListPage.js
  27. +30
    -30
      web/src/WordsetEditPage.js
  28. +27
    -47
      web/src/WordsetListPage.js
  29. +34
    -34
      web/src/backend/FactorsetBackend.js
  30. +5
    -5
      web/src/locales/en/data.json
  31. +5
    -5
      web/src/locales/zh/data.json

+ 1
- 1
README.md View File

@@ -159,4 +159,4 @@ http://localhost:13001

![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 **vectorsets** to achieve a **customized domain knowledge base**.
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**.

controllers/vectorset.go → controllers/factorset.go View File

@@ -20,51 +20,51 @@ import (
"github.com/casbin/casibase/object"
)

func (c *ApiController) GetGlobalVectorsets() {
vectorsets, err := object.GetGlobalVectorsets()
func (c *ApiController) GetGlobalFactorsets() {
factorsets, err := object.GetGlobalFactorsets()
if err != nil {
c.ResponseError(err.Error())
return
}

c.ResponseOk(vectorsets)
c.ResponseOk(factorsets)
}

func (c *ApiController) GetVectorsets() {
func (c *ApiController) GetFactorsets() {
owner := c.Input().Get("owner")

vectorsets, err := object.GetVectorsets(owner)
factorsets, err := object.GetFactorsets(owner)
if err != nil {
c.ResponseError(err.Error())
return
}

c.ResponseOk(vectorsets)
c.ResponseOk(factorsets)
}

func (c *ApiController) GetVectorset() {
func (c *ApiController) GetFactorset() {
id := c.Input().Get("id")

vectorset, err := object.GetVectorset(id)
factorset, err := object.GetFactorset(id)
if err != nil {
c.ResponseError(err.Error())
return
}

c.ResponseOk(vectorset)
c.ResponseOk(factorset)
}

func (c *ApiController) UpdateVectorset() {
func (c *ApiController) UpdateFactorset() {
id := c.Input().Get("id")

var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
var factorset object.Factorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
}

success, err := object.UpdateVectorset(id, &vectorset)
success, err := object.UpdateFactorset(id, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
@@ -73,15 +73,15 @@ func (c *ApiController) UpdateVectorset() {
c.ResponseOk(success)
}

func (c *ApiController) AddVectorset() {
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
func (c *ApiController) AddFactorset() {
var factorset object.Factorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
}

success, err := object.AddVectorset(&vectorset)
success, err := object.AddFactorset(&factorset)
if err != nil {
c.ResponseError(err.Error())
return
@@ -90,15 +90,15 @@ func (c *ApiController) AddVectorset() {
c.ResponseOk(success)
}

func (c *ApiController) DeleteVectorset() {
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
func (c *ApiController) DeleteFactorset() {
var factorset object.Factorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
}

success, err := object.DeleteVectorset(&vectorset)
success, err := object.DeleteFactorset(&factorset)
if err != nil {
c.ResponseError(err.Error())
return

+ 1
- 1
object/adapter.go View File

@@ -108,7 +108,7 @@ func (a *Adapter) createTable() {
panic(err)
}

err = a.engine.Sync2(new(Vectorset))
err = a.engine.Sync2(new(Factorset))
if err != nil {
panic(err)
}


object/vector.go → object/factor.go View File

@@ -19,16 +19,16 @@ import (
"strings"
)

type Vector struct {
type Factor struct {
Name string `xorm:"varchar(100)" json:"name"`
Category string `xorm:"varchar(100)" json:"category"`
Color string `xorm:"varchar(100)" json:"color"`
Data []float64 `xorm:"varchar(1000)" json:"data"`
}

func (vector *Vector) GetDataKey() string {
func (factor *Factor) GetDataKey() string {
sData := []string{}
for _, f := range vector.Data {
for _, f := range factor.Data {
sData = append(sData, fmt.Sprintf("%f", f))
}
return strings.Join(sData, "|")

object/vectorset.go → object/factorset.go View File

@@ -21,7 +21,7 @@ import (
"xorm.io/core"
)

type Vectorset struct {
type Factorset 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"`
@@ -33,61 +33,61 @@ type Vectorset struct {
Dimension int `json:"dimension"`
Count int `json:"count"`

Vectors []*Vector `xorm:"mediumtext" json:"vectors"`
AllVectors []*Vector `xorm:"-" json:"allVectors"`
VectorMap map[string]*Vector `xorm:"-" json:"vectorMap"`
Factors []*Factor `xorm:"mediumtext" json:"factors"`
AllFactors []*Factor `xorm:"-" json:"allFactors"`
FactorMap map[string]*Factor `xorm:"-" json:"factorMap"`
}

func GetGlobalVectorsets() ([]*Vectorset, error) {
vectorsets := []*Vectorset{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&vectorsets)
func GetGlobalFactorsets() ([]*Factorset, error) {
factorsets := []*Factorset{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&factorsets)
if err != nil {
return vectorsets, err
return factorsets, err
}

return vectorsets, nil
return factorsets, nil
}

func GetVectorsets(owner string) ([]*Vectorset, error) {
vectorsets := []*Vectorset{}
err := adapter.engine.Desc("created_time").Find(&vectorsets, &Vectorset{Owner: owner})
func GetFactorsets(owner string) ([]*Factorset, error) {
factorsets := []*Factorset{}
err := adapter.engine.Desc("created_time").Find(&factorsets, &Factorset{Owner: owner})
if err != nil {
return vectorsets, err
return factorsets, err
}

return vectorsets, nil
return factorsets, nil
}

func getVectorset(owner string, name string) (*Vectorset, error) {
vectorset := Vectorset{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&vectorset)
func getFactorset(owner string, name string) (*Factorset, error) {
factorset := Factorset{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&factorset)
if err != nil {
return &vectorset, err
return &factorset, err
}

if existed {
return &vectorset, nil
return &factorset, nil
} else {
return nil, nil
}
}

func GetVectorset(id string) (*Vectorset, error) {
func GetFactorset(id string) (*Factorset, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getVectorset(owner, name)
return getFactorset(owner, name)
}

func UpdateVectorset(id string, vectorset *Vectorset) (bool, error) {
func UpdateFactorset(id string, factorset *Factorset) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getVectorset(owner, name)
_, err := getFactorset(owner, name)
if err != nil {
return false, err
}
if vectorset == nil {
if factorset == nil {
return false, nil
}

_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(vectorset)
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(factorset)
if err != nil {
return false, err
}
@@ -96,8 +96,8 @@ func UpdateVectorset(id string, vectorset *Vectorset) (bool, error) {
return true, nil
}

func AddVectorset(vectorset *Vectorset) (bool, error) {
affected, err := adapter.engine.Insert(vectorset)
func AddFactorset(factorset *Factorset) (bool, error) {
affected, err := adapter.engine.Insert(factorset)
if err != nil {
return false, err
}
@@ -105,8 +105,8 @@ func AddVectorset(vectorset *Vectorset) (bool, error) {
return affected != 0, nil
}

func DeleteVectorset(vectorset *Vectorset) (bool, error) {
affected, err := adapter.engine.ID(core.PK{vectorset.Owner, vectorset.Name}).Delete(&Vectorset{})
func DeleteFactorset(factorset *Factorset) (bool, error) {
affected, err := adapter.engine.ID(core.PK{factorset.Owner, factorset.Name}).Delete(&Factorset{})
if err != nil {
return false, err
}
@@ -114,6 +114,6 @@ func DeleteVectorset(vectorset *Vectorset) (bool, error) {
return affected != 0, nil
}

func (vectorset *Vectorset) GetId() string {
return fmt.Sprintf("%s/%s", vectorset.Owner, vectorset.Name)
func (factorset *Factorset) GetId() string {
return fmt.Sprintf("%s/%s", factorset.Owner, factorset.Name)
}

object/vectorset_tsne.go → object/factorset_tsne.go View File

@@ -40,13 +40,13 @@ func testTsne() {
println(Y)
}

func (vectorset *Vectorset) DoTsne(dimension int) {
func (factorset *Factorset) DoTsne(dimension int) {
floatArray := []float64{}
for _, vector := range vectorset.AllVectors {
floatArray = append(floatArray, vector.Data...)
for _, factor := range factorset.AllFactors {
floatArray = append(floatArray, factor.Data...)
}

X := mat.NewDense(len(vectorset.AllVectors), vectorset.Dimension, floatArray)
X := mat.NewDense(len(factorset.AllFactors), factorset.Dimension, floatArray)

t := tsne.NewTSNE(dimension, 300, 100, 300, true)

@@ -56,18 +56,18 @@ func (vectorset *Vectorset) DoTsne(dimension int) {
})

rowCount, columnCount := Y.Dims()
if rowCount != len(vectorset.AllVectors) {
panic("rowCount != len(vectorset.AllVectors)")
if rowCount != len(factorset.AllFactors) {
panic("rowCount != len(factorset.AllFactors)")
}
if columnCount != dimension {
panic("columnCount != dimension")
}

for i, vector := range vectorset.AllVectors {
for i, factor := range factorset.AllFactors {
arr := []float64{}
for j := 0; j < dimension; j++ {
arr = append(arr, Y.At(i, j))
}
vector.Data = arr
factor.Data = arr
}
}

object/vectorset_tsne_test.go → object/factorset_tsne_test.go View File

@@ -19,20 +19,20 @@ import (
"testing"
)

func TestDoVectorsetTsne(t *testing.T) {
func TestDoFactorsetTsne(t *testing.T) {
InitConfig()

dimension := 50

//vectorset := getVectorset("admin", "wikipedia")
vectorset, _ := getVectorset("admin", "wordVector_utf-8")
vectorset.LoadVectors("../../tmpFiles/")
vectorset.DoTsne(dimension)
//factorset := getFactorset("admin", "wikipedia")
factorset, _ := getFactorset("admin", "wordFactor_utf-8")
factorset.LoadFactors("../../tmpFiles/")
factorset.DoTsne(dimension)

vectorset.Name = fmt.Sprintf("%s_Dim_%d", vectorset.Name, dimension)
vectorset.FileName = fmt.Sprintf("%s_Dim_%d.csv", vectorset.FileName, dimension)
vectorset.FileSize = ""
vectorset.Dimension = dimension
vectorset.WriteVectors("../../tmpFiles/")
AddVectorset(vectorset)
factorset.Name = fmt.Sprintf("%s_Dim_%d", factorset.Name, dimension)
factorset.FileName = fmt.Sprintf("%s_Dim_%d.csv", factorset.FileName, dimension)
factorset.FileSize = ""
factorset.Dimension = dimension
factorset.WriteFactors("../../tmpFiles/")
AddFactorset(factorset)
}

object/vectorset_upload.go → object/factorset_upload.go View File

@@ -21,49 +21,49 @@ import (
"github.com/casbin/casibase/util"
)

func (vectorset *Vectorset) LoadVectors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, vectorset.FileName))
func (factorset *Factorset) LoadFactors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, factorset.FileName))

var nameArray []string
var dataArray [][]float64
if strings.HasSuffix(vectorset.FileName, ".csv") {
if strings.Contains(vectorset.FileName, "_Dim_") {
nameArray, dataArray = util.LoadVectorFileByCsv2(path)
if strings.HasSuffix(factorset.FileName, ".csv") {
if strings.Contains(factorset.FileName, "_Dim_") {
nameArray, dataArray = util.LoadFactorFileByCsv2(path)
} else {
nameArray, dataArray = util.LoadVectorFileByCsv(path)
nameArray, dataArray = util.LoadFactorFileByCsv(path)
}
} else {
nameArray, dataArray = util.LoadVectorFileBySpace(path)
nameArray, dataArray = util.LoadFactorFileBySpace(path)
}

exampleVectors := []*Vector{}
vectors := []*Vector{}
vectorMap := map[string]*Vector{}
exampleFactors := []*Factor{}
factors := []*Factor{}
factorMap := map[string]*Factor{}
for i := 0; i < len(nameArray); i++ {
vector := &Vector{
factor := &Factor{
Name: nameArray[i],
Data: dataArray[i],
}

if i < 100 {
exampleVectors = append(exampleVectors, vector)
exampleFactors = append(exampleFactors, factor)
}
vectors = append(vectors, vector)
vectorMap[vector.Name] = vector
factors = append(factors, factor)
factorMap[factor.Name] = factor
}

vectorset.Vectors = exampleVectors
vectorset.AllVectors = vectors
vectorset.VectorMap = vectorMap
factorset.Factors = exampleFactors
factorset.AllFactors = factors
factorset.FactorMap = factorMap
}

func (vectorset *Vectorset) WriteVectors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, vectorset.FileName))
func (factorset *Factorset) WriteFactors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, factorset.FileName))

rows := [][]string{}
for _, vector := range vectorset.AllVectors {
row := util.FloatsToStrings(vector.Data)
row = append([]string{vector.Name}, row...)
for _, factor := range factorset.AllFactors {
row := util.FloatsToStrings(factor.Data)
row = append([]string{factor.Name}, row...)
rows = append(rows, row)
}


object/vectorset_upload_test.go → object/factorset_upload_test.go View File

@@ -16,11 +16,11 @@ package object

import "testing"

func TestUpdateVectorsetVectors(t *testing.T) {
func TestUpdateFactorsetFactors(t *testing.T) {
InitConfig()

//vectorset := getVectorset("admin", "wikipedia")
vectorset, _ := getVectorset("admin", "wordVector_utf-8")
vectorset.LoadVectors("../../tmpFiles/")
UpdateVectorset(vectorset.GetId(), vectorset)
//factorset := getFactorset("admin", "wikipedia")
factorset, _ := getFactorset("admin", "wordFactor_utf-8")
factorset.LoadFactors("../../tmpFiles/")
UpdateFactorset(factorset.GetId(), factorset)
}

+ 13
- 13
object/kmeans.go View File

@@ -32,19 +32,19 @@ func fa2Str(floatArray []float64) string {
return strings.Join(sData, "|")
}

func runKmeans(vectors []*Vector, clusterNumber int) {
vectorMap := map[string]*Vector{}
func runKmeans(factors []*Factor, clusterNumber int) {
factorMap := map[string]*Factor{}

var d clusters.Observations
for _, vector := range vectors {
if len(vector.Data) == 0 {
for _, factor := range factors {
if len(factor.Data) == 0 {
continue
}

dataKey := vector.GetDataKey()
vectorMap[dataKey] = vector
dataKey := factor.GetDataKey()
factorMap[dataKey] = factor

d = append(d, clusters.Coordinates(vector.Data))
d = append(d, clusters.Coordinates(factor.Data))
}

km := kmeans.New()
@@ -62,20 +62,20 @@ func runKmeans(vectors []*Vector, clusterNumber int) {
floatArray := observation.Coordinates()
dataKey := fa2Str(floatArray)

vector, ok := vectorMap[dataKey]
factor, ok := factorMap[dataKey]
if !ok {
panic(fmt.Errorf("vectorMap vector not found, dataKey = %s", dataKey))
panic(fmt.Errorf("factorMap factor not found, dataKey = %s", dataKey))
}
vector.Category = strconv.Itoa(i)
vector.Color = color
factor.Category = strconv.Itoa(i)
factor.Color = color
}
}
}

func updateWordsetVectorCategories(owner string, wordsetName string) {
func updateWordsetFactorCategories(owner string, wordsetName string) {
wordset, _ := getWordset(owner, wordsetName)

runKmeans(wordset.Vectors, 100)
runKmeans(wordset.Factors, 100)

UpdateWordset(wordset.GetId(), wordset)
}

+ 2
- 2
object/kmeans_test.go View File

@@ -16,8 +16,8 @@ package object

import "testing"

func TestUpdateWordsetVectorCategories(t *testing.T) {
func TestUpdateWordsetFactorCategories(t *testing.T) {
InitConfig()

updateWordsetVectorCategories("admin", "word")
updateWordsetFactorCategories("admin", "word")
}

+ 2
- 2
object/wordset.go View File

@@ -28,9 +28,9 @@ type Wordset struct {

DisplayName string `xorm:"varchar(100)" json:"displayName"`
DistanceLimit int `json:"distanceLimit"`
Vectorset string `xorm:"varchar(100)" json:"vectorset"`
Factorset string `xorm:"varchar(100)" json:"factorset"`

Vectors []*Vector `xorm:"mediumtext" json:"vectors"`
Factors []*Factor `xorm:"mediumtext" json:"factors"`
}

func GetGlobalWordsets() ([]*Wordset, error) {


+ 24
- 24
object/wordset_graph.go View File

@@ -45,13 +45,13 @@ func GetWordsetGraph(id string, clusterNumber int, distanceLimit int) (*Graph, e
return nil, nil
}

if len(wordset.Vectors) == 0 {
if len(wordset.Factors) == 0 {
return nil, nil
}

allZero := true
for _, vector := range wordset.Vectors {
if len(vector.Data) != 0 {
for _, factor := range wordset.Factors {
if len(factor.Data) != 0 {
allZero = false
break
}
@@ -60,14 +60,14 @@ func GetWordsetGraph(id string, clusterNumber int, distanceLimit int) (*Graph, e
return nil, nil
}

runKmeans(wordset.Vectors, clusterNumber)
runKmeans(wordset.Factors, clusterNumber)

g = generateGraph(wordset.Vectors, distanceLimit)
g = generateGraph(wordset.Factors, distanceLimit)
//graphCache[cacheId] = g
return g, nil
}

func getDistance(v1 *Vector, v2 *Vector) float64 {
func getDistance(v1 *Factor, v2 *Factor) float64 {
res := 0.0
for i := range v1.Data {
res += (v1.Data[i] - v2.Data[i]) * (v1.Data[i] - v2.Data[i])
@@ -75,11 +75,11 @@ func getDistance(v1 *Vector, v2 *Vector) float64 {
return math.Sqrt(res)
}

func refineVectors(vectors []*Vector) []*Vector {
res := []*Vector{}
for _, vector := range vectors {
if len(vector.Data) > 0 {
res = append(res, vector)
func refineFactors(factors []*Factor) []*Factor {
res := []*Factor{}
for _, factor := range factors {
if len(factor.Data) > 0 {
res = append(res, factor)
}
}
return res
@@ -97,19 +97,19 @@ func getNodeColor(weight int) string {
return fmt.Sprintf("rgb(%d,%d,%d)", myColor.R, myColor.G, myColor.B)
}

func generateGraph(vectors []*Vector, distanceLimit int) *Graph {
vectors = refineVectors(vectors)
//vectors = vectors[:100]
func generateGraph(factors []*Factor, distanceLimit int) *Graph {
factors = refineFactors(factors)
//factors = factors[:100]

g := newGraph()
g.Nodes = []*Node{}
g.Links = []*Link{}

nodeWeightMap := map[string]int{}
for i := 0; i < len(vectors); i++ {
for j := i + 1; j < len(vectors); j++ {
v1 := vectors[i]
v2 := vectors[j]
for i := 0; i < len(factors); i++ {
for j := i + 1; j < len(factors); j++ {
v1 := factors[i]
v2 := factors[j]
distance := int(getDistance(v1, v2))
if distance >= distanceLimit {
continue
@@ -134,17 +134,17 @@ func generateGraph(vectors []*Vector, distanceLimit int) *Graph {
}
}

for _, vector := range vectors {
for _, factor := range factors {
//value := 5
value := int(math.Sqrt(float64(nodeWeightMap[vector.Name]))) + 3
weight := nodeWeightMap[vector.Name]
value := int(math.Sqrt(float64(nodeWeightMap[factor.Name]))) + 3
weight := nodeWeightMap[factor.Name]

//nodeColor := "rgb(232,67,62)"
//nodeColor := getNodeColor(value)
nodeColor := vector.Color
nodeColor := factor.Color

fmt.Printf("Node [%s]: weight = %d, nodeValue = %d\n", vector.Name, nodeWeightMap[vector.Name], value)
g.addNode(vector.Name, vector.Name, value, nodeColor, vector.Category, weight)
fmt.Printf("Node [%s]: weight = %d, nodeValue = %d\n", factor.Name, nodeWeightMap[factor.Name], value)
g.addNode(factor.Name, factor.Name, value, nodeColor, factor.Category, weight)
}

return g


+ 7
- 7
object/wordset_match.go View File

@@ -23,21 +23,21 @@ func GetWordsetMatch(id string) (*Wordset, error) {
return nil, nil
}

vectorset, err := getVectorset(wordset.Owner, wordset.Vectorset)
factorset, err := getFactorset(wordset.Owner, wordset.Factorset)
if err != nil {
return nil, err
}
if vectorset == nil {
if factorset == nil {
return nil, nil
}

vectorset.LoadVectors("")
factorset.LoadFactors("")

for _, vector := range wordset.Vectors {
if trueVector, ok := vectorset.VectorMap[vector.Name]; ok {
vector.Data = trueVector.Data
for _, factor := range wordset.Factors {
if trueFactor, ok := factorset.FactorMap[factor.Name]; ok {
factor.Data = trueFactor.Data
} else {
vector.Data = []float64{}
factor.Data = []float64{}
}
}



+ 8
- 8
object/wordset_upload.go View File

@@ -19,23 +19,23 @@ import (
"github.com/casbin/casibase/xlsx"
)

func uploadVectorNames(owner string, fileId string) (bool, error) {
func uploadFactorNames(owner string, fileId string) (bool, error) {
table := xlsx.ReadXlsxFile(fileId)

vectorMap := map[string]int{}
vectors := []*Vector{}
factorMap := map[string]int{}
factors := []*Factor{}
for _, line := range table {
if _, ok := vectorMap[line[0]]; ok {
if _, ok := factorMap[line[0]]; ok {
continue
} else {
vectorMap[line[0]] = 1
factorMap[line[0]] = 1
}

vector := &Vector{
factor := &Factor{
Name: line[0],
Data: []float64{},
}
vectors = append(vectors, vector)
factors = append(factors, factor)
}

wordset := &Wordset{
@@ -44,7 +44,7 @@ func uploadVectorNames(owner string, fileId string) (bool, error) {
CreatedTime: util.GetCurrentTime(),
DisplayName: "word",
DistanceLimit: 14,
Vectors: vectors,
Factors: factors,
}
return AddWordset(wordset)
}

+ 2
- 2
object/wordset_upload_test.go View File

@@ -16,8 +16,8 @@ package object

import "testing"

func TestUploadVectorNames(t *testing.T) {
func TestUploadFactorNames(t *testing.T) {
InitConfig()

uploadVectorNames("admin", "../../tmpFiles/filename")
uploadFactorNames("admin", "../../tmpFiles/filename")
}

+ 6
- 6
routers/router.go View File

@@ -45,12 +45,12 @@ func initAPI() {
beego.Router("/api/add-wordset", &controllers.ApiController{}, "POST:AddWordset")
beego.Router("/api/delete-wordset", &controllers.ApiController{}, "POST:DeleteWordset")

beego.Router("/api/get-global-vectorsets", &controllers.ApiController{}, "GET:GetGlobalVectorsets")
beego.Router("/api/get-vectorsets", &controllers.ApiController{}, "GET:GetVectorsets")
beego.Router("/api/get-vectorset", &controllers.ApiController{}, "GET:GetVectorset")
beego.Router("/api/update-vectorset", &controllers.ApiController{}, "POST:UpdateVectorset")
beego.Router("/api/add-vectorset", &controllers.ApiController{}, "POST:AddVectorset")
beego.Router("/api/delete-vectorset", &controllers.ApiController{}, "POST:DeleteVectorset")
beego.Router("/api/get-global-factorsets", &controllers.ApiController{}, "GET:GetGlobalFactorsets")
beego.Router("/api/get-factorsets", &controllers.ApiController{}, "GET:GetFactorsets")
beego.Router("/api/get-factorset", &controllers.ApiController{}, "GET:GetFactorset")
beego.Router("/api/update-factorset", &controllers.ApiController{}, "POST:UpdateFactorset")
beego.Router("/api/add-factorset", &controllers.ApiController{}, "POST:AddFactorset")
beego.Router("/api/delete-factorset", &controllers.ApiController{}, "POST:DeleteFactorset")

beego.Router("/api/get-global-videos", &controllers.ApiController{}, "GET:GetGlobalVideos")
beego.Router("/api/get-videos", &controllers.ApiController{}, "GET:GetVideos")


+ 3
- 3
util/file.go View File

@@ -38,7 +38,7 @@ func parseJsonToFloats(s string) []float64 {
return res
}

func LoadVectorFileByCsv(path string) ([]string, [][]float64) {
func LoadFactorFileByCsv(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}

@@ -63,7 +63,7 @@ func LoadVectorFileByCsv(path string) ([]string, [][]float64) {
return nameArray, dataArray
}

func LoadVectorFileByCsv2(path string) ([]string, [][]float64) {
func LoadFactorFileByCsv2(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}

@@ -84,7 +84,7 @@ func LoadVectorFileByCsv2(path string) ([]string, [][]float64) {
return nameArray, dataArray
}

func LoadVectorFileBySpace(path string) ([]string, [][]float64) {
func LoadFactorFileBySpace(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}



+ 9
- 9
web/src/App.js View File

@@ -29,8 +29,8 @@ import FileTreePage from "./FileTreePage";
import WordsetListPage from "./WordsetListPage";
import WordsetEditPage from "./WordsetEditPage";
import WordsetGraphPage from "./WordsetGraphPage";
import VectorsetListPage from "./VectorsetListPage";
import VectorsetEditPage from "./VectorsetEditPage";
import FactorsetListPage from "./FactorsetListPage";
import FactorsetEditPage from "./FactorsetEditPage";
import VideoListPage from "./VideoListPage";
import VideoEditPage from "./VideoEditPage";
import ProviderListPage from "./ProviderListPage";
@@ -84,8 +84,8 @@ class App extends Component {
this.setState({selectedMenuKey: "/clustering"});
} else if (uri.includes("/wordsets")) {
this.setState({selectedMenuKey: "/wordsets"});
} else if (uri.includes("/vectorsets")) {
this.setState({selectedMenuKey: "/vectorsets"});
} else if (uri.includes("/factorsets")) {
this.setState({selectedMenuKey: "/factorsets"});
} else if (uri.includes("/videos")) {
this.setState({selectedMenuKey: "/videos"});
} else if (uri.includes("/providers")) {
@@ -298,9 +298,9 @@ class App extends Component {
</Menu.Item>
);
res.push(
<Menu.Item key="/vectorsets">
<Link to="/vectorsets">
{i18next.t("general:Vectorsets")}
<Menu.Item key="/factorsets">
<Link to="/factorsets">
{i18next.t("general:Factorsets")}
</Link>
</Menu.Item>
);
@@ -395,8 +395,8 @@ class App extends Component {
<Route exact path="/wordsets" render={(props) => this.renderSigninIfNotSignedIn(<WordsetListPage account={this.state.account} {...props} />)} />
<Route exact path="/wordsets/:wordsetName" render={(props) => this.renderSigninIfNotSignedIn(<WordsetEditPage account={this.state.account} {...props} />)} />
<Route exact path="/wordsets/:wordsetName/graph" render={(props) => this.renderSigninIfNotSignedIn(<WordsetGraphPage account={this.state.account} {...props} />)} />
<Route exact path="/vectorsets" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetListPage account={this.state.account} {...props} />)} />
<Route exact path="/vectorsets/:vectorsetName" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetEditPage account={this.state.account} {...props} />)} />
<Route exact path="/factorsets" render={(props) => this.renderSigninIfNotSignedIn(<FactorsetListPage account={this.state.account} {...props} />)} />
<Route exact path="/factorsets/:factorsetName" render={(props) => this.renderSigninIfNotSignedIn(<FactorsetEditPage account={this.state.account} {...props} />)} />
<Route exact path="/videos" render={(props) => this.renderSigninIfNotSignedIn(<VideoListPage account={this.state.account} {...props} />)} />
<Route exact path="/videos/:videoName" render={(props) => this.renderSigninIfNotSignedIn(<VideoEditPage account={this.state.account} {...props} />)} />
<Route exact path="/providers" render={(props) => this.renderSigninIfNotSignedIn(<ProviderListPage account={this.state.account} {...props} />)} />


web/src/VectorTable.js → web/src/FactorTable.js View File

@@ -18,7 +18,7 @@ import {Button, Col, Input, Row, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import i18next from "i18next";

class VectorTable extends React.Component {
class FactorTable extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -50,7 +50,7 @@ class VectorTable extends React.Component {
}

addRow(table) {
const row = {no: table.length, name: `New Vector - ${table.length}`, data: []};
const row = {no: table.length, name: `New Factor - ${table.length}`, data: []};
if (table === undefined) {
table = [];
}
@@ -164,4 +164,4 @@ class VectorTable extends React.Component {
}
}

export default VectorTable;
export default FactorTable;

web/src/VectorsetEditPage.js → web/src/FactorsetEditPage.js View File

@@ -1,75 +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.
// 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, InputNumber, Row} from "antd";
import * as VectorsetBackend from "./backend/VectorsetBackend";
import * as FactorsetBackend from "./backend/FactorsetBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import VectorTable from "./VectorTable";
import FactorTable from "./FactorTable";
import {LinkOutlined} from "@ant-design/icons";
class VectorsetEditPage extends React.Component {
class FactorsetEditPage extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
vectorsetName: props.match.params.vectorsetName,
vectorset: null,
factorsetName: props.match.params.factorsetName,
factorset: null,
};
}
UNSAFE_componentWillMount() {
this.getVectorset();
this.getFactorset();
}
getVectorset() {
VectorsetBackend.getVectorset(this.props.account.name, this.state.vectorsetName)
.then((vectorset) => {
if (vectorset.status === "ok") {
getFactorset() {
FactorsetBackend.getFactorset(this.props.account.name, this.state.factorsetName)
.then((factorset) => {
if (factorset.status === "ok") {
this.setState({
vectorset: vectorset.data,
factorset: factorset.data,
});
} else {
Setting.showMessage("error", `Failed to get vectorset: ${vectorset.msg}`);
Setting.showMessage("error", `Failed to get factorset: ${factorset.msg}`);
}
});
}
parseVectorsetField(key, value) {
parseFactorsetField(key, value) {
if (["score"].includes(key)) {
value = Setting.myParseInt(value);
}
return value;
}
updateVectorsetField(key, value) {
value = this.parseVectorsetField(key, value);
updateFactorsetField(key, value) {
value = this.parseFactorsetField(key, value);
const vectorset = this.state.vectorset;
vectorset[key] = value;
const factorset = this.state.factorset;
factorset[key] = value;
this.setState({
vectorset: vectorset,
factorset: factorset,
});
}
renderVectorset() {
renderFactorset() {
return (
<Card size="small" title={
<div>
{i18next.t("vectorset:Edit Vectorset")}&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" onClick={this.submitVectorsetEdit.bind(this)}>{i18next.t("general:Save")}</Button>
{i18next.t("factorset:Edit Factorset")}&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" onClick={this.submitFactorsetEdit.bind(this)}>{i18next.t("general:Save")}</Button>
</div>
} style={{marginLeft: "5px"}} type="inner">
<Row style={{marginTop: "10px"}} >
@@ -77,8 +77,8 @@ class VectorsetEditPage extends React.Component {
{i18next.t("general:Name")}:
</Col>
<Col span={22} >
<Input value={this.state.vectorset.name} onChange={e => {
this.updateVectorsetField("name", e.target.value);
<Input value={this.state.factorset.name} onChange={e => {
this.updateFactorsetField("name", e.target.value);
}} />
</Col>
</Row>
@@ -87,8 +87,8 @@ class VectorsetEditPage extends React.Component {
{i18next.t("general:Display name")}:
</Col>
<Col span={22} >
<Input value={this.state.vectorset.displayName} onChange={e => {
this.updateVectorsetField("displayName", e.target.value);
<Input value={this.state.factorset.displayName} onChange={e => {
this.updateFactorsetField("displayName", e.target.value);
}} />
</Col>
</Row>
@@ -97,60 +97,60 @@ class VectorsetEditPage extends React.Component {
{i18next.t("general:URL")}:
</Col>
<Col span={22} >
<Input prefix={<LinkOutlined />} value={this.state.vectorset.url} onChange={e => {
this.updateVectorsetField("url", e.target.value);
<Input prefix={<LinkOutlined />} value={this.state.factorset.url} onChange={e => {
this.updateFactorsetField("url", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("vectorset:File name")}:
{i18next.t("factorset:File name")}:
</Col>
<Col span={22} >
<Input value={this.state.vectorset.fileName} onChange={e => {
this.updateVectorsetField("fileName", e.target.value);
<Input value={this.state.factorset.fileName} onChange={e => {
this.updateFactorsetField("fileName", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("vectorset:File size")}:
{i18next.t("factorset:File size")}:
</Col>
<Col span={22} >
<Input value={this.state.vectorset.fileSize} onChange={e => {
this.updateVectorsetField("fileSize", e.target.value);
<Input value={this.state.factorset.fileSize} onChange={e => {
this.updateFactorsetField("fileSize", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("vectorset:Dimension")}:
{i18next.t("factorset:Dimension")}:
</Col>
<Col span={22} >
<InputNumber value={this.state.vectorset.dimension} onChange={value => {
this.updateVectorsetField("dimension", value);
<InputNumber value={this.state.factorset.dimension} onChange={value => {
this.updateFactorsetField("dimension", value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("vectorset:Count")}:
{i18next.t("factorset:Count")}:
</Col>
<Col span={22} >
<InputNumber value={this.state.vectorset.count} onChange={value => {
this.updateVectorsetField("count", value);
<InputNumber value={this.state.factorset.count} onChange={value => {
this.updateFactorsetField("count", value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("vectorset:Example vectors")}:
{i18next.t("factorset:Example factors")}:
</Col>
<Col span={22} >
<VectorTable
title={i18next.t("vectorset:Example vectors")}
table={this.state.vectorset.vectors}
onUpdateTable={(value) => {this.updateVectorsetField("vectors", value);}}
<FactorTable
title={i18next.t("factorset:Example factors")}
table={this.state.factorset.factors}
onUpdateTable={(value) => {this.updateFactorsetField("factors", value);}}
/>
</Col>
</Row>
@@ -158,20 +158,20 @@ class VectorsetEditPage extends React.Component {
);
}
submitVectorsetEdit() {
const vectorset = Setting.deepCopy(this.state.vectorset);
VectorsetBackend.updateVectorset(this.state.vectorset.owner, this.state.vectorsetName, vectorset)
submitFactorsetEdit() {
const factorset = Setting.deepCopy(this.state.factorset);
FactorsetBackend.updateFactorset(this.state.factorset.owner, this.state.factorsetName, factorset)
.then((res) => {
if (res.status === "ok") {
if (res.data) {
Setting.showMessage("success", "Successfully saved");
this.setState({
vectorsetName: this.state.vectorset.name,
factorsetName: this.state.factorset.name,
});
this.props.history.push(`/vectorsets/${this.state.vectorset.name}`);
this.props.history.push(`/factorsets/${this.state.factorset.name}`);
} else {
Setting.showMessage("error", "failed to save: server side failure");
this.updateVectorsetField("name", this.state.vectorsetName);
this.updateFactorsetField("name", this.state.factorsetName);
}
} else {
Setting.showMessage("error", `failed to save: ${res.msg}`);
@@ -190,7 +190,7 @@ class VectorsetEditPage extends React.Component {
</Col>
<Col span={22}>
{
this.state.vectorset !== null ? this.renderVectorset() : null
this.state.factorset !== null ? this.renderFactorset() : null
}
</Col>
<Col span={1}>
@@ -200,7 +200,7 @@ class VectorsetEditPage extends React.Component {
<Col span={2}>
</Col>
<Col span={18}>
<Button type="primary" size="large" onClick={this.submitVectorsetEdit.bind(this)}>{i18next.t("general:Save")}</Button>
<Button type="primary" size="large" onClick={this.submitFactorsetEdit.bind(this)}>{i18next.t("general:Save")}</Button>
</Col>
</Row>
</div>
@@ -208,4 +208,4 @@ class VectorsetEditPage extends React.Component {
}
}
export default VectorsetEditPage;
export default FactorsetEditPage;

web/src/VectorsetListPage.js → web/src/FactorsetListPage.js View File

@@ -1,103 +1,103 @@
// 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 React from "react";
import {Link} from "react-router-dom";
import {Button, Col, Popconfirm, Row, Table} from "antd";
import moment from "moment";
import * as Setting from "./Setting";
import * as VectorsetBackend from "./backend/VectorsetBackend";
import * as FactorsetBackend from "./backend/FactorsetBackend";
import i18next from "i18next";
class VectorsetListPage extends React.Component {
class FactorsetListPage extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
vectorsets: null,
factorsets: null,
};
}
UNSAFE_componentWillMount() {
this.getVectorsets();
this.getFactorsets();
}
getVectorsets() {
VectorsetBackend.getVectorsets(this.props.account.name)
getFactorsets() {
FactorsetBackend.getFactorsets(this.props.account.name)
.then((res) => {
if (res.status === "ok") {
this.setState({
vectorsets: res.data,
factorsets: res.data,
});
} else {
Setting.showMessage("error", `Failed to get vectorsets: ${res.msg}`);
Setting.showMessage("error", `Failed to get factorsets: ${res.msg}`);
}
});
}
newVectorset() {
newFactorset() {
const randomName = Setting.getRandomName();
return {
owner: this.props.account.name,
name: `vectorset_${randomName}`,
name: `factorset_${randomName}`,
createdTime: moment().format(),
displayName: `New Vectorset - ${randomName}`,
url: "https://github.com/Embedding/Chinese-Word-Vectors",
displayName: `New Factorset - ${randomName}`,
url: "https://github.com/Embedding/Chinese-Word-Factors",
fileName: "sgns.target.word-word.dynwin5.thr10.neg5.dim300.iter5",
fileSize: "1.69 GB",
dimension: 128,
count: 10000,
vectors: [],
factors: [],
};
}
addVectorset() {
const newVectorset = this.newVectorset();
VectorsetBackend.addVectorset(newVectorset)
addFactorset() {
const newFactorset = this.newFactorset();
FactorsetBackend.addFactorset(newFactorset)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Vectorset added successfully");
Setting.showMessage("success", "Factorset added successfully");
this.setState({
vectorsets: Setting.prependRow(this.state.vectorsets, newVectorset),
factorsets: Setting.prependRow(this.state.factorsets, newFactorset),
});
} else {
Setting.showMessage("error", `Failed to add vectorset: ${res.msg}`);
Setting.showMessage("error", `Failed to add factorset: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Vectorset failed to add: ${error}`);
Setting.showMessage("error", `Factorset failed to add: ${error}`);
});
}
deleteVectorset(i) {
VectorsetBackend.deleteVectorset(this.state.vectorsets[i])
deleteFactorset(i) {
FactorsetBackend.deleteFactorset(this.state.factorsets[i])
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Vectorset deleted successfully");
Setting.showMessage("success", "Factorset deleted successfully");
this.setState({
vectorsets: Setting.deleteRow(this.state.vectorsets, i),
factorsets: Setting.deleteRow(this.state.factorsets, i),
});
} else {
Setting.showMessage("error", `Vectorset failed to delete: ${res.msg}`);
Setting.showMessage("error", `Factorset failed to delete: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Vectorset failed to delete: ${error}`);
Setting.showMessage("error", `Factorset failed to delete: ${error}`);
});
}
renderTable(vectorsets) {
renderTable(factorsets) {
const columns = [
{
title: i18next.t("general:Name"),
@@ -107,7 +107,7 @@ class VectorsetListPage extends React.Component {
sorter: (a, b) => a.name.localeCompare(b.name),
render: (text, record, index) => {
return (
<Link to={`/vectorsets/${text}`}>
<Link to={`/factorsets/${text}`}>
{text}
</Link>
);
@@ -137,38 +137,38 @@ class VectorsetListPage extends React.Component {
},
},
{
title: i18next.t("vectorset:File name"),
title: i18next.t("factorset:File name"),
dataIndex: "fileName",
key: "fileName",
width: "200px",
sorter: (a, b) => a.fileName.localeCompare(b.fileName),
},
{
title: i18next.t("vectorset:File size"),
title: i18next.t("factorset:File size"),
dataIndex: "fileSize",
key: "fileSize",
width: "120px",
sorter: (a, b) => a.fileSize.localeCompare(b.fileSize),
},
{
title: i18next.t("vectorset:Dimension"),
title: i18next.t("factorset:Dimension"),
dataIndex: "dimension",
key: "dimension",
width: "110px",
sorter: (a, b) => a.dimension - b.dimension,
},
{
title: i18next.t("vectorset:Example vectors"),
dataIndex: "vectors",
key: "vectors",
title: i18next.t("factorset:Example factors"),
dataIndex: "factors",
key: "factors",
// width: '120px',
sorter: (a, b) => a.vectors.localeCompare(b.vectors),
sorter: (a, b) => a.factors.localeCompare(b.factors),
render: (text, record, index) => {
return Setting.getTags(text, "vectors");
return Setting.getTags(text, "factors");
},
},
{
title: i18next.t("vectorset:Count"),
title: i18next.t("factorset:Count"),
dataIndex: "count",
key: "count",
width: "110px",
@@ -182,10 +182,10 @@ class VectorsetListPage extends React.Component {
render: (text, record, index) => {
return (
<div>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/vectorsets/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/factorsets/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<Popconfirm
title={`Sure to delete vectorset: ${record.name} ?`}
onConfirm={() => this.deleteVectorset(index)}
title={`Sure to delete factorset: ${record.name} ?`}
onConfirm={() => this.deleteFactorset(index)}
okText="OK"
cancelText="Cancel"
>
@@ -199,14 +199,14 @@ class VectorsetListPage extends React.Component {
return (
<div>
<Table columns={columns} dataSource={vectorsets} rowKey="name" size="middle" bordered pagination={{pageSize: 100}}
<Table columns={columns} dataSource={factorsets} rowKey="name" size="middle" bordered pagination={{pageSize: 100}}
title={() => (
<div>
{i18next.t("general:Vectorsets")}&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" size="small" onClick={this.addVectorset.bind(this)}>{i18next.t("general:Add")}</Button>
{i18next.t("general:Factorsets")}&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" size="small" onClick={this.addFactorset.bind(this)}>{i18next.t("general:Add")}</Button>
</div>
)}
loading={vectorsets === null}
loading={factorsets === null}
/>
</div>
);
@@ -220,7 +220,7 @@ class VectorsetListPage extends React.Component {
</Col>
<Col span={22}>
{
this.renderTable(this.state.vectorsets)
this.renderTable(this.state.factorsets)
}
</Col>
<Col span={1}>
@@ -231,4 +231,4 @@ class VectorsetListPage extends React.Component {
}
}
export default VectorsetListPage;
export default FactorsetListPage;

+ 3
- 3
web/src/FileTable.js View File

@@ -52,7 +52,7 @@ class FileTable extends React.Component {
}

addRow(table) {
const row = {no: table.length, name: `New Vector - ${table.length}`, data: []};
const row = {no: table.length, name: `New Factor - ${table.length}`, data: []};
if (table === undefined) {
table = [];
}
@@ -98,7 +98,7 @@ class FileTable extends React.Component {
renderTable(table) {
const columns = [
{
title: i18next.t("vectorset:File name"),
title: i18next.t("factorset:File name"),
dataIndex: "title",
key: "title",
// width: '200px',
@@ -139,7 +139,7 @@ class FileTable extends React.Component {
},
},
{
title: i18next.t("vectorset:File size"),
title: i18next.t("factorset:File size"),
dataIndex: "size",
key: "size",
width: "120px",


+ 2
- 2
web/src/FileTree.js View File

@@ -808,13 +808,13 @@ class FileTree extends React.Component {
size="small"
// extra={<Button type="primary">Edit</Button>}
>
<Descriptions.Item label={i18next.t("vectorset:File name")}>
<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>
<Descriptions.Item label={i18next.t("vectorset:File size")}>
<Descriptions.Item label={i18next.t("factorset:File size")}>
{Setting.getFriendlyFileSize(file.size)}
</Descriptions.Item>
<Descriptions.Item label={i18next.t("general:Created time")}>


+ 30
- 30
web/src/Setting.js 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 {Tag, Tooltip, message} from "antd";
import {SyncOutlined} from "@ant-design/icons";
import {isMobile as isMobileDevice} from "react-device-detect";
@@ -289,33 +289,33 @@ export function getTag(text, type, state) {
}
}
export function getTags(vectors, type) {
if (!vectors) {
export function getTags(factors, type) {
if (!factors) {
return [];
}
if (type === "vectors") {
return getVectorTag(vectors);
if (type === "factors") {
return getFactorTag(factors);
} else if (type === "users") {
return getUserTag(vectors);
return getUserTag(factors);
}
}
function getVectorTag(vectors) {
function getFactorTag(factors) {
const res = [];
vectors.forEach((vector, i) => {
if (vector.data.length !== 0) {
factors.forEach((factor, i) => {
if (factor.data.length !== 0) {
res.push(
<Tooltip placement="top" title={getShortText(JSON.stringify(vector.data), 500)}>
<Tooltip placement="top" title={getShortText(JSON.stringify(factor.data), 500)}>
<Tag color={"success"}>
{vector.name}
{factor.name}
</Tag>
</Tooltip>
);
} else {
res.push(
<Tag color={"warning"}>
{vector.name}
{factor.name}
</Tag>
);
}
@@ -401,11 +401,11 @@ export function workbook2blob(workbook) {
export function downloadXlsx(wordset) {
const data = [];
wordset.vectors.forEach((vector, i) => {
wordset.factors.forEach((factor, i) => {
const row = {};
row[0] = vector.name;
vector.data.forEach((dataItem, i) => {
row[0] = factor.name;
factor.data.forEach((dataItem, i) => {
row[i + 1] = dataItem;
});
@@ -419,8 +419,8 @@ export function downloadXlsx(wordset) {
// ];
try {
const blob = sheet2blob(sheet, "vectors");
const fileName = `vectors-${wordset.name}.xlsx`;
const blob = sheet2blob(sheet, "factors");
const fileName = `factors-${wordset.name}.xlsx`;
FileSaver.saveAs(blob, fileName);
} catch (error) {
showMessage("error", `failed to download: ${error.message}`);


+ 15
- 15
web/src/VideoListPage.js 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 React from "react";
import {Link} from "react-router-dom";
import {Button, Col, Popconfirm, Row, Table, Upload} from "antd";
@@ -185,7 +185,7 @@ class VideoListPage extends React.Component {
dataIndex: "labels",
key: "labels",
// width: '120px',
sorter: (a, b) => a.vectors.localeCompare(b.vectors),
sorter: (a, b) => a.factors.localeCompare(b.factors),
render: (text, record, index) => {
return Setting.getLabelTags(text);
},


+ 30
- 30
web/src/WordsetEditPage.js View File

@@ -1,25 +1,25 @@
// 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 React from "react";
import {Button, Card, Col, Input, InputNumber, Row, Select} from "antd";
import * as WordsetBackend from "./backend/WordsetBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import VectorTable from "./VectorTable";
import FactorTable from "./FactorTable";
import WordsetGraph from "./WordsetGraph";
import * as VectorsetBackend from "./backend/VectorsetBackend";
import * as FactorsetBackend from "./backend/FactorsetBackend";
const {Option} = Select;
@@ -30,14 +30,14 @@ class WordsetEditPage extends React.Component {
classes: props,
wordsetName: props.match.params.wordsetName,
wordset: null,
vectorsets: null,
factorsets: null,
matchLoading: false,
};
}
UNSAFE_componentWillMount() {
this.getWordset();
this.getVectorsets();
this.getFactorsets();
}
getWordset() {
@@ -53,15 +53,15 @@ class WordsetEditPage extends React.Component {
});
}
getVectorsets() {
VectorsetBackend.getVectorsets(this.props.account.name)
getFactorsets() {
FactorsetBackend.getFactorsets(this.props.account.name)
.then((res) => {
if (res.status === "ok") {
this.setState({
vectorsets: res.data,
factorsets: res.data,
});
} else {
Setting.showMessage("error", `Failed to get vectorsets: ${res.msg}`);
Setting.showMessage("error", `Failed to get factorsets: ${res.msg}`);
}
});
}
@@ -84,8 +84,8 @@ class WordsetEditPage extends React.Component {
}
renderWordset() {
const allWords = this.state.wordset?.vectors.length;
const validWords = this.state.wordset?.vectors.filter(vector => vector.data.length !== 0).length;
const allWords = this.state.wordset?.factors.length;
const validWords = this.state.wordset?.factors.filter(factor => factor.data.length !== 0).length;
return (
<Card size="small" title={
@@ -116,12 +116,12 @@ class WordsetEditPage extends React.Component {
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("wordset:Vectorset")}:
{i18next.t("wordset:Factorset")}:
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.wordset.vectorset} onChange={(value => {this.updateWordsetField("vectorset", value);})}>
<Select virtual={false} style={{width: "100%"}} value={this.state.wordset.factorset} onChange={(value => {this.updateWordsetField("factorset", value);})}>
{
this.state.vectorsets?.map((vectorset, index) => <Option key={index} value={vectorset.name}>{vectorset.name}</Option>)
this.state.factorsets?.map((factorset, index) => <Option key={index} value={factorset.name}>{factorset.name}</Option>)
}
</Select>
</Col>
@@ -172,11 +172,11 @@ class WordsetEditPage extends React.Component {
{i18next.t("wordset:Words")}:
</Col>
<Col span={22} >
<VectorTable
<FactorTable
title={i18next.t("wordset:Words")}
table={this.state.wordset.vectors}
table={this.state.wordset.factors}
wordset={this.state.wordset}
onUpdateTable={(value) => {this.updateWordsetField("vectors", value);}}
onUpdateTable={(value) => {this.updateWordsetField("factors", value);}}
/>
</Col>
</Row>


+ 27
- 47
web/src/WordsetListPage.js 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 React from "react";
import {Link} from "react-router-dom";
import {Button, Col, Popconfirm, Row, Table} from "antd";
@@ -54,8 +54,8 @@ class WordsetListPage extends React.Component {
createdTime: moment().format(),
displayName: `New Wordset - ${randomName}`,
distanceLimit: 14,
vectorset: "wordVector_utf-8",
vectors: [],
factorset: "wordFactor_utf-8",
factors: [],
};
}
@@ -119,43 +119,23 @@ class WordsetListPage extends React.Component {
},
{
title: i18next.t("wordset:Words"),
dataIndex: "vectors",
key: "vectors",
dataIndex: "factors",
key: "factors",
// width: '120px',
sorter: (a, b) => a.vectors.localeCompare(b.vectors),
sorter: (a, b) => a.factors.localeCompare(b.factors),
render: (text, record, index) => {
return Setting.getTags(text, "vectors");
return Setting.getTags(text, "factors");
},
},
// {
// title: i18next.t("wordset:All words"),
// dataIndex: 'allWords',
// key: 'allWords',
// width: '140px',
// sorter: (a, b) => a.allWords - b.allWords,
// render: (text, record, index) => {
// return record.vectors.length;
// }
// },
// {
// title: i18next.t("wordset:Valid words"),
// dataIndex: 'validWords',
// key: 'validWords',
// width: '140px',
// sorter: (a, b) => a.validWords - b.validWords,
// render: (text, record, index) => {
// return record.vectors.filter(vector => vector.data.length !== 0).length;
// }
// },
{
title: i18next.t("wordset:Vectorset"),
dataIndex: "vectorset",
key: "vectorset",
title: i18next.t("wordset:Factorset"),
dataIndex: "factorset",
key: "factorset",
width: "140px",
sorter: (a, b) => a.vectorset.localeCompare(b.vectorset),
sorter: (a, b) => a.factorset.localeCompare(b.factorset),
render: (text, record, index) => {
return (
<Link to={`/vectorsets/${text}`}>
<Link to={`/factorsets/${text}`}>
{text}
</Link>
);
@@ -167,8 +147,8 @@ class WordsetListPage extends React.Component {
key: "matched",
width: "140px",
render: (text, record, index) => {
const allWords = record.vectors.length;
const validWords = record.vectors.filter(vector => vector.data.length !== 0).length;
const allWords = record.factors.length;
const validWords = record.factors.filter(factor => factor.data.length !== 0).length;
return `${Setting.getPercentage(allWords === 0 ? 0 : validWords / allWords)}% (${validWords} / ${allWords})`;
},
},


web/src/backend/VectorsetBackend.js → web/src/backend/FactorsetBackend.js View File

@@ -1,70 +1,70 @@
// 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 getGlobalVectorsets() {
return fetch(`${Setting.ServerUrl}/api/get-global-vectorsets`, {
export function getGlobalFactorsets() {
return fetch(`${Setting.ServerUrl}/api/get-global-factorsets`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function getVectorsets(owner) {
return fetch(`${Setting.ServerUrl}/api/get-vectorsets?owner=${owner}`, {
export function getFactorsets(owner) {
return fetch(`${Setting.ServerUrl}/api/get-factorsets?owner=${owner}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function getVectorset(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-vectorset?id=${owner}/${encodeURIComponent(name)}`, {
export function getFactorset(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-factorset?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include",
}).then(res => res.json());
}
export function getVectorsetGraph(owner, name, clusterNumber, distanceLimit) {
return fetch(`${Setting.ServerUrl}/api/get-vectorset-graph?id=${owner}/${encodeURIComponent(name)}&clusterNumber=${clusterNumber}&distanceLimit=${distanceLimit}`, {
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 updateVectorset(owner, name, vectorset) {
const newVectorset = Setting.deepCopy(vectorset);
return fetch(`${Setting.ServerUrl}/api/update-vectorset?id=${owner}/${encodeURIComponent(name)}`, {
export function updateFactorset(owner, name, factorset) {
const newFactorset = Setting.deepCopy(factorset);
return fetch(`${Setting.ServerUrl}/api/update-factorset?id=${owner}/${encodeURIComponent(name)}`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newVectorset),
body: JSON.stringify(newFactorset),
}).then(res => res.json());
}
export function addVectorset(vectorset) {
const newVectorset = Setting.deepCopy(vectorset);
return fetch(`${Setting.ServerUrl}/api/add-vectorset`, {
export function addFactorset(factorset) {
const newFactorset = Setting.deepCopy(factorset);
return fetch(`${Setting.ServerUrl}/api/add-factorset`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newVectorset),
body: JSON.stringify(newFactorset),
}).then(res => res.json());
}
export function deleteVectorset(vectorset) {
const newVectorset = Setting.deepCopy(vectorset);
return fetch(`${Setting.ServerUrl}/api/delete-vectorset`, {
export function deleteFactorset(factorset) {
const newFactorset = Setting.deepCopy(factorset);
return fetch(`${Setting.ServerUrl}/api/delete-factorset`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newVectorset),
body: JSON.stringify(newFactorset),
}).then(res => res.json());
}

+ 5
- 5
web/src/locales/en/data.json View File

@@ -26,7 +26,7 @@
"Save": "Save",
"Stores": "Stores",
"URL": "URL",
"Vectorsets": "Vectorsets",
"Factorsets": "Factorsets",
"Videos": "Videos",
"View": "View",
"Wordsets": "Wordsets"
@@ -66,11 +66,11 @@
"files and": "files and",
"folders are checked": "folders are checked"
},
"vectorset": {
"factorset": {
"Count": "Count",
"Dimension": "Dimension",
"Edit Vectorset": "Edit Vectorset",
"Example vectors": "Example vectors",
"Edit Factorset": "Edit Factorset",
"Example factors": "Example factors",
"File name": "File name",
"File size": "File size"
},
@@ -94,7 +94,7 @@
"Match": "Match",
"Matched": "Matched",
"Valid words": "Valid words",
"Vectorset": "Vectorset",
"Factorset": "Factorset",
"Words": "Words"
}
}

+ 5
- 5
web/src/locales/zh/data.json View File

@@ -26,7 +26,7 @@
"Save": "保存",
"Stores": "我的数据仓库",
"URL": "链接",
"Vectorsets": "我的向量集",
"Factorsets": "我的向量集",
"Videos": "我的视频",
"View": "查看",
"Wordsets": "我的词汇集"
@@ -66,11 +66,11 @@
"files and": "个文件和",
"folders are checked": "文件夹已被选择"
},
"vectorset": {
"factorset": {
"Count": "个数",
"Dimension": "维度",
"Edit Vectorset": "编辑向量集",
"Example vectors": "示例向量",
"Edit Factorset": "编辑向量集",
"Example factors": "示例向量",
"File name": "文件名",
"File size": "文件大小"
},
@@ -94,7 +94,7 @@
"Match": "匹配",
"Matched": "匹配度",
"Valid words": "有效词汇",
"Vectorset": "向量集",
"Factorset": "向量集",
"Words": "词汇表"
}
}

Loading…
Cancel
Save