Skip to content

Commit

Permalink
feat release: admin model market feature
Browse files Browse the repository at this point in the history
  • Loading branch information
zmh-program committed Jan 9, 2024
1 parent b3d4068 commit 6f6d818
Show file tree
Hide file tree
Showing 22 changed files with 293 additions and 579 deletions.
24 changes: 24 additions & 0 deletions admin/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ type UpdateRootPasswordForm struct {
Password string `json:"password"`
}

func UpdateMarketAPI(c *gin.Context) {
var form MarketModelList
if err := c.ShouldBindJSON(&form); err != nil {
c.JSON(http.StatusOK, gin.H{
"status": false,
"error": err.Error(),
})
return
}

err := MarketInstance.SetModels(form)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"status": false,
"error": err.Error(),
})
return
}

c.JSON(http.StatusOK, gin.H{
"status": true,
})
}

func InfoAPI(c *gin.Context) {
db := utils.GetDBFromContext(c)
cache := utils.GetCacheFromContext(c)
Expand Down
7 changes: 7 additions & 0 deletions admin/instance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package admin

var MarketInstance *Market

func InitInstance() {
MarketInstance = NewMarket()
}
57 changes: 57 additions & 0 deletions admin/market.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package admin

import (
"fmt"
"github.com/spf13/viper"
)

type ModelTag []string
type MarketModel struct {
Id string `json:"id" mapstructure:"id" required:"true"`
Name string `json:"name" mapstructure:"name" required:"true"`
Description string `json:"description" mapstructure:"description"`
Default bool `json:"default" mapstructure:"default"`
HighContext bool `json:"high_context" mapstructure:"high_context"`
Avatar string `json:"avatar" mapstructure:"avatar"`
Tag ModelTag `json:"tag" mapstructure:"tag"`
}
type MarketModelList []MarketModel

type Market struct {
Models MarketModelList `json:"models" mapstructure:"models"`
}

func NewMarket() *Market {
var models MarketModelList
if err := viper.UnmarshalKey("market", &models); err != nil {
fmt.Println(fmt.Sprintf("[market] read config error: %s, use default config", err.Error()))
models = MarketModelList{}
}

return &Market{
Models: models,
}
}

func (m *Market) GetModels() MarketModelList {
return m.Models
}

func (m *Market) GetModel(id string) *MarketModel {
for _, model := range m.Models {
if model.Id == id {
return &model
}
}
return nil
}

func (m *Market) SaveConfig() error {
viper.Set("market", m.Models)
return viper.WriteConfig()
}

func (m *Market) SetModels(models MarketModelList) error {
m.Models = models
return m.SaveConfig()
}
2 changes: 2 additions & 0 deletions admin/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ func Register(app *gin.RouterGroup) {
app.POST("/admin/user/quota", UserQuotaAPI)
app.POST("/admin/user/subscription", UserSubscriptionAPI)
app.POST("/admin/user/root", UpdateRootPasswordAPI)

app.POST("/admin/market/update", UpdateMarketAPI)
}
33 changes: 33 additions & 0 deletions app/src/api/v1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import axios from "axios";
import { Model } from "@/api/types.ts";
import { ChargeProps } from "@/admin/charge.ts";

export async function getApiModels(): Promise<string[]> {
try {
const res = await axios.get("/v1/models");
return res.data as string[];
} catch (e) {
console.warn(e);
return [];
}
}

export async function getApiMarket(): Promise<Model[]> {
try {
const res = await axios.get("/v1/market");
return res.data as Model[];
} catch (e) {
console.warn(e);
return [];
}
}

export async function getApiCharge(): Promise<ChargeProps[]> {
try {
const res = await axios.get("/v1/charge");
return res.data as ChargeProps[];
} catch (e) {
console.warn(e);
return [];
}
}
21 changes: 11 additions & 10 deletions app/src/assets/admin/dashboard.less
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

width: 100%;
height: max-content;
padding: 1rem 2rem;
padding: 1rem 2rem 0;

@media (max-width: 940px) {
flex-direction: column;
Expand Down Expand Up @@ -102,9 +102,18 @@
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 1rem 1.5rem;
padding: 0 1.5rem 1rem;
width: 100%;

@media (max-width: 940px) {
flex-direction: column;
padding: 1rem;

.chart-box {
width: calc(100% - 1rem) !important;
}
}

.chart-box {
width: calc(50% - 1rem);
height: max-content;
Expand All @@ -116,13 +125,5 @@
background: hsl(var(--background));
box-shadow: 0.5rem 0.5rem 1rem 0 var(--shadow);
user-select: none;

@media (max-width: 680px) {
width: 100%;
}
}

@media (max-width: 680px) {
padding: 1rem;
}
}
5 changes: 5 additions & 0 deletions app/src/assets/admin/market.less
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
height: max-content;
align-items: center;
background: hsl(var(--card));
transition: 0.25s;

&.error {
border-color: hsl(var(--error));
}

.market-tags {
display: flex;
Expand Down
29 changes: 5 additions & 24 deletions app/src/assets/admin/menu.less
Original file line number Diff line number Diff line change
Expand Up @@ -28,43 +28,21 @@
height: max-content;
padding: 0.75rem 1rem;
align-items: center;
margin: 0 0.75rem;
margin: 0.15rem 0.75rem;
user-select: none;
cursor: pointer;
transition: 0.2s ease-in-out;
border-radius: var(--radius);
font-size: 16px;
color: hsl(var(--text-secondary));

&:before {
content: '';
display: inline-block;
width: 4px;
height: 2rem;
background: hsl(var(--text));
border-radius: var(--radius);
margin-right: 0;
opacity: 0;
transition: 0.25s;
transition-property: opacity, margin-right;
}

&:hover {
background: hsl(var(--card-hover));

&:before {
opacity: .05;
margin-right: 0.75rem;
}
}

&.active {
color: hsl(var(--text));

&:before {
opacity: 1;
margin-right: 0.75rem;
}
background: hsl(var(--card-hover));
}

& > * {
Expand All @@ -78,7 +56,10 @@
.menu-item-icon {
width: 1.5rem;
height: 1.5rem;
scale: 0.95;
margin-right: 0.5rem;
margin-left: 0.5rem;
transform: translateY(1px);
}
}

Expand Down
1 change: 1 addition & 0 deletions app/src/assets/globals.less
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@

--gold: 45 100% 50%;
--link: 210 100% 63%;
--error: 20 80% 50%;
}

.dark {
Expand Down
16 changes: 4 additions & 12 deletions app/src/components/admin/MenuBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { closeMenu, selectMenu } from "@/store/menu.ts";
import React, { useMemo } from "react";
import {
BookCopy,
CandlestickChart,
CloudCog,
Gauge,
GitFork,
LayoutDashboard,
Radio,
Settings,
Users,
Expand Down Expand Up @@ -49,11 +49,7 @@ function MenuBar() {
const open = useSelector(selectMenu);
return (
<div className={`admin-menu ${open ? "open" : ""}`}>
<MenuItem
title={t("admin.dashboard")}
icon={<LayoutDashboard />}
path={"/"}
/>
<MenuItem title={t("admin.dashboard")} icon={<Gauge />} path={"/"} />
<MenuItem title={t("admin.user")} icon={<Users />} path={"/users"} />
<MenuItem
title={t("admin.market.title")}
Expand All @@ -70,11 +66,7 @@ function MenuBar() {
icon={<GitFork />}
path={"/channel"}
/>
<MenuItem
title={t("admin.prize")}
icon={<CandlestickChart />}
path={"/charge"}
/>
<MenuItem title={t("admin.prize")} icon={<CloudCog />} path={"/charge"} />
<MenuItem
title={t("admin.settings")}
icon={<Settings />}
Expand Down
34 changes: 30 additions & 4 deletions app/src/components/app/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,40 @@ import { ThemeProvider } from "@/components/ThemeProvider.tsx";
import DialogManager from "@/dialogs";
import Broadcast from "@/components/Broadcast.tsx";
import { useEffectAsync } from "@/utils/hook.ts";
import { allModels } from "@/conf.ts";
import axios from "axios";
import { allModels, supportModels } from "@/conf.ts";
import { channelModels } from "@/admin/channel.ts";
import { getApiCharge, getApiMarket, getApiModels } from "@/api/v1.ts";
import { loadPreferenceModels } from "@/utils/storage.ts";
import { resetJsArray } from "@/utils/base.ts";
import { useDispatch } from "react-redux";
import { initChatModels } from "@/store/chat.ts";
import { Model } from "@/api/types.ts";
import { ChargeProps, nonBilling } from "@/admin/charge.ts";

function AppProvider() {
const dispatch = useDispatch();

useEffectAsync(async () => {
const res = await axios.get("/v1/models");
res.data.forEach((model: string) => {
const market = await getApiMarket();
const charge = await getApiCharge();

market.forEach((item: Model) => {
const obj = charge.find((i: ChargeProps) => i.models.includes(item.id));
if (!obj) return;

item.free = obj.type === nonBilling;
item.auth = item.free && !obj.anonymous;
});

resetJsArray(supportModels, loadPreferenceModels(market));
resetJsArray(
allModels,
supportModels.map((model) => model.id),
);
initChatModels(dispatch);

const models = await getApiModels();
models.forEach((model: string) => {
if (!allModels.includes(model)) allModels.push(model);
if (!channelModels.includes(model)) channelModels.push(model);
});
Expand Down
1 change: 1 addition & 0 deletions app/src/components/ui/tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const TooltipContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
"max-w-[100vw]",
className,
)}
{...props}
Expand Down
Loading

0 comments on commit 6f6d818

Please sign in to comment.