| @@ -0,0 +1,61 @@ | |||
| package controllers | |||
| import ( | |||
| "encoding/json" | |||
| "github.com/casbin/casbase/object" | |||
| ) | |||
| func (c *ApiController) GetGlobalVectorsets() { | |||
| c.Data["json"] = object.GetGlobalVectorsets() | |||
| c.ServeJSON() | |||
| } | |||
| func (c *ApiController) GetVectorsets() { | |||
| owner := c.Input().Get("owner") | |||
| c.Data["json"] = object.GetVectorsets(owner) | |||
| c.ServeJSON() | |||
| } | |||
| func (c *ApiController) GetVectorset() { | |||
| id := c.Input().Get("id") | |||
| c.Data["json"] = object.GetVectorset(id) | |||
| c.ServeJSON() | |||
| } | |||
| func (c *ApiController) UpdateVectorset() { | |||
| id := c.Input().Get("id") | |||
| var vectorset object.Vectorset | |||
| err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| c.Data["json"] = object.UpdateVectorset(id, &vectorset) | |||
| c.ServeJSON() | |||
| } | |||
| func (c *ApiController) AddVectorset() { | |||
| var vectorset object.Vectorset | |||
| err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| c.Data["json"] = object.AddVectorset(&vectorset) | |||
| c.ServeJSON() | |||
| } | |||
| func (c *ApiController) DeleteVectorset() { | |||
| var vectorset object.Vectorset | |||
| err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| c.Data["json"] = object.DeleteVectorset(&vectorset) | |||
| c.ServeJSON() | |||
| } | |||
| @@ -89,4 +89,9 @@ func (a *Adapter) createTable() { | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| err = a.engine.Sync2(new(Vectorset)) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| } | |||
| @@ -0,0 +1,96 @@ | |||
| package object | |||
| import ( | |||
| "fmt" | |||
| "github.com/casbin/casbase/util" | |||
| "xorm.io/core" | |||
| ) | |||
| type Vectorset 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"` | |||
| Url string `xorm:"varchar(100)" json:"url"` | |||
| Dimension int `json:"dimension"` | |||
| Vectors []*Vector `xorm:"mediumtext" json:"vectors"` | |||
| } | |||
| func GetGlobalVectorsets() []*Vectorset { | |||
| vectorsets := []*Vectorset{} | |||
| err := adapter.engine.Asc("owner").Desc("created_time").Find(&vectorsets) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| return vectorsets | |||
| } | |||
| func GetVectorsets(owner string) []*Vectorset { | |||
| vectorsets := []*Vectorset{} | |||
| err := adapter.engine.Desc("created_time").Find(&vectorsets, &Vectorset{Owner: owner}) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| return vectorsets | |||
| } | |||
| func getVectorset(owner string, name string) *Vectorset { | |||
| vectorset := Vectorset{Owner: owner, Name: name} | |||
| existed, err := adapter.engine.Get(&vectorset) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| if existed { | |||
| return &vectorset | |||
| } else { | |||
| return nil | |||
| } | |||
| } | |||
| func GetVectorset(id string) *Vectorset { | |||
| owner, name := util.GetOwnerAndNameFromId(id) | |||
| return getVectorset(owner, name) | |||
| } | |||
| func UpdateVectorset(id string, vectorset *Vectorset) bool { | |||
| owner, name := util.GetOwnerAndNameFromId(id) | |||
| if getVectorset(owner, name) == nil { | |||
| return false | |||
| } | |||
| _, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(vectorset) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| //return affected != 0 | |||
| return true | |||
| } | |||
| func AddVectorset(vectorset *Vectorset) bool { | |||
| affected, err := adapter.engine.Insert(vectorset) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| return affected != 0 | |||
| } | |||
| func DeleteVectorset(vectorset *Vectorset) bool { | |||
| affected, err := adapter.engine.ID(core.PK{vectorset.Owner, vectorset.Name}).Delete(&Vectorset{}) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| return affected != 0 | |||
| } | |||
| func (vectorset *Vectorset) GetId() string { | |||
| return fmt.Sprintf("%s/%s", vectorset.Owner, vectorset.Name) | |||
| } | |||
| @@ -29,4 +29,11 @@ func initAPI() { | |||
| beego.Router("/api/update-dataset", &controllers.ApiController{}, "POST:UpdateDataset") | |||
| beego.Router("/api/add-dataset", &controllers.ApiController{}, "POST:AddDataset") | |||
| beego.Router("/api/delete-dataset", &controllers.ApiController{}, "POST:DeleteDataset") | |||
| 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") | |||
| } | |||
| @@ -10,6 +10,8 @@ import * as Conf from "./Conf"; | |||
| import HomePage from "./HomePage"; | |||
| import DatasetListPage from "./DatasetListPage"; | |||
| import DatasetEditPage from "./DatasetEditPage"; | |||
| import VectorsetListPage from "./VectorsetListPage"; | |||
| import VectorsetEditPage from "./VectorsetEditPage"; | |||
| import SigninPage from "./SigninPage"; | |||
| import i18next from "i18next"; | |||
| import SelectLanguageBox from "./SelectLanguageBox"; | |||
| @@ -53,6 +55,8 @@ class App extends Component { | |||
| this.setState({selectedMenuKey: '/'}); | |||
| } else if (uri.includes('/datasets')) { | |||
| this.setState({ selectedMenuKey: '/datasets' }); | |||
| } else if (uri.includes('/vectorsets')) { | |||
| this.setState({ selectedMenuKey: '/vectorsets' }); | |||
| } else { | |||
| this.setState({selectedMenuKey: 'null'}); | |||
| } | |||
| @@ -219,6 +223,13 @@ class App extends Component { | |||
| </Link> | |||
| </Menu.Item> | |||
| ); | |||
| res.push( | |||
| <Menu.Item key="/vectorsets"> | |||
| <Link to="/vectorsets"> | |||
| {i18next.t("general:Vectorsets")} | |||
| </Link> | |||
| </Menu.Item> | |||
| ); | |||
| return res; | |||
| } | |||
| @@ -271,6 +282,8 @@ class App extends Component { | |||
| <Route exact path="/signin" render={(props) => this.renderHomeIfSignedIn(<SigninPage {...props} />)}/> | |||
| <Route exact path="/datasets" render={(props) => this.renderSigninIfNotSignedIn(<DatasetListPage account={this.state.account} {...props} />)}/> | |||
| <Route exact path="/datasets/:datasetName" render={(props) => this.renderSigninIfNotSignedIn(<DatasetEditPage 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} />)}/> | |||
| </Switch> | |||
| </div> | |||
| ) | |||
| @@ -76,7 +76,7 @@ class DatasetEditPage extends React.Component { | |||
| </Row> | |||
| <Row style={{marginTop: '20px'}} > | |||
| <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}> | |||
| {i18next.t("dataset:Distance")} : | |||
| {i18next.t("dataset:Distance")}: | |||
| </Col> | |||
| <Col span={22} > | |||
| <InputNumber value={this.state.dataset.distance} onChange={value => { | |||
| @@ -98,7 +98,7 @@ class DatasetEditPage extends React.Component { | |||
| </Row> | |||
| <Row style={{marginTop: '20px'}} > | |||
| <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}> | |||
| {i18next.t("general:Preview")} : | |||
| {i18next.t("general:Preview")}: | |||
| </Col> | |||
| <Col span={22} > | |||
| <Dataset dataset={this.state.dataset} datasetName={this.state.dataset.name} /> | |||
| @@ -0,0 +1,167 @@ | |||
| import React from "react"; | |||
| import {Button, Card, Col, Input, InputNumber, Row} from 'antd'; | |||
| import * as VectorsetBackend from "./backend/VectorsetBackend"; | |||
| import * as Setting from "./Setting"; | |||
| import i18next from "i18next"; | |||
| import VectorTable from "./VectorTable"; | |||
| import {LinkOutlined} from "@ant-design/icons"; | |||
| class VectorsetEditPage extends React.Component { | |||
| constructor(props) { | |||
| super(props); | |||
| this.state = { | |||
| classes: props, | |||
| vectorsetName: props.match.params.vectorsetName, | |||
| vectorset: null, | |||
| }; | |||
| } | |||
| componentWillMount() { | |||
| this.getVectorset(); | |||
| } | |||
| getVectorset() { | |||
| VectorsetBackend.getVectorset(this.props.account.name, this.state.vectorsetName) | |||
| .then((vectorset) => { | |||
| this.setState({ | |||
| vectorset: vectorset, | |||
| }); | |||
| }); | |||
| } | |||
| parseVectorsetField(key, value) { | |||
| if (["score"].includes(key)) { | |||
| value = Setting.myParseInt(value); | |||
| } | |||
| return value; | |||
| } | |||
| updateVectorsetField(key, value) { | |||
| value = this.parseVectorsetField(key, value); | |||
| let vectorset = this.state.vectorset; | |||
| vectorset[key] = value; | |||
| this.setState({ | |||
| vectorset: vectorset, | |||
| }); | |||
| } | |||
| renderVectorset() { | |||
| return ( | |||
| <Card size="small" title={ | |||
| <div> | |||
| {i18next.t("vectorset:Edit Vectorset")} | |||
| <Button type="primary" onClick={this.submitVectorsetEdit.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.vectorset.name} onChange={e => { | |||
| this.updateVectorsetField('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.vectorset.displayName} onChange={e => { | |||
| this.updateVectorsetField('displayName', e.target.value); | |||
| }} /> | |||
| </Col> | |||
| </Row> | |||
| <Row style={{marginTop: '20px'}} > | |||
| <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}> | |||
| {i18next.t("general:URL")}: | |||
| </Col> | |||
| <Col span={22} > | |||
| <Input prefix={<LinkOutlined/>} value={this.state.vectorset.url} onChange={e => { | |||
| this.updateVectorsetField('url', e.target.value); | |||
| }} /> | |||
| </Col> | |||
| </Row> | |||
| <Row style={{marginTop: '20px'}} > | |||
| <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}> | |||
| {i18next.t("vectorset:Dimension")}: | |||
| </Col> | |||
| <Col span={22} > | |||
| <InputNumber value={this.state.vectorset.dimension} onChange={value => { | |||
| this.updateVectorsetField('dimension', value); | |||
| }} /> | |||
| </Col> | |||
| </Row> | |||
| <Row style={{marginTop: '20px'}} > | |||
| <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}> | |||
| {i18next.t("vectorset:Count")}: | |||
| </Col> | |||
| <Col span={22} > | |||
| <InputNumber disabled={true} value={this.state.vectorset.vectors.length} /> | |||
| </Col> | |||
| </Row> | |||
| <Row style={{marginTop: '20px'}} > | |||
| <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}> | |||
| {i18next.t("vectorset:Vectors")}: | |||
| </Col> | |||
| <Col span={22} > | |||
| <VectorTable | |||
| title={i18next.t("vectorset:Vectors")} | |||
| table={this.state.vectorset.vectors} | |||
| onUpdateTable={(value) => { this.updateVectorsetField('vectors', value)}} | |||
| /> | |||
| </Col> | |||
| </Row> | |||
| </Card> | |||
| ) | |||
| } | |||
| submitVectorsetEdit() { | |||
| let vectorset = Setting.deepCopy(this.state.vectorset); | |||
| VectorsetBackend.updateVectorset(this.state.vectorset.owner, this.state.vectorsetName, vectorset) | |||
| .then((res) => { | |||
| if (res) { | |||
| Setting.showMessage("success", `Successfully saved`); | |||
| this.setState({ | |||
| vectorsetName: this.state.vectorset.name, | |||
| }); | |||
| this.props.history.push(`/vectorsets/${this.state.vectorset.name}`); | |||
| } else { | |||
| Setting.showMessage("error", `failed to save: server side failure`); | |||
| this.updateVectorsetField('name', this.state.vectorsetName); | |||
| } | |||
| }) | |||
| .catch(error => { | |||
| Setting.showMessage("error", `failed to save: ${error}`); | |||
| }); | |||
| } | |||
| render() { | |||
| return ( | |||
| <div> | |||
| <Row style={{width: "100%"}}> | |||
| <Col span={1}> | |||
| </Col> | |||
| <Col span={22}> | |||
| { | |||
| this.state.vectorset !== null ? this.renderVectorset() : null | |||
| } | |||
| </Col> | |||
| <Col span={1}> | |||
| </Col> | |||
| </Row> | |||
| <Row style={{margin: 10}}> | |||
| <Col span={2}> | |||
| </Col> | |||
| <Col span={18}> | |||
| <Button type="primary" size="large" onClick={this.submitVectorsetEdit.bind(this)}>{i18next.t("general:Save")}</Button> | |||
| </Col> | |||
| </Row> | |||
| </div> | |||
| ); | |||
| } | |||
| } | |||
| export default VectorsetEditPage; | |||
| @@ -0,0 +1,195 @@ | |||
| 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 i18next from "i18next"; | |||
| class VectorsetListPage extends React.Component { | |||
| constructor(props) { | |||
| super(props); | |||
| this.state = { | |||
| classes: props, | |||
| vectorsets: null, | |||
| }; | |||
| } | |||
| componentWillMount() { | |||
| this.getVectorsets(); | |||
| } | |||
| getVectorsets() { | |||
| VectorsetBackend.getVectorsets(this.props.account.name) | |||
| .then((res) => { | |||
| this.setState({ | |||
| vectorsets: res, | |||
| }); | |||
| }); | |||
| } | |||
| newVectorset() { | |||
| return { | |||
| owner: this.props.account.name, | |||
| name: `vectorset_${this.state.vectorsets.length}`, | |||
| createdTime: moment().format(), | |||
| displayName: `Vectorset ${this.state.vectorsets.length}`, | |||
| url: "https://github.com/Embedding/Chinese-Word-Vectors", | |||
| dimension: 128, | |||
| vectors: [], | |||
| } | |||
| } | |||
| addVectorset() { | |||
| const newVectorset = this.newVectorset(); | |||
| VectorsetBackend.addVectorset(newVectorset) | |||
| .then((res) => { | |||
| Setting.showMessage("success", `Vectorset added successfully`); | |||
| this.setState({ | |||
| vectorsets: Setting.prependRow(this.state.vectorsets, newVectorset), | |||
| }); | |||
| } | |||
| ) | |||
| .catch(error => { | |||
| Setting.showMessage("error", `Vectorset failed to add: ${error}`); | |||
| }); | |||
| } | |||
| deleteVectorset(i) { | |||
| VectorsetBackend.deleteVectorset(this.state.vectorsets[i]) | |||
| .then((res) => { | |||
| Setting.showMessage("success", `Vectorset deleted successfully`); | |||
| this.setState({ | |||
| vectorsets: Setting.deleteRow(this.state.vectorsets, i), | |||
| }); | |||
| } | |||
| ) | |||
| .catch(error => { | |||
| Setting.showMessage("error", `Vectorset failed to delete: ${error}`); | |||
| }); | |||
| } | |||
| renderTable(vectorsets) { | |||
| const columns = [ | |||
| { | |||
| title: i18next.t("general:Name"), | |||
| dataIndex: 'name', | |||
| key: 'name', | |||
| width: '120px', | |||
| sorter: (a, b) => a.name.localeCompare(b.name), | |||
| render: (text, record, index) => { | |||
| return ( | |||
| <Link to={`/vectorsets/${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("general:URL"), | |||
| dataIndex: 'url', | |||
| key: 'url', | |||
| width: '300px', | |||
| sorter: (a, b) => a.url.localeCompare(b.url), | |||
| render: (text, record, index) => { | |||
| return ( | |||
| <a target="_blank" rel="noreferrer" href={text}> | |||
| { | |||
| Setting.getShortText(text) | |||
| } | |||
| </a> | |||
| ) | |||
| } | |||
| }, | |||
| { | |||
| title: i18next.t("vectorset:Dimension"), | |||
| dataIndex: 'dimension', | |||
| key: 'dimension', | |||
| width: '130px', | |||
| sorter: (a, b) => a.dimension - b.dimension, | |||
| }, | |||
| { | |||
| title: i18next.t("vectorset:Vectors"), | |||
| dataIndex: 'vectors', | |||
| key: 'vectors', | |||
| // width: '120px', | |||
| sorter: (a, b) => a.vectors.localeCompare(b.vectors), | |||
| render: (text, record, index) => { | |||
| return Setting.getTags(text); | |||
| } | |||
| }, | |||
| { | |||
| title: i18next.t("vectorset:Count"), | |||
| dataIndex: 'count', | |||
| key: 'count', | |||
| width: '120px', | |||
| sorter: (a, b) => a.count - b.count, | |||
| render: (text, record, index) => { | |||
| return record.vectors.length; | |||
| } | |||
| }, | |||
| { | |||
| title: i18next.t("general:Action"), | |||
| dataIndex: 'action', | |||
| key: 'action', | |||
| width: '160px', | |||
| 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> | |||
| <Popconfirm | |||
| title={`Sure to delete vectorset: ${record.name} ?`} | |||
| onConfirm={() => this.deleteVectorset(index)} | |||
| okText="OK" | |||
| cancelText="Cancel" | |||
| > | |||
| <Button style={{marginBottom: '10px'}} type="danger">{i18next.t("general:Delete")}</Button> | |||
| </Popconfirm> | |||
| </div> | |||
| ) | |||
| } | |||
| }, | |||
| ]; | |||
| return ( | |||
| <div> | |||
| <Table columns={columns} dataSource={vectorsets} rowKey="name" size="middle" bordered pagination={{pageSize: 100}} | |||
| title={() => ( | |||
| <div> | |||
| {i18next.t("general:Vectorsets")} | |||
| <Button type="primary" size="small" onClick={this.addVectorset.bind(this)}>{i18next.t("general:Add")}</Button> | |||
| </div> | |||
| )} | |||
| loading={vectorsets === null} | |||
| /> | |||
| </div> | |||
| ); | |||
| } | |||
| render() { | |||
| return ( | |||
| <div> | |||
| <Row style={{width: "100%"}}> | |||
| <Col span={1}> | |||
| </Col> | |||
| <Col span={22}> | |||
| { | |||
| this.renderTable(this.state.vectorsets) | |||
| } | |||
| </Col> | |||
| <Col span={1}> | |||
| </Col> | |||
| </Row> | |||
| </div> | |||
| ); | |||
| } | |||
| } | |||
| export default VectorsetListPage; | |||
| @@ -0,0 +1,56 @@ | |||
| import * as Setting from "../Setting"; | |||
| export function getGlobalVectorsets() { | |||
| return fetch(`${Setting.ServerUrl}/api/get-global-vectorsets`, { | |||
| method: "GET", | |||
| credentials: "include" | |||
| }).then(res => res.json()); | |||
| } | |||
| export function getVectorsets(owner) { | |||
| return fetch(`${Setting.ServerUrl}/api/get-vectorsets?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)}`, { | |||
| 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}`, { | |||
| method: "GET", | |||
| credentials: "include" | |||
| }).then(res => res.json()); | |||
| } | |||
| export function updateVectorset(owner, name, vectorset) { | |||
| let newVectorset = Setting.deepCopy(vectorset); | |||
| return fetch(`${Setting.ServerUrl}/api/update-vectorset?id=${owner}/${encodeURIComponent(name)}`, { | |||
| method: 'POST', | |||
| credentials: 'include', | |||
| body: JSON.stringify(newVectorset), | |||
| }).then(res => res.json()); | |||
| } | |||
| export function addVectorset(vectorset) { | |||
| let newVectorset = Setting.deepCopy(vectorset); | |||
| return fetch(`${Setting.ServerUrl}/api/add-vectorset`, { | |||
| method: 'POST', | |||
| credentials: 'include', | |||
| body: JSON.stringify(newVectorset), | |||
| }).then(res => res.json()); | |||
| } | |||
| export function deleteVectorset(vectorset) { | |||
| let newVectorset = Setting.deepCopy(vectorset); | |||
| return fetch(`${Setting.ServerUrl}/api/delete-vectorset`, { | |||
| method: 'POST', | |||
| credentials: 'include', | |||
| body: JSON.stringify(newVectorset), | |||
| }).then(res => res.json()); | |||
| } | |||
| @@ -23,6 +23,14 @@ | |||
| "Loading...": "Loading...", | |||
| "Name": "Name", | |||
| "Preview": "Preview", | |||
| "Save": "Save" | |||
| "Save": "Save", | |||
| "URL": "URL", | |||
| "Vectorsets": "Vectorsets" | |||
| }, | |||
| "vectorset": { | |||
| "Count": "Count", | |||
| "Dimension": "Dimension", | |||
| "Edit Vectorset": "Edit Vectorset", | |||
| "Vectors": "Vectors" | |||
| } | |||
| } | |||
| @@ -23,6 +23,14 @@ | |||
| "Loading...": "加载中...", | |||
| "Name": "名称", | |||
| "Preview": "预览", | |||
| "Save": "保存" | |||
| "Save": "保存", | |||
| "URL": "URL", | |||
| "Vectorsets": "向量集" | |||
| }, | |||
| "vectorset": { | |||
| "Count": "个数", | |||
| "Dimension": "维度", | |||
| "Edit Vectorset": "编辑向量集", | |||
| "Vectors": "向量" | |||
| } | |||
| } | |||