@@ -1,25 +1,48 @@ | |||||
[English](README.md) | |||||
<h1><img src="public/img/favicon.png" alt="logo" width="30" height="30"> OpenData - open data project management</h1> | |||||
[](https://drone.gitea.io/go-gitea/gitea) | |||||
[](https://discord.gg/Gitea) | |||||
[](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com") | |||||
[](https://codecov.io/gh/go-gitea/gitea) | |||||
[](https://godoc.org/code.gitea.io/gitea) | |||||
[](https://github.com/go-gitea/gitea/releases/latest) | |||||
[](https://www.codetriage.com/go-gitea/gitea) | |||||
[](https://opencollective.com/gitea) | |||||
<!--[English](README_EN.md)--> | |||||
<h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1> | |||||
[](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||||
[](https://opensource.org/licenses/MIT) | [](https://opensource.org/licenses/MIT) | ||||
[](https://crowdin.com/project/gitea) | |||||
## 目标 | |||||
OpenData 的首要目标是提供对开源数据的大存储支持和管理,旨在为国家开源项目的建设贡献力量。为软件行业中的开源项目的发展提供助力。 | |||||
## AiForge | |||||
启智AI开发协作平台是一个在线Web应用,旨在为人工智能算法、模型开发提供在线协同工作环境,它提供了<b>代码托管、数据集管理与共享、免费云端算力资源支持(GPU/NPU)、共享镜像</b>等功能。 | |||||
[启智AI开发协作平台](https://git.openi.org.cn) 是使用本项目构建的在线服务,您可以直接点击链接访问试用。 | |||||
本项目是基于[Gitea](https://github.com/go-gitea/gitea)发展而来的,我们对其进行了Fork并基于此扩展了人工智能开发中需要的功能,如数据集管理和模型训练等。对于和代码托管相关的功能,您可以参考[Gitea的文档](https://docs.gitea.io/zh-cn/)。 | |||||
### 系统总体架构 | |||||
下图展示了系统总体架构,本项目分为Web前端和服务后端,Web页面面向算法开发者、应用开发者、科研工作者、学生等用户群体,通过统一的Web页面入口,使用系统提供的系统服务。 | |||||
后端服务涵盖了AI模型开发流水线,包括代码协同开发、数据管理、模型调试、训练、推理和部署等(*目前尚未支持模型部署*)。在不同的开发阶段,我们还将提供丰富的开发工具供用户使用,如数据标注、数据筛选、模型转换、模型压缩、代码监测等。我们也欢迎社区提供更多丰富的工具接入,提高利用平台进行开发的效率。 | |||||
 | |||||
## 在线服务使用 | |||||
本项目的在线服务平台的详细使用帮助文档,可参阅本项目[百科](https://git.openi.org.cn/OpenI/aiforge/wiki)内容。 | |||||
- 如何创建账号 | |||||
- 如何创建组织及管理成员权限 | |||||
- 如何创建项目仓库 | |||||
- 如何使用数据集功能 | |||||
- 如何使用计算资源进行模型调试和训练 | |||||
- 使用小技巧 | |||||
- 常见问题(FAQ) | |||||
## 安装 | |||||
您也可以基于本项目代码,在本地环境安装部署服务。 | |||||
### 数据库准备 | |||||
[数据库准备说明](https://docs.gitea.io/zh-cn/database-prep/) | |||||
### 从源代码安装 | |||||
- node版本 >= v10.13.0 | |||||
- golang版本 >= 1.13.3 | |||||
[从源代码安装说明](https://docs.gitea.io/zh-cn/install-from-source/) | |||||
## 我们所提供的 | |||||
## 授权许可 | |||||
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://git.openi.org.cn/OpenI/aiforge/src/branch/develop/LICENSE) 文件中。 | |||||
- 项目管理 | |||||
- git代码管理 | |||||
- <strong>大数据集存储管理,最高单个数据集限制为1TB</strong> | |||||
- 初期为社区项目免费提供30PB的算力,后续根据使用情况逐步增加 | |||||
## 需要帮助? | |||||
如果您在使用或者开发过程中遇到问题,可以在以下渠道咨询: | |||||
- 点击[这里](https://git.openi.org.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**) | |||||
- 加入微信群实时交流,获得进一步的支持 | |||||
<img src="https://git.openi.org.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px /> |
@@ -0,0 +1,36 @@ | |||||
package models | |||||
import ( | |||||
"code.gitea.io/gitea/modules/log" | |||||
"xorm.io/xorm" | |||||
) | |||||
type CustomMigration struct { | |||||
Description string | |||||
Migrate func(*xorm.Engine) error | |||||
} | |||||
var customMigrations = []CustomMigration{ | |||||
{"Custom v1 Topic struct change to support chinese", syncTopicStruct}, | |||||
} | |||||
func MigrateCustom(x *xorm.Engine) { | |||||
for _, m := range customMigrations { | |||||
log.Info("Migration: %s", m.Description) | |||||
if err := m.Migrate(x); err != nil { | |||||
log.Error("Migration: %v", err) | |||||
} | |||||
} | |||||
} | |||||
func syncTopicStruct(x *xorm.Engine) error { | |||||
query := "ALTER TABLE topic ALTER COLUMN name TYPE varchar(105);" | |||||
_, err := x.Exec(query) | |||||
return err | |||||
} |
@@ -185,6 +185,8 @@ func SetEngine() (err error) { | |||||
x.SetMaxOpenConns(setting.Database.MaxOpenConns) | x.SetMaxOpenConns(setting.Database.MaxOpenConns) | ||||
x.SetMaxIdleConns(setting.Database.MaxIdleConns) | x.SetMaxIdleConns(setting.Database.MaxIdleConns) | ||||
x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) | x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) | ||||
x.Sync2(tables...) | |||||
MigrateCustom(x) | |||||
return nil | return nil | ||||
} | } | ||||
@@ -8,6 +8,7 @@ import ( | |||||
"fmt" | "fmt" | ||||
"regexp" | "regexp" | ||||
"strings" | "strings" | ||||
"unicode/utf8" | |||||
"code.gitea.io/gitea/modules/timeutil" | "code.gitea.io/gitea/modules/timeutil" | ||||
@@ -21,12 +22,12 @@ func init() { | |||||
) | ) | ||||
} | } | ||||
var topicPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`) | |||||
var topicPattern = regexp.MustCompile(`^[\x{4e00}-\x{9fa5}a-z0-9][\x{4e00}-\x{9fa5}a-z0-9-]*$`) | |||||
// Topic represents a topic of repositories | // Topic represents a topic of repositories | ||||
type Topic struct { | type Topic struct { | ||||
ID int64 | ID int64 | ||||
Name string `xorm:"UNIQUE VARCHAR(25)"` | |||||
Name string `xorm:"UNIQUE VARCHAR(105)"` | |||||
RepoCount int | RepoCount int | ||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | ||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | ||||
@@ -56,7 +57,7 @@ func (err ErrTopicNotExist) Error() string { | |||||
// ValidateTopic checks a topic by length and match pattern rules | // ValidateTopic checks a topic by length and match pattern rules | ||||
func ValidateTopic(topic string) bool { | func ValidateTopic(topic string) bool { | ||||
return len(topic) <= 35 && topicPattern.MatchString(topic) | |||||
return utf8.RuneCountInString(topic) <= 35 && topicPattern.MatchString(topic) | |||||
} | } | ||||
// SanitizeAndValidateTopics sanitizes and checks an array or topics | // SanitizeAndValidateTopics sanitizes and checks an array or topics | ||||
@@ -1815,7 +1815,7 @@ branch.included = Included | |||||
topic.manage_topics = Manage Topics | topic.manage_topics = Manage Topics | ||||
topic.done = Done | topic.done = Done | ||||
topic.count_prompt = You can not select more than 25 topics | topic.count_prompt = You can not select more than 25 topics | ||||
topic.format_prompt = Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long. | |||||
topic.format_prompt = Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long. | |||||
[org] | [org] | ||||
org_name_holder = Organization Name | org_name_holder = Organization Name | ||||
@@ -1817,7 +1817,7 @@ branch.included=已包含 | |||||
topic.manage_topics=管理主题 | topic.manage_topics=管理主题 | ||||
topic.done=保存 | topic.done=保存 | ||||
topic.count_prompt=您最多选择25个主题 | topic.count_prompt=您最多选择25个主题 | ||||
topic.format_prompt=主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符 | |||||
topic.format_prompt=主题必须以中文、字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符 | |||||
[org] | [org] | ||||
org_name_holder=组织名称 | org_name_holder=组织名称 | ||||
@@ -4113,11 +4113,7 @@ function initTopicbar() { | |||||
$.fn.form.settings.rules.validateTopic = function (_values, regExp) { | $.fn.form.settings.rules.validateTopic = function (_values, regExp) { | ||||
const topics = topicDropdown.children('a.ui.label'); | const topics = topicDropdown.children('a.ui.label'); | ||||
const status = | const status = | ||||
topics.length === 0 || | |||||
topics | |||||
.last() | |||||
.attr('data-value') | |||||
.match(regExp); | |||||
topics.length === 0 || (topics.last().attr('data-value').match(regExp) !== null && topics.last().attr('data-value').length <= 35); | |||||
if (!status) { | if (!status) { | ||||
topics | topics | ||||
.last() | .last() | ||||
@@ -4136,7 +4132,7 @@ function initTopicbar() { | |||||
rules: [ | rules: [ | ||||
{ | { | ||||
type: 'validateTopic', | type: 'validateTopic', | ||||
value: /^[a-z0-9][a-z0-9-]{0,35}$/, | |||||
value: /^[\u4e00-\u9fa5a-z0-9][\u4e00-\u9fa5a-z0-9-]{0,105}$/, | |||||
prompt: topicPrompts.formatPrompt | prompt: topicPrompts.formatPrompt | ||||
}, | }, | ||||
{ | { | ||||