mirror of
https://github.com/coaidev/coai.git
synced 2025-05-20 05:20:15 +09:00
fix: fix sharing message use message action issue
This commit is contained in:
parent
a5d2c8c1ff
commit
f7a135af0e
@ -41,6 +41,7 @@ type MessageProps = {
|
|||||||
index: number;
|
index: number;
|
||||||
message: Message;
|
message: Message;
|
||||||
end?: boolean;
|
end?: boolean;
|
||||||
|
username?: string;
|
||||||
onEvent?: (event: string, index?: number, message?: string) => void;
|
onEvent?: (event: string, index?: number, message?: string) => void;
|
||||||
ref?: Ref<HTMLElement>;
|
ref?: Ref<HTMLElement>;
|
||||||
sharing?: boolean;
|
sharing?: boolean;
|
||||||
@ -216,10 +217,11 @@ function MessageContent({
|
|||||||
index,
|
index,
|
||||||
onEvent,
|
onEvent,
|
||||||
selected,
|
selected,
|
||||||
|
username,
|
||||||
}: MessageProps) {
|
}: MessageProps) {
|
||||||
const isUser = message.role === "user";
|
const isUser = message.role === "user";
|
||||||
|
|
||||||
const username = useSelector(selectUsername);
|
const user = useSelector(selectUsername);
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [editedMessage, setEditedMessage] = useState<string | undefined>("");
|
const [editedMessage, setEditedMessage] = useState<string | undefined>("");
|
||||||
@ -239,7 +241,7 @@ function MessageContent({
|
|||||||
isUser ? (
|
isUser ? (
|
||||||
<Avatar
|
<Avatar
|
||||||
className={`message-avatar animate-fade-in`}
|
className={`message-avatar animate-fade-in`}
|
||||||
username={username}
|
username={username ?? user}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<img
|
<img
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import { EventCommitter } from "./struct.ts";
|
|
||||||
import { Message } from "@/api/types.tsx";
|
|
||||||
|
|
||||||
export type SharingEvent = {
|
|
||||||
refer: string;
|
|
||||||
data: Message[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sharingEvent = new EventCommitter<SharingEvent>({
|
|
||||||
name: "sharing",
|
|
||||||
destroyedAfterTrigger: true,
|
|
||||||
});
|
|
@ -19,7 +19,6 @@ import MessageSegment from "@/components/Message.tsx";
|
|||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import router from "@/router.tsx";
|
import router from "@/router.tsx";
|
||||||
import { useToast } from "@/components/ui/use-toast.ts";
|
import { useToast } from "@/components/ui/use-toast.ts";
|
||||||
import { sharingEvent } from "@/events/sharing.ts";
|
|
||||||
import { Message } from "@/api/types.tsx";
|
import { Message } from "@/api/types.tsx";
|
||||||
import Avatar from "@/components/Avatar.tsx";
|
import Avatar from "@/components/Avatar.tsx";
|
||||||
import { toJpeg } from "html-to-image";
|
import { toJpeg } from "html-to-image";
|
||||||
@ -28,18 +27,20 @@ import { extractMessage } from "@/utils/processor.ts";
|
|||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
import { useMobile } from "@/utils/device.ts";
|
import { useMobile } from "@/utils/device.ts";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area.tsx";
|
import { ScrollArea } from "@/components/ui/scroll-area.tsx";
|
||||||
|
import { useConversationActions } from "@/store/chat.ts";
|
||||||
|
|
||||||
type SharingFormProps = {
|
type SharingFormProps = {
|
||||||
refer?: string;
|
refer?: string;
|
||||||
data: ViewData | null;
|
data: ViewData | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function SharingForm({ refer, data }: SharingFormProps) {
|
function SharingForm({ data }: SharingFormProps) {
|
||||||
if (data === null) return null;
|
if (data === null) return null;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const mobile = useMobile();
|
const mobile = useMobile();
|
||||||
|
const { mask: setMask } = useConversationActions();
|
||||||
const [maximized, setMaximized] = useState(false);
|
const [maximized, setMaximized] = useState(false);
|
||||||
const container = useRef<HTMLDivElement>(null);
|
const container = useRef<HTMLDivElement>(null);
|
||||||
const date = new Date(data.time);
|
const date = new Date(data.time);
|
||||||
@ -111,7 +112,12 @@ function SharingForm({ refer, data }: SharingFormProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className={`shot-content`}>
|
<div className={`shot-content`}>
|
||||||
{data.messages.map((message, i) => (
|
{data.messages.map((message, i) => (
|
||||||
<MessageSegment message={message} key={i} index={i} />
|
<MessageSegment
|
||||||
|
message={message}
|
||||||
|
key={i}
|
||||||
|
index={i}
|
||||||
|
username={data.username}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -151,9 +157,11 @@ function SharingForm({ refer, data }: SharingFormProps) {
|
|||||||
<Button
|
<Button
|
||||||
variant={`outline`}
|
variant={`outline`}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
sharingEvent.emit({
|
const message: Message[] = data?.messages || [];
|
||||||
refer: refer as string,
|
setMask({
|
||||||
data: data?.messages as Message[],
|
avatar: "",
|
||||||
|
name: data.name,
|
||||||
|
context: message,
|
||||||
});
|
});
|
||||||
await router.navigate("/");
|
await router.navigate("/");
|
||||||
}}
|
}}
|
||||||
|
@ -14,10 +14,10 @@ type Limiter struct {
|
|||||||
Count int64
|
Count int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Limiter) RateLimit(client *redis.Client, ip string, path string) bool {
|
func (l *Limiter) RateLimit(client *redis.Client, ip string, path string) (bool, error) {
|
||||||
key := fmt.Sprintf("rate:%s:%s", path, ip)
|
key := fmt.Sprintf("rate:%s:%s", path, ip)
|
||||||
rate := utils.IncrWithLimit(client, key, 1, l.Count, int64(l.Duration))
|
rate, err := utils.IncrWithLimit(client, key, 1, l.Count, int64(l.Duration))
|
||||||
return !rate
|
return !rate, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var limits = map[string]Limiter{
|
var limits = map[string]Limiter{
|
||||||
@ -64,14 +64,28 @@ func ThrottleMiddleware() gin.HandlerFunc {
|
|||||||
cache := utils.GetCacheFromContext(c)
|
cache := utils.GetCacheFromContext(c)
|
||||||
|
|
||||||
limiter := GetPrefixMap[Limiter](path, limits)
|
limiter := GetPrefixMap[Limiter](path, limits)
|
||||||
if limiter != nil && limiter.RateLimit(cache, ip, path) {
|
if limiter != nil {
|
||||||
c.JSON(200, gin.H{
|
rate, err := limiter.RateLimit(cache, ip, path)
|
||||||
"status": false,
|
|
||||||
"reason": "You have sent too many requests. Please try again later.",
|
if err != nil {
|
||||||
"error": "request_throttled",
|
c.JSON(200, gin.H{
|
||||||
})
|
"status": false,
|
||||||
c.Abort()
|
"reason": err.Error(),
|
||||||
return
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rate {
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"status": false,
|
||||||
|
"reason": "You have sent too many requests. Please try again later.",
|
||||||
|
"error": "request_throttled",
|
||||||
|
})
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
@ -53,25 +53,25 @@ func SetCache(cache *redis.Client, key string, value string, expiration int64) e
|
|||||||
return cache.Set(context.Background(), key, value, time.Duration(expiration)*time.Second).Err()
|
return cache.Set(context.Background(), key, value, time.Duration(expiration)*time.Second).Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func IncrWithLimit(cache *redis.Client, key string, delta int64, limit int64, expiration int64) bool {
|
func IncrWithLimit(cache *redis.Client, key string, delta int64, limit int64, expiration int64) (bool, error) {
|
||||||
// not exist
|
// not exist
|
||||||
if _, err := cache.Get(context.Background(), key).Result(); err != nil {
|
if _, err := cache.Get(context.Background(), key).Result(); err != nil {
|
||||||
if errors.Is(err, redis.Nil) {
|
if errors.Is(err, redis.Nil) {
|
||||||
cache.Set(context.Background(), key, delta, time.Duration(expiration)*time.Second)
|
cache.Set(context.Background(), key, delta, time.Duration(expiration)*time.Second)
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
return false
|
return false, err
|
||||||
}
|
}
|
||||||
res, err := Incr(cache, key, delta)
|
res, err := Incr(cache, key, delta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false, err
|
||||||
}
|
}
|
||||||
if res > limit {
|
if res > limit {
|
||||||
// reset
|
// reset
|
||||||
cache.Set(context.Background(), key, limit, time.Duration(expiration)*time.Second)
|
cache.Set(context.Background(), key, limit, time.Duration(expiration)*time.Second)
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecrInt(cache *redis.Client, key string, delta int64) bool {
|
func DecrInt(cache *redis.Client, key string, delta int64) bool {
|
||||||
|
@ -145,7 +145,8 @@ func (w *WebSocket) IncrRate(key string) bool {
|
|||||||
|
|
||||||
func (w *WebSocket) IncrRateWithLimit(key string, limit int64, expiration int64) bool {
|
func (w *WebSocket) IncrRateWithLimit(key string, limit int64, expiration int64) bool {
|
||||||
cache := w.GetCache()
|
cache := w.GetCache()
|
||||||
return IncrWithLimit(cache, key, 1, limit, expiration)
|
state, err := IncrWithLimit(cache, key, 1, limit, expiration)
|
||||||
|
return state && err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebSocket) GetCtx() *gin.Context {
|
func (w *WebSocket) GetCtx() *gin.Context {
|
||||||
|
Loading…
Reference in New Issue
Block a user