merge
This commit is contained in:
45
package-lock.json
generated
45
package-lock.json
generated
@@ -13,6 +13,7 @@
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-switch": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -941,7 +942,7 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz",
|
||||
"integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
@@ -1312,6 +1313,34 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-switch": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.3.tgz",
|
||||
"integrity": "sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ==",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||
"@radix-ui/react-use-previous": "1.1.0",
|
||||
"@radix-ui/react-use-size": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz",
|
||||
@@ -1407,6 +1436,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-previous": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz",
|
||||
"integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-rect": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-switch": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { Send, Menu, MoreHorizontal, UserPlus, UserMinus, Users2, Users, MoreVertical, Share2, Mic, MicOff } from 'lucide-react';
|
||||
import { Send, Menu, MoreHorizontal, UserPlus, UserMinus, Users2, Users, MoreVertical, Share2, Mic, MicOff, Settings2 } from 'lucide-react';
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
@@ -12,11 +12,11 @@ import {
|
||||
} from "@/components/ui/tooltip";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog"
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from "@/components/ui/sheet"
|
||||
|
||||
import {generateAICharacters} from "@/config/aiCharacters";
|
||||
import { groups } from "@/config/groups";
|
||||
@@ -27,6 +27,7 @@ import remarkMath from 'remark-math'
|
||||
import rehypeKatex from 'rehype-katex'
|
||||
import html2canvas from 'html2canvas';
|
||||
import { SharePoster } from '@/components/SharePoster';
|
||||
import { MembersManagement } from '@/components/MembersManagement';
|
||||
|
||||
// 使用本地头像数据,避免外部依赖
|
||||
const getAvatarData = (name: string) => {
|
||||
@@ -117,9 +118,9 @@ const QuarterAvatar = ({ user, index }: { user: User, index: number }) => {
|
||||
);
|
||||
};
|
||||
|
||||
// 动态导入 KaTeX 样式
|
||||
// 修改 KaTeXStyle 组件
|
||||
const KaTeXStyle = () => (
|
||||
<style jsx global>{`
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
/* 只在聊天消息内应用 KaTeX 样式 */
|
||||
.chat-message .katex-html {
|
||||
display: none;
|
||||
@@ -141,11 +142,12 @@ const KaTeXStyle = () => (
|
||||
|
||||
/* 其他必要的 KaTeX 样式 */
|
||||
@import "katex/dist/katex.min.css";
|
||||
`}</style>
|
||||
`}} />
|
||||
);
|
||||
|
||||
const ChatUI = () => {
|
||||
const [group, setGroup] = useState(groups[1]);
|
||||
const [isGroupDiscussionMode, setIsGroupDiscussionMode] = useState(false);
|
||||
const groupAiCharacters = generateAICharacters(group.name).filter(character => group.members.includes(character.id));
|
||||
const [users, setUsers] = useState([
|
||||
{ id: 1, name: "我" },
|
||||
@@ -215,17 +217,18 @@ const ChatUI = () => {
|
||||
name: msg.sender.name
|
||||
}));
|
||||
let selectedGroupAiCharacters = groupAiCharacters;
|
||||
// 调度器api请求
|
||||
const shedulerResponse = await fetch('/api/scheduler', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ message: inputMessage, history: messageHistory, availableAIs: groupAiCharacters })
|
||||
});
|
||||
const shedulerData = await shedulerResponse.json();
|
||||
const selectedAIs = shedulerData.selectedAIs;
|
||||
selectedGroupAiCharacters = selectedAIs.map(ai => groupAiCharacters.find(c => c.id === ai));
|
||||
if (!isGroupDiscussionMode) {
|
||||
const shedulerResponse = await fetch('/api/scheduler', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ message: inputMessage, history: messageHistory, availableAIs: groupAiCharacters })
|
||||
});
|
||||
const shedulerData = await shedulerResponse.json();
|
||||
const selectedAIs = shedulerData.selectedAIs;
|
||||
selectedGroupAiCharacters = selectedAIs.map(ai => groupAiCharacters.find(c => c.id === ai));
|
||||
}
|
||||
for (let i = 0; i < selectedGroupAiCharacters.length; i++) {
|
||||
//禁言
|
||||
if (mutedUsers.includes(selectedGroupAiCharacters[i].id)) {
|
||||
@@ -454,7 +457,7 @@ const ChatUI = () => {
|
||||
)}
|
||||
</div>
|
||||
<Button variant="ghost" size="icon" onClick={() => setShowMembers(true)}>
|
||||
<Users className="w-5 h-5" />
|
||||
<Settings2 className="w-5 h-5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -589,81 +592,19 @@ const ChatUI = () => {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Members Management Dialog */}
|
||||
<Dialog open={showMembers} onOpenChange={setShowMembers}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>群成员管理</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="mt-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="text-sm text-gray-500">当前成员({users.length})</span>
|
||||
<Button variant="outline" size="sm">
|
||||
<UserPlus className="w-4 h-4 mr-2" />
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
<ScrollArea className="h-[300px]">
|
||||
<div className="space-y-2">
|
||||
{users.map((user) => (
|
||||
<div key={user.id} className="flex items-center justify-between p-2 hover:bg-gray-100 rounded-lg">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar>
|
||||
{'avatar' in user && user.avatar ? (
|
||||
<AvatarImage src={user.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(user.name).backgroundColor, color: 'white' }}>
|
||||
{user.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<span>{user.name}</span>
|
||||
{mutedUsers.includes(user.id) && (
|
||||
<span className="text-xs text-red-500">已禁言</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{user.name !== "我" && (
|
||||
<div className="flex gap-2">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleToggleMute(user.id)}
|
||||
>
|
||||
{mutedUsers.includes(user.id) ? (
|
||||
<MicOff className="w-4 h-4 text-red-500" />
|
||||
) : (
|
||||
<Mic className="w-4 h-4 text-green-500" />
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{mutedUsers.includes(user.id) ? '取消禁言' : '禁言'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
{/*<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleRemoveUser(user.id)}
|
||||
>
|
||||
<UserMinus className="w-4 h-4 text-red-500" />
|
||||
</Button>*/}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
{/* Members Management Dialog */}
|
||||
<MembersManagement
|
||||
showMembers={showMembers}
|
||||
setShowMembers={setShowMembers}
|
||||
users={users}
|
||||
mutedUsers={mutedUsers}
|
||||
handleToggleMute={handleToggleMute}
|
||||
isGroupDiscussionMode={isGroupDiscussionMode}
|
||||
onToggleGroupDiscussion={() => setIsGroupDiscussionMode(!isGroupDiscussionMode)}
|
||||
getAvatarData={getAvatarData}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 添加 SharePoster 组件 */}
|
||||
|
||||
116
src/components/MembersManagement.tsx
Normal file
116
src/components/MembersManagement.tsx
Normal file
@@ -0,0 +1,116 @@
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { UserPlus, Mic, MicOff } from 'lucide-react';
|
||||
import { type AICharacter } from "@/config/aiCharacters";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
interface User {
|
||||
id: number | string;
|
||||
name: string;
|
||||
avatar?: string;
|
||||
}
|
||||
|
||||
interface MembersManagementProps {
|
||||
showMembers: boolean;
|
||||
setShowMembers: (show: boolean) => void;
|
||||
users: (User | AICharacter)[];
|
||||
mutedUsers: string[];
|
||||
handleToggleMute: (userId: string) => void;
|
||||
getAvatarData: (name: string) => { backgroundColor: string; text: string };
|
||||
isGroupDiscussionMode: boolean;
|
||||
onToggleGroupDiscussion: () => void;
|
||||
}
|
||||
|
||||
export const MembersManagement = ({
|
||||
showMembers,
|
||||
setShowMembers,
|
||||
users,
|
||||
mutedUsers,
|
||||
handleToggleMute,
|
||||
getAvatarData,
|
||||
isGroupDiscussionMode,
|
||||
onToggleGroupDiscussion
|
||||
}: MembersManagementProps) => {
|
||||
return (
|
||||
<Sheet open={showMembers} onOpenChange={setShowMembers}>
|
||||
<SheetContent side="right" className="w-[300px] sm:w-[400px]">
|
||||
<SheetHeader>
|
||||
<SheetTitle>群聊配置</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="mt-4">
|
||||
<div className="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="text-sm">全员讨论模式</div>
|
||||
<div className="text-xs text-gray-500">开启后全员回复讨论</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={isGroupDiscussionMode}
|
||||
onCheckedChange={onToggleGroupDiscussion}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="text-sm text-gray-500">当前成员({users.length})</span>
|
||||
<Button variant="outline" size="sm">
|
||||
<UserPlus className="w-4 h-4 mr-2" />
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
<ScrollArea className="h-[calc(100vh-150px)]">
|
||||
<div className="space-y-2 pr-4">
|
||||
{users.map((user) => (
|
||||
<div key={user.id} className="flex items-center justify-between p-2 hover:bg-gray-100 rounded-lg">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar>
|
||||
{'avatar' in user && user.avatar ? (
|
||||
<AvatarImage src={user.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(user.name).backgroundColor, color: 'white' }}>
|
||||
{user.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<span>{user.name}</span>
|
||||
{mutedUsers.includes(user.id as string) && (
|
||||
<span className="text-xs text-red-500">已禁言</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{user.name !== "我" && (
|
||||
<div className="flex gap-2">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleToggleMute(user.id as string)}
|
||||
>
|
||||
{mutedUsers.includes(user.id as string) ? (
|
||||
<MicOff className="w-4 h-4 text-red-500" />
|
||||
) : (
|
||||
<Mic className="w-4 h-4 text-green-500" />
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{mutedUsers.includes(user.id as string) ? '取消禁言' : '禁言'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
};
|
||||
@@ -60,7 +60,7 @@ export function SharePoster({ isOpen, onClose, chatAreaRef }: SharePosterProps)
|
||||
chatAreaRef.current.scrollTop = 0;
|
||||
|
||||
const viewportWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
|
||||
const extraSpace = 20;
|
||||
const extraSpace = 6;
|
||||
const targetWidth = viewportWidth * 0.95 - (extraSpace * 2);
|
||||
|
||||
const currentWidth = messageContainer.getBoundingClientRect().width;
|
||||
|
||||
140
src/components/ui/sheet.tsx
Normal file
140
src/components/ui/sheet.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Sheet = SheetPrimitive.Root
|
||||
|
||||
const SheetTrigger = SheetPrimitive.Trigger
|
||||
|
||||
const SheetClose = SheetPrimitive.Close
|
||||
|
||||
const SheetPortal = SheetPrimitive.Portal
|
||||
|
||||
const SheetOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
))
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
||||
|
||||
const sheetVariants = cva(
|
||||
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
||||
{
|
||||
variants: {
|
||||
side: {
|
||||
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
||||
bottom:
|
||||
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
||||
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
||||
right:
|
||||
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
side: "right",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
interface SheetContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
VariantProps<typeof sheetVariants> {}
|
||||
|
||||
const SheetContent = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Content>,
|
||||
SheetContentProps
|
||||
>(({ side = "right", className, children, ...props }, ref) => (
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(sheetVariants({ side }), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">关闭</span>
|
||||
</SheetPrimitive.Close>
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
||||
))
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName
|
||||
|
||||
const SheetHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
SheetHeader.displayName = "SheetHeader"
|
||||
|
||||
const SheetFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
SheetFooter.displayName = "SheetFooter"
|
||||
|
||||
const SheetTitle = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
||||
|
||||
const SheetDescription = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SheetDescription.displayName = SheetPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Sheet,
|
||||
SheetPortal,
|
||||
SheetOverlay,
|
||||
SheetTrigger,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription,
|
||||
}
|
||||
27
src/components/ui/switch.tsx
Normal file
27
src/components/ui/switch.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
export { Switch }
|
||||
@@ -48,8 +48,8 @@ export function shedulerAICharacter(message: string, allTags: string[]): AIChara
|
||||
avatar: "",
|
||||
custom_prompt: `你是一个群聊总结分析专家,你在一个聊天群里,请分析群用户消息和上文群聊内容
|
||||
1、只能从给定的标签列表中选择最相关的标签,可选标签:${allTags.join(', ')}。
|
||||
2、请只返回标签列表,用逗号分隔,不要有其他解释。
|
||||
3、回复格式示例:标签1,标签2,标签3`
|
||||
2、请只返回标签列表,用逗号分隔,不要有其他解释, 不要有任何前缀。
|
||||
3、回复格式示例:文字游戏, 生活助手, 娱乐`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
model: modelConfigs[2].model,
|
||||
avatar: "/img/yuanbao.png",
|
||||
custom_prompt: `你是一个名叫"元宝"的硅基生命体,你当前在一个叫"${groupName}" 的聊天群里`,
|
||||
tags: ["微信生态", "新闻搜索", "文字游戏", "生活助手", "娱乐", "信息总结"]
|
||||
tags: ["微信生态", "新闻报道", "文字游戏", "生活助手", "娱乐", "信息总结"]
|
||||
},
|
||||
{
|
||||
id: 'ai5',
|
||||
@@ -122,16 +122,16 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
model: modelConfigs[0].model,
|
||||
avatar: "/img/qwen.jpg",
|
||||
custom_prompt: `你是一个名叫"千问"的硅基生命体,你当前在一个叫"${groupName}" 的聊天群里`,
|
||||
tags: ["广告文案","分析数据","文字游戏", "阿里"]
|
||||
tags: ["广告文案","分析数据","文字游戏","信息总结", "阿里"]
|
||||
},
|
||||
{
|
||||
id: 'ai7',
|
||||
name: "DeepSeek",
|
||||
personality: "deepseek-v3",
|
||||
model: modelConfigs[1].model,
|
||||
personality: "deepseek-r1",
|
||||
model: modelConfigs[3].model,
|
||||
avatar: "/img/ds.svg",
|
||||
custom_prompt: `你是一个名叫"DeepSeek"的硅基生命体,你当前在一个叫"${groupName}" 的聊天群里`,
|
||||
tags: ["深度推理", "编程", "文字游戏", "数学"]
|
||||
tags: ["深度推理", "编程", "文字游戏", "数学", "信息总结"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -126,3 +126,14 @@
|
||||
@keyframes blink {
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user