Compare commits

..

35 Commits

Author SHA1 Message Date
Dot.L 901bef1463 Merge pull request #189 from APIParkLab/feature/openapi
update workflows actions/download-artifact to v4
2025-02-08 16:15:32 +08:00
Liujian 8d44d796b4 update workflows actions/download-artifact to v4 2025-02-08 16:14:01 +08:00
Dot.L 5a10ad478e Merge pull request #188 from APIParkLab/feature/openapi
update workflows actions/upload-artifact to v4
2025-02-08 15:59:53 +08:00
Liujian fd6680d615 update workflows actions/upload-artifact to v4 2025-02-08 15:57:36 +08:00
Dot.L e03cdfc42b Merge pull request #187 from APIParkLab/feature/openapi
Feature/openapi
2025-02-08 15:02:06 +08:00
Liujian 945d53fcfd Merge remote-tracking branch 'github-pro/main' into feature/openapi 2025-02-08 15:01:27 +08:00
Liujian ac7045b724 Fix: AI provider's default key synchronization to Apinto failed issue 2025-02-08 14:58:36 +08:00
Liujian c907bdc4a5 Merge remote-tracking branch 'origin/main' into feature/openapi 2025-01-23 16:54:58 +08:00
ningyv 733ed9ac2f Merge pull request #183 from APIParkLab/feature/1.4
chroe: optimize AI model node graphics
2025-01-23 14:01:10 +08:00
ningyv 1d8e579a10 Merge remote-tracking branch 'origin/main' into feature/1.4 2025-01-23 13:57:01 +08:00
lichunxian 567cac9c95 Merge branch 'feature/1.4' into 'main'
chroe: optimize AI model node graphics

See merge request apipark/APIPark!161
2025-01-21 11:52:02 +08:00
ningyv 095c09c8c0 chroe: optimize AI model node graphics 2025-01-21 11:50:58 +08:00
刘健 e9c949822d Merge branch 'feature/openapi' into 'main'
Feature/openapi

See merge request apipark/APIPark!160
2025-01-20 17:36:53 +08:00
Dot.L 3482d5416c Merge pull request #181 from APIParkLab/feature/openapi
fix:ai init bug
2025-01-20 14:08:37 +08:00
Liujian d8cb4a0c94 fix:ai init bug 2025-01-20 14:03:03 +08:00
Dot.L 59acfa7a47 Merge pull request #180 from APIParkLab/feature/openapi
Feature/openapi
2025-01-20 13:55:59 +08:00
Liujian 2eb2e690d1 update ai bug 2025-01-20 13:54:58 +08:00
刘健 f7801261c3 Merge branch 'feature/openapi' into 'main'
fix: Nsq returns no error directly after parsing JSON exceptionNsq returns no...

See merge request apipark/APIPark!159
2025-01-17 16:03:51 +08:00
Liujian 7e7be7f040 add openapi 2025-01-17 16:03:09 +08:00
刘健 b0c37918b5 Merge branch 'feature/merge' into 'main'
fix: login page redirect multiple times (#166)

See merge request apipark/APIPark!158
2025-01-16 14:57:39 +08:00
刘健 d5af1c8da3 Merge branch 'feature/ai-balance' into 'main'
Feature/1.4 (#154)

See merge request apipark/APIPark!157
2025-01-15 16:04:24 +08:00
秦圆圆 7c827804f4 Merge branch 'feature/1.4' into 'main'
fix: In the supplier load chart, the mouse should not show a hand shape except...

See merge request apipark/APIPark!156
2025-01-07 18:41:58 +08:00
scarqin b0dacbda0d fix: When the current supplier is abnormal, there should be a line on the model pointing to the next model, which means that the APIs on this link are associated with the next valid supplier. 2025-01-07 18:40:43 +08:00
scarqin d5abde2593 fix: The language option is wrong. The current language is Chinese, but the option is displayed as English. 2025-01-07 18:14:25 +08:00
scarqin bc3290de3b fix: jump link error 2025-01-07 17:56:16 +08:00
scarqin 7f438bf776 fix: When the current supplier is abnormal, there should be a line on the model pointing to the next model, which means that the APIs on this link are associated with the next valid supplier. 2025-01-07 17:54:53 +08:00
scarqin 13cfe24b2f fix: error line 2025-01-07 17:21:21 +08:00
刘健 f5cfd77550 Merge branch 'feature/ai-balance' into 'main'
fix: ai provider status error

See merge request apipark/APIPark!155
2025-01-07 16:50:27 +08:00
刘健 4a8f5152b3 Merge branch 'feature/ai-balance' into 'main'
AI API token quantity docking completed

See merge request apipark/APIPark!154
2025-01-07 12:49:51 +08:00
秦圆圆 83ac747cb1 Merge branch 'feature/1.4' into 'main'
fix: After the release log configuration is successful, there is no success...

See merge request apipark/APIPark!153
2025-01-07 11:33:54 +08:00
刘健 d5eedd1dd2 Merge branch 'feature/ai-balance' into 'main'
fix: ai key config error

See merge request apipark/APIPark!152
2025-01-07 09:23:34 +08:00
秦圆圆 86758383c4 Merge branch 'feature/1.4' into 'main'
Feature/1.4

See merge request apipark/APIPark!151
2025-01-06 19:45:37 +08:00
刘健 6ce3e0bfac Merge branch 'feature/ai-balance' into 'main'
update ai key status to gateway

See merge request apipark/APIPark!150
2025-01-06 10:57:54 +08:00
刘健 e4eadf863e Merge branch 'feature/ai-balance' into 'main'
fix: ai key sort

See merge request apipark/APIPark!149
2025-01-06 10:26:39 +08:00
刘健 ca328e784c Merge branch 'feature/ai-balance' into 'main'
Feature/ai balance

See merge request apipark/APIPark!148
2025-01-06 10:02:19 +08:00
13 changed files with 182 additions and 62 deletions
+3 -3
View File
@@ -25,7 +25,7 @@ jobs:
echo "Build frontend..."
cd ./frontend && pnpm run build
- name: upload frontend release
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: frontend-package
path: frontend/dist
@@ -41,7 +41,7 @@ jobs:
- name: Checkout #Checkout代码
uses: actions/checkout@v3
- name: download frontend release
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: frontend-package
path: frontend/dist
@@ -71,7 +71,7 @@ jobs:
- uses: actions/checkout@v3
- name: download frontend release
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: frontend-package
path: frontend/dist
@@ -27,6 +27,7 @@ export const KeyStatusNode: React.FC<{ data: KeyStatusNodeData }> = ({ data }) =
<div
className="flex gap-1 w-full"
style={{
minWidth: keys.length > 5 ? '118px' : 'auto',
maxWidth: `calc(${MAX_KEYS} * ${KEY_SIZE} + (${MAX_KEYS} - 1) * ${KEY_GAP})`,
minHeight: KEY_SIZE
}}
@@ -29,46 +29,48 @@ export const ModelCardNode: React.FC<{ data: ModelCardNodeData }> = ({ data }) =
const statusConfig = getStatusIcon(status)
return (
<div
className="node-card bg-white rounded-lg shadow-sm p-4 min-w-[280px] group"
style={{ border: '1px solid var(--border-color)' }}
>
<Handle type="target" position={Position.Left} />
<Handle type="source" position={Position.Right} />
<div>
<div className="flex justify-between items-center">
<div className="flex gap-2 items-center">
<div className="flex flex-1 overflow-hidden items-center gap-[4px]">
<span
className="flex items-center h-[22px] ai-setting-svg-container"
dangerouslySetInnerHTML={{ __html: logo }}
></span>
<>
<div
className="node-card bg-white rounded-lg shadow-sm p-4 min-w-[280px] group"
style={{ border: '1px solid var(--border-color)' }}
>
<Handle type="target" position={Position.Left} />
<Handle type="source" position={Position.Right} />
<div>
<div className="flex justify-between items-center">
<div className="flex gap-2 items-center">
<div className="flex flex-1 overflow-hidden items-center gap-[4px]">
<span
className="flex items-center h-[22px] ai-setting-svg-container"
dangerouslySetInnerHTML={{ __html: logo }}
></span>
</div>
<span className="text-base text-gray-900 max-w-[180px] truncate">{name}</span>
<Icon icon={statusConfig?.icon} className={`text-xl ${statusConfig?.color}`} />
</div>
<span className="text-base text-gray-900 max-w-[180px] truncate">{name}</span>
<Icon icon={statusConfig?.icon} className={`text-xl ${statusConfig?.color}`} />
</div>
{/* Action buttons */}
<div className="flex gap-2 transition-opacity duration-200">
<Icon
icon="mdi:cog"
className="text-xl text-gray-400 cursor-pointer hover:text-[--primary-color]"
onClick={() => {
openConfigModal({ id: data.id, defaultLlm: defaultLlm } as AiSettingListItem)
}}
/>
{/* Action buttons */}
<div className="flex gap-2 transition-opacity duration-200">
<Icon
icon="mdi:cog"
className="text-xl text-gray-400 cursor-pointer hover:text-[--primary-color]"
onClick={() => {
openConfigModal({ id: data.id, defaultLlm: defaultLlm } as AiSettingListItem)
}}
/>
</div>
</div>
<div className="mt-2 text-sm text-gray-500">
{$t('默认:')}
{defaultLlm}
</div>
</div>
<div className="mt-2 text-sm text-gray-500">
{$t('默认:')}
{defaultLlm}
</div>
{status !== 'enabled' && alternativeModel && (
<div className="mt-1 text-sm text-gray-500">
{$t('关联 API 已转用')} {alternativeModel.name}/{alternativeModel.defaultLlm}
</div>
)}
</div>
</div>
{status !== 'enabled' && alternativeModel && (
<div className="ml-4 mt-1 text-sm text-gray-500">
{$t('关联 API 已转用')} {alternativeModel.name}/{alternativeModel.defaultLlm}
</div>
)}
</>
)
}
@@ -18,11 +18,15 @@
.react-flow__node {
padding: 0;
border-radius: 8px;
min-width: 150px;
width: auto;
max-width: 100%;
}
.react-flow__node-modelCard,
.react-flow__node-serviceCard {
min-width: 150px;
}
/* Custom Node Styles */
.custom-node {
background: white;
+1
View File
@@ -5,6 +5,7 @@ import (
_ "github.com/APIParkLab/APIPark/frontend"
_ "github.com/APIParkLab/APIPark/gateway/apinto"
_ "github.com/APIParkLab/APIPark/plugins/core"
_ "github.com/APIParkLab/APIPark/plugins/openapi"
_ "github.com/APIParkLab/APIPark/plugins/permit"
_ "github.com/APIParkLab/APIPark/plugins/publish_flow"
_ "github.com/APIParkLab/APIPark/resources/locale"
+13 -18
View File
@@ -533,16 +533,17 @@ func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string,
DefaultLLM: &input.DefaultLLM,
Config: &input.Config,
Priority: input.Priority,
Status: &status,
}
_, err = i.aiKeyService.DefaultKey(ctx, id)
_, err = i.aiKeyService.DefaultKey(txCtx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
err = i.aiKeyService.Create(ctx, &ai_key.Create{
err = i.aiKeyService.Create(txCtx, &ai_key.Create{
ID: id,
Name: info.Name,
Config: info.Config,
Config: input.Config,
Provider: id,
Status: 1,
ExpireTime: 0,
@@ -550,27 +551,21 @@ func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string,
Priority: 1,
})
} else {
err = i.aiKeyService.Save(ctx, id, &ai_key.Edit{
Config: &info.Config,
err = i.aiKeyService.Save(txCtx, id, &ai_key.Edit{
Config: &input.Config,
Status: &status,
})
}
if err != nil {
return err
}
if input.Enable != nil {
status = 0
if *input.Enable {
status = 1
}
pInfo.Status = &status
}
err = i.providerService.Save(ctx, id, pInfo)
err = i.providerService.Save(txCtx, id, pInfo)
if err != nil {
return err
}
if *pInfo.Status == 0 {
return i.syncGateway(ctx, cluster.DefaultClusterID, []*gateway.DynamicRelease{
return i.syncGateway(txCtx, cluster.DefaultClusterID, []*gateway.DynamicRelease{
{
BasicItem: &gateway.BasicItem{
ID: id,
@@ -579,8 +574,8 @@ func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string,
},
}, false)
}
// 获取当前供应商所有Key信息
defaultKey, err := i.aiKeyService.DefaultKey(ctx, id)
// 获取当前供应商默认Key信息
defaultKey, err := i.aiKeyService.DefaultKey(txCtx, id)
if err != nil {
return err
}
@@ -590,7 +585,7 @@ func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string,
cfg["model_config"] = model.DefaultConfig()
cfg["priority"] = info.Priority
cfg["base"] = fmt.Sprintf("%s://%s", p.URI().Scheme(), p.URI().Host())
return i.syncGateway(ctx, cluster.DefaultClusterID, []*gateway.DynamicRelease{
return i.syncGateway(txCtx, cluster.DefaultClusterID, []*gateway.DynamicRelease{
{
BasicItem: &gateway.BasicItem{
ID: id,
+4 -2
View File
@@ -100,7 +100,8 @@ func (i *imlAuthorizationModule) getApplications(ctx context.Context, appIds []s
Config: authCfg,
HideCredential: a.HideCredential,
Label: map[string]string{
"authorization": a.UUID,
"authorization": a.UUID,
"authorization_name": a.Name,
},
}
}),
@@ -157,7 +158,8 @@ func (i *imlAuthorizationModule) online(ctx context.Context, s *service.Service)
Config: authCfg,
HideCredential: a.HideCredential,
Label: map[string]string{
"authorization": a.UUID,
"authorization": a.UUID,
"authorization_name": a.Name,
},
}
}),
+18
View File
@@ -0,0 +1,18 @@
package openapi
import (
"net/http"
"github.com/eolinker/go-common/pm3"
)
func (p *plugin) appAuthorizationApis() []pm3.Api {
return []pm3.Api{
pm3.CreateApiWidthDoc(http.MethodPost, "/openapi/v1/app/authorization", []string{"context", "query:app", "body"}, []string{"authorization"}, p.authorizationController.AddAuthorization),
pm3.CreateApiWidthDoc(http.MethodPut, "/openapi/v1/app/authorization", []string{"context", "query:app", "query:authorization", "body"}, []string{"authorization"}, p.authorizationController.EditAuthorization),
pm3.CreateApiWidthDoc(http.MethodDelete, "/openapi/v1/app/authorization", []string{"context", "query:app", "query:authorization"}, nil, p.authorizationController.DeleteAuthorization),
pm3.CreateApiWidthDoc(http.MethodGet, "/openapi/v1/app/authorization", []string{"context", "query:app", "query:authorization"}, []string{"authorization"}, p.authorizationController.Info),
pm3.CreateApiWidthDoc(http.MethodGet, "/openapi/v1/app/authorizations", []string{"context", "query:app"}, []string{"authorizations"}, p.authorizationController.Authorizations),
pm3.CreateApiWidthDoc(http.MethodGet, "/openapi/v1/app/authorization/details", []string{"context", "query:app", "query:authorization"}, []string{"details"}, p.authorizationController.Detail),
}
}
+45
View File
@@ -0,0 +1,45 @@
package openapi
import (
"strings"
"github.com/eolinker/eosc/env"
"github.com/gin-gonic/gin"
)
var (
defaultAPIKey = "37eb0ebf"
openCheck = newOpenapiCheck()
)
type openapiCheck struct {
apikey string
}
func newOpenapiCheck() *openapiCheck {
apikey, has := env.GetEnv("API_KEY")
if !has {
apikey = defaultAPIKey
}
return &openapiCheck{apikey: apikey}
}
func (o *openapiCheck) Check(method string, path string) (bool, []gin.HandlerFunc) {
if strings.HasPrefix(path, "/openapi/") {
return true, []gin.HandlerFunc{o.Handler}
}
return false, nil
}
func (o *openapiCheck) Sort() int {
return -1
}
func (o *openapiCheck) Handler(ginCtx *gin.Context) {
authorization := ginCtx.GetHeader("Authorization")
if authorization == "" {
ginCtx.AbortWithStatusJSON(403, gin.H{"code": -8, "msg": "invalid token", "success": "fail"})
return
}
}
+19
View File
@@ -0,0 +1,19 @@
package openapi
import (
"github.com/eolinker/go-common/autowire"
"github.com/eolinker/go-common/pm3"
)
func init() {
pm3.Register("openapi", new(Driver))
}
type Driver struct {
}
func (d *Driver) Create() (pm3.IPlugin, error) {
p := new(plugin)
autowire.Autowired(p)
return p, nil
}
+33
View File
@@ -0,0 +1,33 @@
package openapi
import (
application_authorization "github.com/APIParkLab/APIPark/controller/application-authorization"
"github.com/eolinker/go-common/pm3"
)
var (
_ pm3.IPlugin = (*plugin)(nil)
_ pm3.IPluginMiddleware = (*plugin)(nil)
)
type plugin struct {
apis []pm3.Api
authorizationController application_authorization.IAuthorizationController `autowired:""`
}
func (p *plugin) Middlewares() []pm3.IMiddleware {
return []pm3.IMiddleware{
openCheck,
}
}
func (p *plugin) APis() []pm3.Api {
return p.apis
}
func (p *plugin) Name() string {
return "openapi"
}
func (p *plugin) OnComplete() {
p.apis = p.appAuthorizationApis()
}
+1 -1
View File
@@ -55,7 +55,7 @@ type Doc struct {
Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"`
UUID string `gorm:"type:varchar(36);not null;column:uuid;uniqueIndex:uuid;comment:UUID;"`
Service string `gorm:"size:36;not null;column:service;comment:服务;index:service"`
Content string `gorm:"type:text;null;column:content;comment:文档内容"`
Content string `gorm:"type:longtext;null;column:content;comment:文档内容"`
Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"`
UpdateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:update_at;comment:更新时间"`
APICount int64 `gorm:"type:int(11);not null;column:api_count;comment:接口数量"`
+1 -1
View File
@@ -7,7 +7,7 @@ type Commit[H any] struct {
UUID string `gorm:"size:36;not null;column:uuid;comment:uuid;uniqueIndex:uuid;"`
Target string `gorm:"column:target;type:varchar(36);NOT NULL;comment:目标id;index:target;"`
Key string `gorm:"size:50;not null;column:key;comment:类型;index:key;"`
Data *H `gorm:"type:text;not null;column:data;comment:数据;charset=utf8mb4;serializer:json"`
Data *H `gorm:"type:longtext;not null;column:data;comment:数据;charset=utf8mb4;serializer:json"`
CreateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:create_at;comment:创建时间"`
Operator string `gorm:"size:36;not null;column:operator;comment:操作人;index:operator;"`
}