mirror of
https://github.com/coaidev/coai.git
synced 2025-05-28 17:30:15 +09:00
feat: support markdown/html on site notify and fix preset issues
This commit is contained in:
parent
6bf12df847
commit
80fd32add3
@ -67,7 +67,7 @@ func (c *ChatInstance) CreateRequest(props *ChatProps) *api.ChatReq {
|
||||
}
|
||||
|
||||
func getChoice(choice *api.ChatResp) *globals.Chunk {
|
||||
if choice == nil {
|
||||
if choice == nil || choice.Choice == nil || choice.Choice.Message == nil {
|
||||
return &globals.Chunk{Content: ""}
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ func getChoice(choice *api.ChatResp) *globals.Chunk {
|
||||
ToolCall: utils.Multi(calls != nil, &globals.ToolCalls{
|
||||
globals.ToolCall{
|
||||
Type: "function",
|
||||
Id: globals.ToolCallId(fmt.Sprintf("%s-%s", calls.Name, choice.ReqId)),
|
||||
Id: fmt.Sprintf("%s-%s", calls.Name, choice.ReqId),
|
||||
Function: globals.ToolCallFunction{
|
||||
Name: calls.Name,
|
||||
Arguments: calls.Arguments,
|
||||
|
@ -79,7 +79,7 @@ func getChoice(form *ChatResponse) *globals.Chunk {
|
||||
ToolCall: utils.Multi(choice.FunctionCall != nil, &globals.ToolCalls{
|
||||
globals.ToolCall{
|
||||
Type: "function",
|
||||
Id: globals.ToolCallId(fmt.Sprintf("%s-%s", choice.FunctionCall.Name, choice.FunctionCall.Arguments)),
|
||||
Id: fmt.Sprintf("%s-%s", choice.FunctionCall.Name, choice.FunctionCall.Arguments),
|
||||
Function: globals.ToolCallFunction{
|
||||
Name: choice.FunctionCall.Name,
|
||||
Arguments: choice.FunctionCall.Arguments,
|
||||
|
@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "chatnio",
|
||||
"version": "3.10.4"
|
||||
"version": "3.10.5"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
@ -363,3 +363,7 @@ input[type="number"] {
|
||||
|
||||
animation: fadeIn 0.5s forwards;
|
||||
}
|
||||
|
||||
.text-common {
|
||||
color: hsl(var(--text)) !important;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { useToast } from "@/components/ui/use-toast.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useEffectAsync } from "@/utils/hook.ts";
|
||||
import { getBroadcast } from "@/api/broadcast.ts";
|
||||
import Markdown from "@/components/Markdown.tsx";
|
||||
|
||||
function Broadcast() {
|
||||
const { t } = useTranslation();
|
||||
@ -17,8 +18,12 @@ function Broadcast() {
|
||||
|
||||
toast({
|
||||
title: t("broadcast"),
|
||||
description: content,
|
||||
duration: 10000,
|
||||
description: (
|
||||
<Markdown className={`text-common`} acceptHtml>
|
||||
{content}
|
||||
</Markdown>
|
||||
),
|
||||
duration: 30000,
|
||||
});
|
||||
}, [init]);
|
||||
|
||||
|
@ -23,6 +23,8 @@ type RichEditorProps = {
|
||||
onChange: (value: string) => void;
|
||||
maxLength?: number;
|
||||
|
||||
title?: string;
|
||||
|
||||
open?: boolean;
|
||||
setOpen?: (open: boolean) => void;
|
||||
children?: React.ReactNode;
|
||||
@ -184,7 +186,7 @@ function EditorProvider(props: RichEditorProps) {
|
||||
)}
|
||||
<DialogContent className={`editor-dialog flex-dialog`}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t("edit")}</DialogTitle>
|
||||
<DialogTitle>{props.title ?? t("edit")}</DialogTitle>
|
||||
<DialogDescription asChild>
|
||||
<RichEditor {...props} />
|
||||
</DialogDescription>
|
||||
|
@ -18,7 +18,7 @@ import {
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { extractMessage } from "@/utils/processor.ts";
|
||||
import { Button } from "@/components/ui/button.tsx";
|
||||
import { Loader2, Plus, RotateCcw } from "lucide-react";
|
||||
import { Eye, Loader2, MoreVertical, Plus, RotateCcw } from "lucide-react";
|
||||
import { useToast } from "@/components/ui/use-toast.ts";
|
||||
import {
|
||||
Dialog,
|
||||
@ -31,6 +31,13 @@ import {
|
||||
} from "@/components/ui/dialog.tsx";
|
||||
import { Textarea } from "@/components/ui/textarea.tsx";
|
||||
import { DialogClose } from "@radix-ui/react-dialog";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu.tsx";
|
||||
import EditorProvider from "@/components/EditorProvider.tsx";
|
||||
|
||||
type CreateBroadcastDialogProps = {
|
||||
onCreated?: () => void;
|
||||
@ -96,6 +103,45 @@ function CreateBroadcastDialog(props: CreateBroadcastDialogProps) {
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
function BroadcastItem({ item }: { item: BroadcastInfo }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const [value, setValue] = useState<string>("");
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<EditorProvider
|
||||
title={t("admin.view")}
|
||||
value={value || item.content}
|
||||
onChange={setValue}
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
<TableCell>{item.index}</TableCell>
|
||||
<TableCell>{extractMessage(item.content, 25)}</TableCell>
|
||||
<TableCell>{item.poster}</TableCell>
|
||||
<TableCell>{item.created_at}</TableCell>
|
||||
<TableCell>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant={`outline`} size={`icon`}>
|
||||
<MoreVertical className={`w-4 h-4`} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align={`end`}>
|
||||
<DropdownMenuItem onClick={() => setOpen(true)}>
|
||||
<Eye className={`w-4 h-4 mr-1`} />
|
||||
{t("admin.view")}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
function BroadcastTable() {
|
||||
const { t } = useTranslation();
|
||||
const init = useSelector(selectInit);
|
||||
@ -135,16 +181,12 @@ function BroadcastTable() {
|
||||
<TableHead>{t("admin.broadcast-content")}</TableHead>
|
||||
<TableHead>{t("admin.poster")}</TableHead>
|
||||
<TableHead>{t("admin.post-at")}</TableHead>
|
||||
<TableHead>{t("admin.action")}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.map((user, idx) => (
|
||||
<TableRow key={idx}>
|
||||
<TableCell>{user.index}</TableCell>
|
||||
<TableCell>{extractMessage(user.content, 25)}</TableCell>
|
||||
<TableCell>{user.poster}</TableCell>
|
||||
<TableCell>{user.created_at}</TableCell>
|
||||
</TableRow>
|
||||
{data.map((item, idx) => (
|
||||
<BroadcastItem key={idx} item={item} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
import { syncSiteInfo } from "@/admin/api/info.ts";
|
||||
import { setAxiosConfig } from "@/conf/api.ts";
|
||||
|
||||
export const version = "3.10.4"; // version of the current build
|
||||
export const version = "3.10.5"; // version of the current build
|
||||
export const dev: boolean = getDev(); // is in development mode (for debugging, in localhost origin)
|
||||
export const deploy: boolean = true; // is production environment (for api endpoint)
|
||||
export const tokenField = getTokenField(deploy); // token field name for storing token
|
||||
|
@ -407,6 +407,7 @@
|
||||
"billing-month": "本月入账",
|
||||
"subscription-users": "订阅用户",
|
||||
"seat": "位",
|
||||
"view": "查看",
|
||||
"model-chart": "模型使用统计",
|
||||
"model-chart-tip": "Token 用量",
|
||||
"model-usage-chart": "模型使用占比",
|
||||
@ -438,7 +439,7 @@
|
||||
"post-at": "发布时间",
|
||||
"broadcast-content": "公告内容",
|
||||
"create-broadcast": "发布公告",
|
||||
"broadcast-placeholder": "请输入公告内容",
|
||||
"broadcast-placeholder": "请输入通知内容 (支持 Markdown / HTML)",
|
||||
"post": "发布",
|
||||
"post-success": "发布成功",
|
||||
"post-success-prompt": "公告发布成功。",
|
||||
|
@ -672,7 +672,8 @@
|
||||
"unban-action-desc": "Are you sure you want to unblock this user?",
|
||||
"billing": "Income",
|
||||
"chatnio-format-only": "This format is unique to Chat Nio",
|
||||
"exit": "Log out of the background"
|
||||
"exit": "Log out of the background",
|
||||
"view": "View"
|
||||
},
|
||||
"mask": {
|
||||
"title": "Mask Settings",
|
||||
|
@ -672,7 +672,8 @@
|
||||
"unban-action-desc": "このユーザーのブロックを解除してもよろしいですか?",
|
||||
"billing": "収入",
|
||||
"chatnio-format-only": "このフォーマットはChat Nioに固有です",
|
||||
"exit": "バックグラウンドからログアウト"
|
||||
"exit": "バックグラウンドからログアウト",
|
||||
"view": "確認"
|
||||
},
|
||||
"mask": {
|
||||
"title": "プリセット設定",
|
||||
|
@ -672,7 +672,8 @@
|
||||
"unban-action-desc": "Вы уверены, что хотите разблокировать этого пользователя?",
|
||||
"billing": "Доходы",
|
||||
"chatnio-format-only": "Этот формат уникален для Chat Nio",
|
||||
"exit": "Выйти из фонового режима"
|
||||
"exit": "Выйти из фонового режима",
|
||||
"view": "проверить"
|
||||
},
|
||||
"mask": {
|
||||
"title": "Настройки маски",
|
||||
|
@ -31,7 +31,11 @@ type ProgressProps = {
|
||||
total: number;
|
||||
};
|
||||
|
||||
function GenerateProgress({ current, total, quota }: ProgressProps & { quota: number }) {
|
||||
function GenerateProgress({
|
||||
current,
|
||||
total,
|
||||
quota,
|
||||
}: ProgressProps & { quota: number }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
|
@ -136,17 +136,20 @@ const chatSlice = createSlice({
|
||||
const conversation = state.conversations[id];
|
||||
if (!conversation) return;
|
||||
|
||||
if (id === -1 && state.mask_item && conversation.messages.length === 0) {
|
||||
conversation.messages = [...state.mask_item.context];
|
||||
state.mask_item = null;
|
||||
}
|
||||
|
||||
conversation.messages.push({
|
||||
role: role ?? AssistantRole,
|
||||
content: content ?? "",
|
||||
end: role === AssistantRole ? false : undefined,
|
||||
});
|
||||
},
|
||||
fillMaskItem: (state) => {
|
||||
const conversation = state.conversations[-1];
|
||||
|
||||
if (state.mask_item && conversation.messages.length === 0) {
|
||||
conversation.messages = [...state.mask_item.context];
|
||||
state.mask_item = null;
|
||||
}
|
||||
},
|
||||
updateMessage: (state, action) => {
|
||||
const { id, message } = action.payload as {
|
||||
id: number;
|
||||
@ -380,6 +383,7 @@ export const {
|
||||
setSupportModels,
|
||||
setMaskItem,
|
||||
clearMaskItem,
|
||||
fillMaskItem,
|
||||
createMessage,
|
||||
updateMessage,
|
||||
removeMessage,
|
||||
@ -513,7 +517,7 @@ export function useMessageActions() {
|
||||
|
||||
if (current === -1 && mask && mask.context.length > 0) {
|
||||
conn.sendMaskEvent(t, mask);
|
||||
dispatch(clearMaskItem());
|
||||
dispatch(fillMaskItem());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package globals
|
||||
|
||||
type ToolCallId string
|
||||
type FunctionTools []ToolObject
|
||||
type ToolObject struct {
|
||||
Type string `json:"type"`
|
||||
@ -41,7 +40,7 @@ type ToolCallFunction struct {
|
||||
type ToolCall struct {
|
||||
Index *int `json:"index,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Id ToolCallId `json:"id"`
|
||||
Id string `json:"id"`
|
||||
Function ToolCallFunction `json:"function"`
|
||||
}
|
||||
type ToolCalls []ToolCall
|
||||
|
Loading…
Reference in New Issue
Block a user