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