mirror of
https://github.com/coaidev/coai.git
synced 2025-06-05 13:20:15 +09:00
update subscription usage form
This commit is contained in:
parent
65eb601d84
commit
74be9cb54d
@ -6,23 +6,51 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 18px 4px !important;
|
||||
margin-bottom: 32px !important;
|
||||
margin-bottom: 48px !important;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.date {
|
||||
.sub-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
color: hsl(45, 100%, 50%);
|
||||
flex-direction: column;
|
||||
padding: 8px 16px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid hsl(var(--border));
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
transform: translateY(1px);
|
||||
.sub-column {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
color: hsl(45, 100%, 50%);
|
||||
margin-bottom: 4px;
|
||||
width: 100%;
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.sub-value {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
|
||||
p {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
import { Model } from "./conversation/types.ts";
|
||||
|
||||
export const version = "3.5.12";
|
||||
export const version = "3.5.13";
|
||||
export const dev: boolean = window.location.hostname === "localhost";
|
||||
export const deploy: boolean = true;
|
||||
export let rest_api: string = "http://localhost:8094";
|
||||
|
@ -15,6 +15,10 @@ type SubscriptionResponse = {
|
||||
status: boolean;
|
||||
is_subscribed: boolean;
|
||||
expired: number;
|
||||
usage: {
|
||||
gpt4: number;
|
||||
dalle: number;
|
||||
}
|
||||
};
|
||||
|
||||
type BuySubscriptionResponse = {
|
||||
@ -58,16 +62,12 @@ export async function getSubscription(): Promise<SubscriptionResponse> {
|
||||
try {
|
||||
const resp = await axios.get(`/subscription`);
|
||||
if (resp.data.status === false) {
|
||||
return { status: false, is_subscribed: false, expired: 0 };
|
||||
return { status: false, is_subscribed: false, expired: 0, usage: { gpt4: 0, dalle: 0 } };
|
||||
}
|
||||
return {
|
||||
status: resp.data.status,
|
||||
is_subscribed: resp.data.is_subscribed,
|
||||
expired: resp.data.expired,
|
||||
};
|
||||
return resp.data as SubscriptionResponse;
|
||||
} catch (e) {
|
||||
console.debug(e);
|
||||
return { status: false, is_subscribed: false, expired: 0 };
|
||||
return { status: false, is_subscribed: false, expired: 0 , usage: { gpt4: 0, dalle: 0 } };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
isSubscribedSelector,
|
||||
refreshSubscription,
|
||||
refreshSubscriptionTask,
|
||||
setDialog,
|
||||
setDialog, usageSelector,
|
||||
} from "../store/subscription.ts";
|
||||
import {
|
||||
Dialog,
|
||||
@ -158,6 +158,7 @@ function Subscription() {
|
||||
const open = useSelector(dialogSelector);
|
||||
const subscription = useSelector(isSubscribedSelector);
|
||||
const expired = useSelector(expiredSelector);
|
||||
const usage = useSelector(usageSelector);
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
refreshSubscriptionTask(dispatch);
|
||||
@ -174,9 +175,27 @@ function Subscription() {
|
||||
<DialogDescription asChild>
|
||||
<div className={`sub-wrapper`}>
|
||||
{subscription && (
|
||||
<div className={`date`}>
|
||||
<Calendar className={`h-4 w-4 mr-1`} />
|
||||
{t("sub.expired", { expired })}
|
||||
<div className={`sub-row`}>
|
||||
<div className={`sub-column`}>
|
||||
<Calendar className={`h-4 w-4 mr-1`} />
|
||||
{t("sub.expired", { expired })}
|
||||
</div>
|
||||
<div className={`sub-column`}>
|
||||
<Compass className={`h-4 w-4 mr-1`} />
|
||||
GPT-4
|
||||
<div className={`grow`} />
|
||||
<div className={`sub-value`}>
|
||||
<p>{ usage.gpt4 }</p> / <p> 50 </p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`sub-column`}>
|
||||
<ImagePlus className={`h-4 w-4 mr-1`} />
|
||||
DALL-E
|
||||
<div className={`grow`} />
|
||||
<div className={`sub-value`}>
|
||||
<p>{ usage.dalle }</p> / <p> 2000 </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={`plan-wrapper`}>
|
||||
|
@ -8,6 +8,10 @@ export const subscriptionSlice = createSlice({
|
||||
dialog: false,
|
||||
is_subscribed: false,
|
||||
expired: 0,
|
||||
usage: {
|
||||
gpt4: 0,
|
||||
dalle: 0,
|
||||
}
|
||||
},
|
||||
reducers: {
|
||||
toggleDialog: (state) => {
|
||||
@ -25,6 +29,7 @@ export const subscriptionSlice = createSlice({
|
||||
updateSubscription: (state, action) => {
|
||||
state.is_subscribed = action.payload.is_subscribed;
|
||||
state.expired = action.payload.expired;
|
||||
state.usage = action.payload.usage;
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -44,6 +49,8 @@ export const isSubscribedSelector = (state: any): boolean =>
|
||||
state.subscription.is_subscribed;
|
||||
export const expiredSelector = (state: any): number =>
|
||||
state.subscription.expired;
|
||||
export const usageSelector = (state: any): any =>
|
||||
state.subscription.usage;
|
||||
|
||||
export const refreshSubscription = async (dispatch: AppDispatch) => {
|
||||
const current = new Date().getTime(); //@ts-ignore
|
||||
|
@ -62,10 +62,12 @@ func SubscriptionAPI(c *gin.Context) {
|
||||
}
|
||||
|
||||
db := utils.GetDBFromContext(c)
|
||||
cache := utils.GetCacheFromContext(c)
|
||||
c.JSON(200, gin.H{
|
||||
"status": true,
|
||||
"is_subscribed": user.IsSubscribe(db),
|
||||
"expired": user.GetSubscriptionExpiredDay(db),
|
||||
"usage": user.GetSubscriptionUsage(db, cache),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"chat/globals"
|
||||
"chat/utils"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CountSubscriptionPrize(month int) float32 {
|
||||
@ -33,13 +32,11 @@ func BuySubscription(db *sql.DB, user *User, month int) bool {
|
||||
}
|
||||
|
||||
func IncreaseSubscriptionUsage(cache *redis.Client, user *User) bool {
|
||||
today := time.Now().Format("2006-01-02")
|
||||
return utils.IncrWithLimit(cache, fmt.Sprintf(":subscription-usage:%s:%d", today, user.ID), 1, 50, 60*60*24) // 1 day
|
||||
return utils.IncrWithLimit(cache, globals.GetGPT4LimitFormat(user.ID), 1, 50, 60*60*24) // 1 day
|
||||
}
|
||||
|
||||
func DecreaseSubscriptionUsage(cache *redis.Client, user *User) bool {
|
||||
today := time.Now().Format("2006-01-02")
|
||||
return utils.DecrInt(cache, fmt.Sprintf(":subscription-usage:%s:%d", today, user.ID), 1)
|
||||
return utils.DecrInt(cache, globals.GetGPT4LimitFormat(user.ID), 1)
|
||||
}
|
||||
|
||||
func CanEnableSubscription(db *sql.DB, cache *redis.Client, user *User) bool {
|
||||
|
17
auth/user.go
17
auth/user.go
@ -1,12 +1,14 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"chat/globals"
|
||||
"chat/utils"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/spf13/viper"
|
||||
"math"
|
||||
"net/http"
|
||||
@ -162,6 +164,21 @@ func (u *User) GetSubscriptionExpiredDay(db *sql.DB) int {
|
||||
return int(math.Round(stamp.Hours() / 24))
|
||||
}
|
||||
|
||||
type Usage struct {
|
||||
GPT4 int64 `json:"gpt4"`
|
||||
Dalle int64 `json:"dalle"`
|
||||
}
|
||||
|
||||
func (u *User) GetSubscriptionUsage(db *sql.DB, cache *redis.Client) Usage {
|
||||
gpt4, _ := utils.GetInt(cache, globals.GetGPT4LimitFormat(u.GetID(db)))
|
||||
dalle, _ := utils.GetInt(cache, globals.GetImageLimitFormat(u.GetID(db)))
|
||||
|
||||
return Usage{
|
||||
GPT4: gpt4,
|
||||
Dalle: dalle,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) AddSubscription(db *sql.DB, month int) bool {
|
||||
current := u.GetSubscription(db)
|
||||
if current.Unix() < time.Now().Unix() {
|
||||
|
14
globals/quota.go
Normal file
14
globals/quota.go
Normal file
@ -0,0 +1,14 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetImageLimitFormat(id int64) string {
|
||||
return fmt.Sprintf(":imagelimit:%s:%d", time.Now().Format("2006-01-02"), id)
|
||||
}
|
||||
|
||||
func GetGPT4LimitFormat(id int64) string {
|
||||
return fmt.Sprintf(":subscription-usage:%s:%d", time.Now().Format("2006-01-02"), id)
|
||||
}
|
@ -3,18 +3,13 @@ package manager
|
||||
import (
|
||||
"chat/adapter/chatgpt"
|
||||
"chat/auth"
|
||||
"chat/globals"
|
||||
"chat/utils"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetImageLimitFormat(db *sql.DB, user *auth.User) string {
|
||||
return fmt.Sprintf(":imagelimit:%s:%d", time.Now().Format("2006-01-02"), user.GetID(db))
|
||||
}
|
||||
|
||||
func GenerateImage(c *gin.Context, user *auth.User, prompt string) (string, error) {
|
||||
// free plan: 5 images per day
|
||||
// pro plan: 50 images per day
|
||||
@ -22,7 +17,7 @@ func GenerateImage(c *gin.Context, user *auth.User, prompt string) (string, erro
|
||||
db := utils.GetDBFromContext(c)
|
||||
cache := utils.GetCacheFromContext(c)
|
||||
|
||||
key := GetImageLimitFormat(db, user)
|
||||
key := globals.GetImageLimitFormat(user.GetID(db))
|
||||
usage := auth.GetDalleUsageLimit(db, user)
|
||||
|
||||
prompt = strings.TrimSpace(prompt)
|
||||
|
Loading…
Reference in New Issue
Block a user