diff --git a/adapter/skylark/chat.go b/adapter/skylark/chat.go index 3cd973b..6fb0478 100644 --- a/adapter/skylark/chat.go +++ b/adapter/skylark/chat.go @@ -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, diff --git a/adapter/sparkdesk/chat.go b/adapter/sparkdesk/chat.go index 25b7d69..b534945 100644 --- a/adapter/sparkdesk/chat.go +++ b/adapter/sparkdesk/chat.go @@ -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, diff --git a/app/src-tauri/tauri.conf.json b/app/src-tauri/tauri.conf.json index 089621d..bcf2004 100644 --- a/app/src-tauri/tauri.conf.json +++ b/app/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "chatnio", - "version": "3.10.4" + "version": "3.10.5" }, "tauri": { "allowlist": { diff --git a/app/src/assets/ui.less b/app/src/assets/ui.less index 522c16f..cd3296a 100644 --- a/app/src/assets/ui.less +++ b/app/src/assets/ui.less @@ -363,3 +363,7 @@ input[type="number"] { animation: fadeIn 0.5s forwards; } + +.text-common { + color: hsl(var(--text)) !important; +} diff --git a/app/src/components/Broadcast.tsx b/app/src/components/Broadcast.tsx index 32ba348..de3f5bd 100644 --- a/app/src/components/Broadcast.tsx +++ b/app/src/components/Broadcast.tsx @@ -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: ( + + {content} + + ), + duration: 30000, }); }, [init]); diff --git a/app/src/components/EditorProvider.tsx b/app/src/components/EditorProvider.tsx index 8c80910..1da8c8c 100644 --- a/app/src/components/EditorProvider.tsx +++ b/app/src/components/EditorProvider.tsx @@ -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) { )} - {t("edit")} + {props.title ?? t("edit")} diff --git a/app/src/components/admin/assemblies/BroadcastTable.tsx b/app/src/components/admin/assemblies/BroadcastTable.tsx index 0f87af7..9ce834f 100644 --- a/app/src/components/admin/assemblies/BroadcastTable.tsx +++ b/app/src/components/admin/assemblies/BroadcastTable.tsx @@ -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) { ); } + +function BroadcastItem({ item }: { item: BroadcastInfo }) { + const { t } = useTranslation(); + + const [open, setOpen] = useState(false); + const [value, setValue] = useState(""); + + return ( + + + {item.index} + {extractMessage(item.content, 25)} + {item.poster} + {item.created_at} + + + + + + + setOpen(true)}> + + {t("admin.view")} + + + + + + ); +} + function BroadcastTable() { const { t } = useTranslation(); const init = useSelector(selectInit); @@ -135,16 +181,12 @@ function BroadcastTable() { {t("admin.broadcast-content")} {t("admin.poster")} {t("admin.post-at")} + {t("admin.action")} - {data.map((user, idx) => ( - - {user.index} - {extractMessage(user.content, 25)} - {user.poster} - {user.created_at} - + {data.map((item, idx) => ( + ))} diff --git a/app/src/conf/bootstrap.ts b/app/src/conf/bootstrap.ts index 35a253a..b6f0cba 100644 --- a/app/src/conf/bootstrap.ts +++ b/app/src/conf/bootstrap.ts @@ -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 diff --git a/app/src/resources/i18n/cn.json b/app/src/resources/i18n/cn.json index 9b7e671..cdb1990 100644 --- a/app/src/resources/i18n/cn.json +++ b/app/src/resources/i18n/cn.json @@ -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": "公告发布成功。", diff --git a/app/src/resources/i18n/en.json b/app/src/resources/i18n/en.json index 2dd61ec..0bd31cc 100644 --- a/app/src/resources/i18n/en.json +++ b/app/src/resources/i18n/en.json @@ -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", diff --git a/app/src/resources/i18n/ja.json b/app/src/resources/i18n/ja.json index b3198bd..aac9954 100644 --- a/app/src/resources/i18n/ja.json +++ b/app/src/resources/i18n/ja.json @@ -672,7 +672,8 @@ "unban-action-desc": "このユーザーのブロックを解除してもよろしいですか?", "billing": "収入", "chatnio-format-only": "このフォーマットはChat Nioに固有です", - "exit": "バックグラウンドからログアウト" + "exit": "バックグラウンドからログアウト", + "view": "確認" }, "mask": { "title": "プリセット設定", diff --git a/app/src/resources/i18n/ru.json b/app/src/resources/i18n/ru.json index dd9bb03..2609fe1 100644 --- a/app/src/resources/i18n/ru.json +++ b/app/src/resources/i18n/ru.json @@ -672,7 +672,8 @@ "unban-action-desc": "Вы уверены, что хотите разблокировать этого пользователя?", "billing": "Доходы", "chatnio-format-only": "Этот формат уникален для Chat Nio", - "exit": "Выйти из фонового режима" + "exit": "Выйти из фонового режима", + "view": "проверить" }, "mask": { "title": "Настройки маски", diff --git a/app/src/routes/Article.tsx b/app/src/routes/Article.tsx index a9cbfe8..9e97ede 100644 --- a/app/src/routes/Article.tsx +++ b/app/src/routes/Article.tsx @@ -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 ( diff --git a/app/src/store/chat.ts b/app/src/store/chat.ts index a0fc030..155c511 100644 --- a/app/src/store/chat.ts +++ b/app/src/store/chat.ts @@ -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()); } } diff --git a/globals/tools.go b/globals/tools.go index dd14866..6d66f1b 100644 --- a/globals/tools.go +++ b/globals/tools.go @@ -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