正在显示
10 个修改的文件
包含
221 行增加
和
221 行删除
1 | import { getServerSideConfig } from "@/app/config/server"; | 1 | import { getServerSideConfig } from "@/app/config/server"; |
2 | import { NextRequest, NextResponse } from "next/server"; | 2 | import { NextRequest, NextResponse } from "next/server"; |
3 | 3 | ||
4 | +// 处理每日使用限制逻辑 | ||
5 | +function parseDailyUsage(allowNum: string, configMax: number): number { | ||
6 | + if (allowNum === "first") return configMax; | ||
7 | + const parsed = parseInt(allowNum, 10); | ||
8 | + return Number.isNaN(parsed) ? configMax : parsed; | ||
9 | +} | ||
10 | + | ||
4 | export async function handle( | 11 | export async function handle( |
5 | req: NextRequest, | 12 | req: NextRequest, |
6 | { params }: { params: { path: string[] } }, | 13 | { params }: { params: { path: string[] } }, |
@@ -14,7 +21,25 @@ export async function handle( | @@ -14,7 +21,25 @@ export async function handle( | ||
14 | try { | 21 | try { |
15 | // 获取 accessCode | 22 | // 获取 accessCode |
16 | const body = await new Response(req.body).text(); | 23 | const body = await new Response(req.body).text(); |
17 | - const uid = JSON.parse(body); | 24 | + const parsedBody = JSON.parse(body); |
25 | + | ||
26 | + // 提取 accessCode 和 max_use 参数 | ||
27 | + const uid = parsedBody.accessCode; | ||
28 | + let maxUse = parsedBody.max_use; | ||
29 | + if (!uid) { | ||
30 | + return NextResponse.json({ | ||
31 | + data: "请前往设置页面输入登录密码", | ||
32 | + status: 400, | ||
33 | + }); | ||
34 | + } | ||
35 | + if (!maxUse) { | ||
36 | + return NextResponse.json({ | ||
37 | + data: "参数错误", | ||
38 | + status: 400, | ||
39 | + }); | ||
40 | + } | ||
41 | + maxUse = parseDailyUsage(maxUse, config.docmeeMaxDailyUses); | ||
42 | + | ||
18 | const headers = new Headers({ | 43 | const headers = new Headers({ |
19 | "Api-Key": config.docmeeApiKey, | 44 | "Api-Key": config.docmeeApiKey, |
20 | "Content-Type": "application/json", | 45 | "Content-Type": "application/json", |
@@ -24,7 +49,7 @@ export async function handle( | @@ -24,7 +49,7 @@ export async function handle( | ||
24 | const response = await fetch(reqUrl, { | 49 | const response = await fetch(reqUrl, { |
25 | headers, | 50 | headers, |
26 | method: "POST", | 51 | method: "POST", |
27 | - body: JSON.stringify({ uid: uid, limit: config.docmeeMaxDailyUses }), | 52 | + body: JSON.stringify({ uid: uid, limit: maxUse }), |
28 | }); | 53 | }); |
29 | if (!response.ok) { | 54 | if (!response.ok) { |
30 | throw new Error( | 55 | throw new Error( |
@@ -62,6 +62,9 @@ export async function handle( | @@ -62,6 +62,9 @@ export async function handle( | ||
62 | return createErrorResponse("无效请求参数", 400); | 62 | return createErrorResponse("无效请求参数", 400); |
63 | } | 63 | } |
64 | const localDataObj: LocalData = JSON.parse(localData); | 64 | const localDataObj: LocalData = JSON.parse(localData); |
65 | + if (!localDataObj.maxDailyUses) { | ||
66 | + return createErrorResponse("缺少请求参数", 400); | ||
67 | + } | ||
65 | const maxDailyUses = parseDailyUsage( | 68 | const maxDailyUses = parseDailyUsage( |
66 | localDataObj.maxDailyUses, | 69 | localDataObj.maxDailyUses, |
67 | config.maxDailyUses, | 70 | config.maxDailyUses, |
@@ -95,7 +95,7 @@ const useTaskPoller = () => { | @@ -95,7 +95,7 @@ const useTaskPoller = () => { | ||
95 | }; | 95 | }; |
96 | 96 | ||
97 | // 日期处理工具 | 97 | // 日期处理工具 |
98 | -const useDateUtils = () => { | 98 | +export const useDateUtils = () => { |
99 | const getFormattedToday = (): string => { | 99 | const getFormattedToday = (): string => { |
100 | const today = new Date(); | 100 | const today = new Date(); |
101 | return today.toISOString().split("T")[0].replace(/-/g, ""); | 101 | return today.toISOString().split("T")[0].replace(/-/g, ""); |
@@ -109,9 +109,8 @@ const useDateUtils = () => { | @@ -109,9 +109,8 @@ const useDateUtils = () => { | ||
109 | }; | 109 | }; |
110 | 110 | ||
111 | // 本地存储管理 | 111 | // 本地存储管理 |
112 | -const useLocalStorage = () => { | 112 | +export const useLocalStorage = () => { |
113 | const { getFormattedToday, isToday } = useDateUtils(); | 113 | const { getFormattedToday, isToday } = useDateUtils(); |
114 | - | ||
115 | const getLocalData = (accessCode: string): LocalData => { | 114 | const getLocalData = (accessCode: string): LocalData => { |
116 | try { | 115 | try { |
117 | const data = localStorage.getItem(accessCode); | 116 | const data = localStorage.getItem(accessCode); |
@@ -123,25 +122,45 @@ const useLocalStorage = () => { | @@ -123,25 +122,45 @@ const useLocalStorage = () => { | ||
123 | return { | 122 | return { |
124 | date: parsed.date || getFormattedToday(), | 123 | date: parsed.date || getFormattedToday(), |
125 | maxDailyUses: parsed.maxDailyUses || "first", | 124 | maxDailyUses: parsed.maxDailyUses || "first", |
125 | + pptMaxUses: parsed.pptMsxUses || "first", | ||
126 | }; | 126 | }; |
127 | } catch (e) { | 127 | } catch (e) { |
128 | return defaultLocalData(); | 128 | return defaultLocalData(); |
129 | } | 129 | } |
130 | }; | 130 | }; |
131 | 131 | ||
132 | - const updateLocalUsage = (accessCode: string, maxDailyUses: number) => { | ||
133 | - const saveData: LocalData = { | 132 | + const updateLocalUsage = ( |
133 | + accessCode: string, | ||
134 | + maxDailyUses?: number, | ||
135 | + pptMaxUses?: number, | ||
136 | + ) => { | ||
137 | + const existingData = getLocalData(accessCode); | ||
138 | + // 检查现有数据的日期是否是今天 | ||
139 | + const isNewDay = !isToday(existingData.date); | ||
140 | + // 创建新的数据对象 | ||
141 | + const newData: LocalData = { | ||
134 | date: getFormattedToday(), | 142 | date: getFormattedToday(), |
135 | - maxDailyUses: maxDailyUses.toString(), | 143 | + maxDailyUses: |
144 | + maxDailyUses !== undefined | ||
145 | + ? maxDailyUses.toString() | ||
146 | + : isNewDay | ||
147 | + ? "first" | ||
148 | + : existingData.maxDailyUses, | ||
149 | + pptMaxUses: | ||
150 | + pptMaxUses !== undefined | ||
151 | + ? pptMaxUses.toString() | ||
152 | + : isNewDay | ||
153 | + ? "first" | ||
154 | + : existingData.pptMaxUses, | ||
136 | }; | 155 | }; |
137 | - localStorage.setItem(accessCode, JSON.stringify(saveData)); | 156 | + localStorage.setItem(accessCode, JSON.stringify(newData)); |
138 | }; | 157 | }; |
139 | 158 | ||
140 | const defaultLocalData = (): LocalData => ({ | 159 | const defaultLocalData = (): LocalData => ({ |
141 | date: getFormattedToday(), | 160 | date: getFormattedToday(), |
142 | maxDailyUses: "first", | 161 | maxDailyUses: "first", |
162 | + pptMaxUses: "first", | ||
143 | }); | 163 | }); |
144 | - | ||
145 | return { getLocalData, updateLocalUsage }; | 164 | return { getLocalData, updateLocalUsage }; |
146 | }; | 165 | }; |
147 | 166 | ||
@@ -283,18 +302,28 @@ export function BgPanel(props: FileProps) { | @@ -283,18 +302,28 @@ export function BgPanel(props: FileProps) { | ||
283 | return message.error("请先输入提示词"); | 302 | return message.error("请先输入提示词"); |
284 | } | 303 | } |
285 | setIsLoading(true); | 304 | setIsLoading(true); |
286 | - const res = await fetch(`${ApiPath.OpenAiImg}/generations`, { | ||
287 | - method: "POST", | ||
288 | - body: JSON.stringify(prompt), | ||
289 | - }); | ||
290 | - if (!res.ok) { | ||
291 | - const errorData = await res.json(); | ||
292 | - throw new Error(errorData.message || Locale.BgRemoval.error.reqErr); | 305 | + try { |
306 | + const res = await fetch(`${ApiPath.OpenAiImg}/generations`, { | ||
307 | + method: "POST", | ||
308 | + body: JSON.stringify(prompt), | ||
309 | + }); | ||
310 | + if (!res.ok) { | ||
311 | + const errorData = await res.json(); | ||
312 | + throw new Error(errorData.message || Locale.BgRemoval.error.reqErr); | ||
313 | + } | ||
314 | + const responseData = await res.json(); | ||
315 | + // 获取新图片的Blob | ||
316 | + const newBlob = await urlToBlob(responseData.data.data[0].url); | ||
317 | + // 创建新的对象URL | ||
318 | + const newUrl = URL.createObjectURL(newBlob); | ||
319 | + // 同步更新所有相关状态 | ||
320 | + setPreviewUrl(newUrl); | ||
321 | + setFileData(newBlob); | ||
322 | + } catch (error) { | ||
323 | + message.error(Locale.BgRemoval.error.reqErr); | ||
324 | + } finally { | ||
325 | + setIsLoading(false); | ||
293 | } | 326 | } |
294 | - const responseData = await res.json(); | ||
295 | - console.log(responseData.data.data[0]); | ||
296 | - setPreviewUrl(responseData.data.data[0].url); | ||
297 | - setIsLoading(false); | ||
298 | }; | 327 | }; |
299 | 328 | ||
300 | const handleApiRequest = async (endpoint: string) => { | 329 | const handleApiRequest = async (endpoint: string) => { |
@@ -315,7 +344,7 @@ export function BgPanel(props: FileProps) { | @@ -315,7 +344,7 @@ export function BgPanel(props: FileProps) { | ||
315 | const formData = new FormData(); | 344 | const formData = new FormData(); |
316 | const localData = getLocalData(accessStore.accessCode); // 获取本地数据 | 345 | const localData = getLocalData(accessStore.accessCode); // 获取本地数据 |
317 | formData.append("accessCode", accessStore.accessCode); | 346 | formData.append("accessCode", accessStore.accessCode); |
318 | - formData.append("localData", JSON.stringify(localData)); // 序列化后添加 | 347 | + formData.append("localData", JSON.stringify(localData)); |
319 | formData.append("image_file", fileData as Blob); | 348 | formData.append("image_file", fileData as Blob); |
320 | if (endpoint === "visual/r-background") { | 349 | if (endpoint === "visual/r-background") { |
321 | formData.append("prompt", prompt); | 350 | formData.append("prompt", prompt); |
@@ -6,6 +6,7 @@ import { getMindPrompt } from "@/app/utils/prompt"; | @@ -6,6 +6,7 @@ import { getMindPrompt } from "@/app/utils/prompt"; | ||
6 | import { useChatStore } from "@/app/store"; | 6 | import { useChatStore } from "@/app/store"; |
7 | import { type MindElixirData } from "mind-elixir"; | 7 | import { type MindElixirData } from "mind-elixir"; |
8 | import { message } from "antd"; | 8 | import { message } from "antd"; |
9 | +import Locale from "@/app/locales"; | ||
9 | 10 | ||
10 | export interface MindPanelProps { | 11 | export interface MindPanelProps { |
11 | setData: React.Dispatch<React.SetStateAction<MindElixirData>>; | 12 | setData: React.Dispatch<React.SetStateAction<MindElixirData>>; |
@@ -19,31 +20,21 @@ export function MindPanel(props: MindPanelProps) { | @@ -19,31 +20,21 @@ export function MindPanel(props: MindPanelProps) { | ||
19 | const [loading, setLoading] = useState(false); | 20 | const [loading, setLoading] = useState(false); |
20 | const chatStore = useChatStore(); | 21 | const chatStore = useChatStore(); |
21 | const submit = async () => { | 22 | const submit = async () => { |
22 | - if (!inputValue.trim()) return message.error("请输入提示词!"); | 23 | + if (!inputValue.trim()) return message.error(Locale.BgRemoval.error.prompt); |
23 | setIsLoading(true); | 24 | setIsLoading(true); |
24 | try { | 25 | try { |
25 | const prompt = getMindPrompt(inputValue, false); | 26 | const prompt = getMindPrompt(inputValue, false); |
27 | + console.log("请求------------"); | ||
26 | const response = await chatStore.directLlmInvoke(prompt, "gpt-4o-mini"); | 28 | const response = await chatStore.directLlmInvoke(prompt, "gpt-4o-mini"); |
27 | - console.log("原始响应:", response); | ||
28 | - let cleanedContent = response.startsWith("```json") | ||
29 | - ? response.substring(8) | ||
30 | - : response; | ||
31 | - if (cleanedContent.endsWith("```")) { | ||
32 | - cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4); | ||
33 | - } | ||
34 | - const parsedData: MindElixirData = JSON.parse(response); | ||
35 | - console.log("解析后响应:", parsedData); | ||
36 | - // 增强校验逻辑 | ||
37 | - if ( | ||
38 | - !parsedData?.nodeData?.id || | ||
39 | - !Array.isArray(parsedData.nodeData.children) | ||
40 | - ) { | ||
41 | - throw new Error("数据结构不完整"); | ||
42 | - } | 29 | + console.log(response); |
30 | + const cleanedContent = response.replace(/^```json|```$/g, ""); | ||
31 | + console.log(cleanedContent); | ||
32 | + const parsedData: MindElixirData = JSON.parse(cleanedContent); | ||
33 | + console.log("-----" + parsedData); | ||
43 | setData(parsedData); | 34 | setData(parsedData); |
44 | } catch (error) { | 35 | } catch (error) { |
45 | console.log(error); | 36 | console.log(error); |
46 | - message.error("请求失败,请重试"); | 37 | + message.error(Locale.BgRemoval.error.reqErr); |
47 | } finally { | 38 | } finally { |
48 | setIsLoading(false); // 确保关闭加载状态:ml-citation{ref="2,5" data="citationList"} | 39 | setIsLoading(false); // 确保关闭加载状态:ml-citation{ref="2,5" data="citationList"} |
49 | } | 40 | } |
@@ -21,6 +21,20 @@ import SDIcon from "@/app/icons/sd.svg"; | @@ -21,6 +21,20 @@ import SDIcon from "@/app/icons/sd.svg"; | ||
21 | import { useChatStore, useMindMapStore } from "@/app/store"; | 21 | import { useChatStore, useMindMapStore } from "@/app/store"; |
22 | import { message } from "antd"; | 22 | import { message } from "antd"; |
23 | 23 | ||
24 | +// 常量配置抽取 | ||
25 | +const INITIAL_DATA: MindElixirData = { | ||
26 | + nodeData: { | ||
27 | + id: "root", | ||
28 | + topic: "中心主题", | ||
29 | + }, | ||
30 | +}; | ||
31 | +const LOADING_DATA: MindElixirData = { | ||
32 | + nodeData: { | ||
33 | + id: "root", | ||
34 | + topic: "生成中....", | ||
35 | + }, | ||
36 | +}; | ||
37 | + | ||
24 | export function MindPage() { | 38 | export function MindPage() { |
25 | const isMobileScreen = useMobileScreen(); | 39 | const isMobileScreen = useMobileScreen(); |
26 | const navigate = useNavigate(); | 40 | const navigate = useNavigate(); |
@@ -35,13 +49,8 @@ export function MindPage() { | @@ -35,13 +49,8 @@ export function MindPage() { | ||
35 | const chatStore = useChatStore(); | 49 | const chatStore = useChatStore(); |
36 | const { newMessages, content } = useMindMapStore.getState(); | 50 | const { newMessages, content } = useMindMapStore.getState(); |
37 | const query = useLocation(); | 51 | const query = useLocation(); |
38 | - const { msg } = query.state || {}; | ||
39 | - const [data, setData] = useState<MindElixirData>({ | ||
40 | - nodeData: { | ||
41 | - id: "root", | ||
42 | - topic: "中心主题", | ||
43 | - }, | ||
44 | - }); | 52 | + let { msg } = query.state || {}; |
53 | + const [data, setData] = useState<MindElixirData>(INITIAL_DATA); | ||
45 | 54 | ||
46 | useEffect(() => { | 55 | useEffect(() => { |
47 | // 确保容器元素已挂载 | 56 | // 确保容器元素已挂载 |
@@ -68,15 +77,7 @@ export function MindPage() { | @@ -68,15 +77,7 @@ export function MindPage() { | ||
68 | newMessages, | 77 | newMessages, |
69 | "gpt-4o-mini", | 78 | "gpt-4o-mini", |
70 | ); | 79 | ); |
71 | - let cleanedContent = response.startsWith("```json") | ||
72 | - ? response.substring(8) | ||
73 | - : response; | ||
74 | - if (cleanedContent.endsWith("```")) { | ||
75 | - cleanedContent = cleanedContent.substring( | ||
76 | - 0, | ||
77 | - cleanedContent.length - 4, | ||
78 | - ); | ||
79 | - } | 80 | + const cleanedContent = response.replace(/^```json|```$/g, ""); |
80 | const parsedData: MindElixirData = JSON.parse(cleanedContent); | 81 | const parsedData: MindElixirData = JSON.parse(cleanedContent); |
81 | // 增强校验逻辑 | 82 | // 增强校验逻辑 |
82 | if ( | 83 | if ( |
@@ -86,6 +87,7 @@ export function MindPage() { | @@ -86,6 +87,7 @@ export function MindPage() { | ||
86 | throw new Error("数据结构不完整"); | 87 | throw new Error("数据结构不完整"); |
87 | } | 88 | } |
88 | setData(parsedData); | 89 | setData(parsedData); |
90 | + navigate(Path.Mind, { replace: true, state: { msg: null } }); | ||
89 | } catch (error) { | 91 | } catch (error) { |
90 | console.log(error); | 92 | console.log(error); |
91 | message.error("请求失败,请重试"); | 93 | message.error("请求失败,请重试"); |
@@ -100,9 +102,6 @@ export function MindPage() { | @@ -100,9 +102,6 @@ export function MindPage() { | ||
100 | return () => { | 102 | return () => { |
101 | if (mindInstance.current) { | 103 | if (mindInstance.current) { |
102 | mindInstance.current.destroy(); | 104 | mindInstance.current.destroy(); |
103 | - // 移除事件监听器 | ||
104 | - document.removeEventListener("mousemove", () => {}); | ||
105 | - document.removeEventListener("mouseup", () => {}); | ||
106 | } | 105 | } |
107 | }; | 106 | }; |
108 | }, []); | 107 | }, []); |
@@ -113,76 +112,10 @@ export function MindPage() { | @@ -113,76 +112,10 @@ export function MindPage() { | ||
113 | 112 | ||
114 | useEffect(() => { | 113 | useEffect(() => { |
115 | if (isLoading) { | 114 | if (isLoading) { |
116 | - mindInstance.current?.refresh({ | ||
117 | - nodeData: { | ||
118 | - id: "root", | ||
119 | - topic: "生成中....", | ||
120 | - }, | ||
121 | - }); | ||
122 | - } else { | ||
123 | - mindInstance.current?.refresh({ | ||
124 | - nodeData: { | ||
125 | - id: "root", | ||
126 | - topic: "中心主题", | ||
127 | - }, | ||
128 | - }); | 115 | + mindInstance.current?.refresh(LOADING_DATA); |
129 | } | 116 | } |
130 | }, [isLoading]); | 117 | }, [isLoading]); |
131 | 118 | ||
132 | - // const meNode=document.querySelector('me-nodes') | ||
133 | - // const draggableElement = meNode?.querySelector('me-root') as HTMLElement | null; | ||
134 | - // if (draggableElement) { | ||
135 | - // let isDragging = false; // 是否正在拖拽 | ||
136 | - // let startX = 0; // 鼠标按下时的 X 坐标 | ||
137 | - // let startY = 0; // 鼠标按下时的 Y 坐标 | ||
138 | - // let initialLeft = 0; // 元素初始的左偏移量 | ||
139 | - // let initialTop = 0; // 元素初始的上偏移量 | ||
140 | - // // 鼠标按下事件 | ||
141 | - // draggableElement.addEventListener('mousedown', (e) => { | ||
142 | - // isDragging = true; | ||
143 | - // startX = e.clientX; | ||
144 | - // startY = e.clientY; | ||
145 | - // // 获取 me-root 元素当前的位置 | ||
146 | - // const draggableStyle = window.getComputedStyle(draggableElement); | ||
147 | - // initialLeft = parseInt(draggableStyle.left) || 0; | ||
148 | - // initialTop = parseInt(draggableStyle.top) || 0; | ||
149 | - // // 确保元素可以移动 | ||
150 | - // draggableElement.style.position = 'absolute'; | ||
151 | - // }); | ||
152 | - // // 鼠标移动事件 | ||
153 | - // document.addEventListener('mousemove', (e) => { | ||
154 | - // if (isDragging) { | ||
155 | - // const currentX = e.clientX; | ||
156 | - // const currentY = e.clientY; | ||
157 | - // // 计算偏移量 | ||
158 | - // const diffX = currentX - startX; | ||
159 | - // const diffY = currentY - startY; | ||
160 | - // // 更新 me-root 元素位置 | ||
161 | - // draggableElement.style.left = `${initialLeft + diffX}px`; | ||
162 | - // draggableElement.style.top = `${initialTop + diffY}px`; | ||
163 | - // // 检查 meMain 是否存在,如果存在则更新其位置 | ||
164 | - // const meMain = meNode?.querySelector('me-main') as HTMLElement | null; | ||
165 | - // if (meMain) { | ||
166 | - // // 获取 meMain 元素当前的位置 | ||
167 | - // const meMainStyle = window.getComputedStyle(meMain); | ||
168 | - // const meMainInitialLeft = parseInt(meMainStyle.left) || 0; | ||
169 | - // const meMainInitialTop = parseInt(meMainStyle.top) || 0; | ||
170 | - // // 更新 meMain 元素位置 | ||
171 | - // meMain.style.position = 'absolute'; | ||
172 | - // meMain.style.left = `${meMainInitialLeft + diffX}px`; | ||
173 | - // meMain.style.top = `${meMainInitialTop + diffY}px`; | ||
174 | - // } | ||
175 | - // } | ||
176 | - // }); | ||
177 | - | ||
178 | - // // 鼠标释放事件 | ||
179 | - // document.addEventListener('mouseup', () => { | ||
180 | - // isDragging = false; | ||
181 | - // }); | ||
182 | - // } else { | ||
183 | - // console.error('未找到 me-root 元素'); | ||
184 | - // } | ||
185 | - | ||
186 | return ( | 119 | return ( |
187 | <> | 120 | <> |
188 | <MindSiderBar | 121 | <MindSiderBar |
@@ -12,32 +12,15 @@ import { CreatorType, DocmeeUI } from "@docmee/sdk-ui"; | @@ -12,32 +12,15 @@ import { CreatorType, DocmeeUI } from "@docmee/sdk-ui"; | ||
12 | import { getClientConfig } from "@/app/config/client"; | 12 | import { getClientConfig } from "@/app/config/client"; |
13 | import { useAppConfig, useAccessStore } from "@/app/store"; | 13 | import { useAppConfig, useAccessStore } from "@/app/store"; |
14 | import type { generateError, generateOutline } from "@/app/types/docmee"; | 14 | import type { generateError, generateOutline } from "@/app/types/docmee"; |
15 | +import type { LocalData } from "@/app/types/zuotang"; | ||
16 | +import { useLocalStorage } from "../bgRemoval"; | ||
15 | import axios from "axios"; | 17 | import axios from "axios"; |
18 | + | ||
16 | import ReturnIcon from "@/app/icons/return.svg"; | 19 | import ReturnIcon from "@/app/icons/return.svg"; |
17 | import MinIcon from "@/app/icons/min.svg"; | 20 | import MinIcon from "@/app/icons/min.svg"; |
18 | import MaxIcon from "@/app/icons/max.svg"; | 21 | import MaxIcon from "@/app/icons/max.svg"; |
19 | import { message } from "antd"; | 22 | import { message } from "antd"; |
20 | 23 | ||
21 | -// 错误消息映射 | ||
22 | -const errorMap: { [key: number]: string } = { | ||
23 | - [-1]: "操作失败", | ||
24 | - [88]: "功能受限(积分已用完 或 非VIP)", | ||
25 | - [98]: "认证失败(检查token是否过期)", | ||
26 | - [99]: "登录过期", | ||
27 | - [1001]: "数据不存在", | ||
28 | - [1002]: "数据访问异常", | ||
29 | - [1003]: "无权限访问", | ||
30 | - [1006]: "内容涉及敏感信息", | ||
31 | - [1009]: "AI服务异常", | ||
32 | - [1010]: "你的次数已用完", | ||
33 | - [1012]: "请求太频繁,限流", | ||
34 | -}; | ||
35 | - | ||
36 | -// 获取错误消息的函数 | ||
37 | -const getErrorMessage = (errorCode: number): string => { | ||
38 | - return errorMap[errorCode] || `未知错误(错误码:${errorCode})`; | ||
39 | -}; | ||
40 | - | ||
41 | export function PowerPoint() { | 24 | export function PowerPoint() { |
42 | const accessStore = useAccessStore(); | 25 | const accessStore = useAccessStore(); |
43 | const containerRef = useRef<HTMLDivElement>(null); | 26 | const containerRef = useRef<HTMLDivElement>(null); |
@@ -48,20 +31,23 @@ export function PowerPoint() { | @@ -48,20 +31,23 @@ export function PowerPoint() { | ||
48 | const showMaxIcon = !isMobileScreen && !clientConfig?.isApp; | 31 | const showMaxIcon = !isMobileScreen && !clientConfig?.isApp; |
49 | const config = useAppConfig(); | 32 | const config = useAppConfig(); |
50 | const scrollRef = useRef<HTMLDivElement>(null); | 33 | const scrollRef = useRef<HTMLDivElement>(null); |
34 | + const { updateLocalUsage, getLocalData } = useLocalStorage(); | ||
35 | + const query = useLocation(); //获取路由参数 | ||
36 | + const { msg, pptMessage } = query.state || {}; //获取路由参数 | ||
51 | 37 | ||
52 | - const query = useLocation(); | ||
53 | - const { msg, pptMessage } = query.state || {}; | ||
54 | - | 38 | + const localData: LocalData = getLocalData(accessStore.accessCode); //获取限制次数 |
55 | const getToken = async () => { | 39 | const getToken = async () => { |
56 | if (!accessStore.accessCode) { | 40 | if (!accessStore.accessCode) { |
57 | return message.error("请先输入登录秘钥"); | 41 | return message.error("请先输入登录秘钥"); |
58 | } | 42 | } |
59 | const res = await fetch("/api/ppt/createApiToken", { | 43 | const res = await fetch("/api/ppt/createApiToken", { |
60 | method: "POST", | 44 | method: "POST", |
61 | - body: JSON.stringify(accessStore.accessCode), | 45 | + body: JSON.stringify({ |
46 | + accessCode: accessStore.accessCode, | ||
47 | + max_use: localData.pptMaxUses, | ||
48 | + }), | ||
62 | }); | 49 | }); |
63 | const data = await res.json(); | 50 | const data = await res.json(); |
64 | - console.log(data); | ||
65 | if (data.status == 200) { | 51 | if (data.status == 200) { |
66 | return data.data.data.token; | 52 | return data.data.data.token; |
67 | } else { | 53 | } else { |
@@ -89,7 +75,7 @@ export function PowerPoint() { | @@ -89,7 +75,7 @@ export function PowerPoint() { | ||
89 | container: containerRef.current, | 75 | container: containerRef.current, |
90 | page: "creator-v2", | 76 | page: "creator-v2", |
91 | token: token, | 77 | token: token, |
92 | - mode: "light", | 78 | + mode: config.theme as "dark" | "light", |
93 | lang: "zh", | 79 | lang: "zh", |
94 | isMobile: isMobileScreen, | 80 | isMobile: isMobileScreen, |
95 | creatorData: { | 81 | creatorData: { |
@@ -99,19 +85,52 @@ export function PowerPoint() { | @@ -99,19 +85,52 @@ export function PowerPoint() { | ||
99 | }); | 85 | }); |
100 | if (msg) { | 86 | if (msg) { |
101 | docmee.on("mounted", (msg: generateOutline) => { | 87 | docmee.on("mounted", (msg: generateOutline) => { |
88 | + if (localData.pptMaxUses == "0") { | ||
89 | + message.error("你的免费次数已用完"); | ||
90 | + return false; | ||
91 | + } | ||
102 | docmee.changeCreatorData({ text: pptMessage }, true); | 92 | docmee.changeCreatorData({ text: pptMessage }, true); |
103 | }); | 93 | }); |
104 | } | 94 | } |
105 | docmee.on("beforeGenerate", (msg: generateOutline) => { | 95 | docmee.on("beforeGenerate", (msg: generateOutline) => { |
96 | + //生成大纲事件 | ||
97 | + console.log(localData.pptMaxUses); | ||
98 | + if (localData.pptMaxUses == "0") { | ||
99 | + message.error("你的免费次数已用完"); | ||
100 | + return false; | ||
101 | + } | ||
106 | axios.post("https://docmee.cn/api/ppt/v2/generateContent", msg, { | 102 | axios.post("https://docmee.cn/api/ppt/v2/generateContent", msg, { |
107 | headers: { token: token }, | 103 | headers: { token: token }, |
108 | }); | 104 | }); |
109 | }); | 105 | }); |
110 | - docmee.on("error", (msg: generateError) => { | 106 | + |
107 | + docmee.on("charge", (msg: string) => { | ||
108 | + //PPT生成后扣费 | ||
109 | + // 解析 pptMaxUses 为数字 | ||
110 | + let max_use = parseInt(localData.pptMaxUses, 10); | ||
111 | + // 校验解析结果是否为有效数字 | ||
112 | + if (isNaN(max_use)) { | ||
113 | + max_use = 0; // 如果解析失败,设置默认值为 0 | ||
114 | + } | ||
115 | + max_use = max_use - 1; | ||
116 | + if (max_use < 0) { | ||
117 | + max_use = 0; | ||
118 | + } | ||
119 | + updateLocalUsage(accessStore.accessCode, undefined, max_use); | ||
120 | + }); | ||
121 | + | ||
122 | + docmee.on("error", async (msg: generateError) => { | ||
123 | + //请求错误事件 | ||
124 | + console.log(msg); | ||
111 | if (msg.data.code == 98) { | 125 | if (msg.data.code == 98) { |
126 | + // message.error('token失效,请重试') | ||
127 | + const token = await getToken(); | ||
112 | docmee.updateToken(token); | 128 | docmee.updateToken(token); |
129 | + return; | ||
113 | } | 130 | } |
114 | - message.error(msg.data.message); | 131 | + message.error( |
132 | + msg.data.code == 403 ? "请检查登录密码或网络" : msg.data.message, | ||
133 | + ); | ||
115 | }); | 134 | }); |
116 | return () => docmee.destroy(); | 135 | return () => docmee.destroy(); |
117 | }; | 136 | }; |
@@ -685,7 +685,6 @@ export function Settings() { | @@ -685,7 +685,6 @@ export function Settings() { | ||
685 | type="text" | 685 | type="text" |
686 | placeholder={Locale.Settings.Access.AccessCode.Placeholder} | 686 | placeholder={Locale.Settings.Access.AccessCode.Placeholder} |
687 | onChange={(e) => { | 687 | onChange={(e) => { |
688 | - console.log("更改密码了"); | ||
689 | if (localStorage.getItem("token")) { | 688 | if (localStorage.getItem("token")) { |
690 | localStorage.removeItem("token"); | 689 | localStorage.removeItem("token"); |
691 | } //20250328新增更改访问密码删除本地储存token | 690 | } //20250328新增更改访问密码删除本地储存token |
@@ -100,6 +100,7 @@ declare global { | @@ -100,6 +100,7 @@ declare global { | ||
100 | 100 | ||
101 | DOCMEE_URL: string; | 101 | DOCMEE_URL: string; |
102 | DOCMEE_API_KEY: string; | 102 | DOCMEE_API_KEY: string; |
103 | + DOCMEE_MAX_DAILY_USES: number; | ||
103 | 104 | ||
104 | NXET_PUBLIC_BGREMOVAL_MODEL: string; | 105 | NXET_PUBLIC_BGREMOVAL_MODEL: string; |
105 | NXET_PUBLIC_WRITING_MODEL: string; | 106 | NXET_PUBLIC_WRITING_MODEL: string; |
@@ -866,7 +866,7 @@ const cn = { | @@ -866,7 +866,7 @@ const cn = { | ||
866 | reqErr: "请求失败", | 866 | reqErr: "请求失败", |
867 | selectImg: "请选择图片", | 867 | selectImg: "请选择图片", |
868 | code: "请先输入访问密码", | 868 | code: "请先输入访问密码", |
869 | - prompt: "请输入背景提示词", | 869 | + prompt: "请输入提示词", |
870 | resultErr: "结果图片加载失败", | 870 | resultErr: "结果图片加载失败", |
871 | downLoadErr: "请先完成图片处理", | 871 | downLoadErr: "请先完成图片处理", |
872 | statuErr: "状态查询失败", | 872 | statuErr: "状态查询失败", |
1 | -export type FileProps={ | ||
2 | - fileData: Blob | null; | ||
3 | - setFileData: React.Dispatch<React.SetStateAction<Blob | null>>; | ||
4 | - previewUrl: string | null; | ||
5 | - setPreviewUrl: React.Dispatch<React.SetStateAction<string | null>>; | ||
6 | - isLoading:boolean; | ||
7 | - setIsLoading: React.Dispatch<React.SetStateAction<boolean>>; | ||
8 | -} | 1 | +export type FileProps = { |
2 | + fileData: Blob | null; | ||
3 | + setFileData: React.Dispatch<React.SetStateAction<Blob | null>>; | ||
4 | + previewUrl: string | null; | ||
5 | + setPreviewUrl: React.Dispatch<React.SetStateAction<string | null>>; | ||
6 | + isLoading: boolean; | ||
7 | + setIsLoading: React.Dispatch<React.SetStateAction<boolean>>; | ||
8 | +}; | ||
9 | 9 | ||
10 | -export type LocalData={ | ||
11 | - date:string | ||
12 | - maxDailyUses:string | ||
13 | -} | 10 | +export type LocalData = { |
11 | + date: string; | ||
12 | + maxDailyUses: string; | ||
13 | + pptMaxUses: string; | ||
14 | +}; | ||
14 | 15 | ||
16 | +export type CreateTaskResponse = { | ||
17 | + status: number; | ||
18 | + message: string; | ||
19 | + data: { | ||
20 | + task_id: string; | ||
21 | + }; | ||
22 | + maxDailyUses?: number; | ||
23 | +}; | ||
15 | 24 | ||
16 | -export type CreateTaskResponse={ | ||
17 | - status: number; | ||
18 | - message: string; | ||
19 | - data: { | ||
20 | - task_id: string; | ||
21 | - }; | ||
22 | - maxDailyUses?:number; | ||
23 | -} | ||
24 | - | ||
25 | -export type GetTaskResponse={ | ||
26 | - status: number; | ||
27 | - message: string; | ||
28 | - data: { | ||
29 | - err_info: string; //错误信息 | ||
30 | - image: string; //抠图完成后的图片URL | ||
31 | - image_height: number; //抠图完成后的图片高 | ||
32 | - image_width: number; //抠图完成后的图片宽 | ||
33 | - output_type: number; //返回图片 1为返回图片和蒙版 2为图片 3为蒙版 | ||
34 | - result_type: string; //图片前景类型 | ||
35 | - return_type: number; //返回图片的类型 1为图片URL 2为base64 | ||
36 | - type: string; //图片前景类型 | ||
37 | - task_id: string; //任务队列ID | ||
38 | - state:number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。 | ||
39 | - state_detail: string; //结果为Completed表示转换完成 | ||
40 | - }; | ||
41 | -} | ||
42 | -export type GetGenerateTaskResponse={ | ||
43 | - status: number; | ||
44 | - message: string; | ||
45 | - data: { | ||
46 | - /**错误信息 */ | ||
47 | - err_info: string; | ||
48 | - /**抠图完成后的图片URL */ | ||
49 | - image_1: string; | ||
50 | - /**抠图完成后的图片高 */ | ||
51 | - image_height: number; | ||
52 | - /**抠图完成后的图片宽 */ | ||
53 | - image_width: number; | ||
54 | - /**返回图片 1为返回图片和蒙版 2为图片 3为蒙版 */ | ||
55 | - output_type: number; | ||
56 | - /**图片前景类型 */ | ||
57 | - result_type: string; | ||
58 | - /**返回图片的类型 1为图片URL 2为base64 */ | ||
59 | - return_type: number; | ||
60 | - /**图片前景类型 */ | ||
61 | - type: string; | ||
62 | - /**任务队列ID */ | ||
63 | - task_id: string; | ||
64 | - state:number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。 | ||
65 | - /**结果为Completed表示转换完成 */ | ||
66 | - state_detail: string; | ||
67 | - }; | ||
68 | -} | ||
25 | +export type GetTaskResponse = { | ||
26 | + status: number; | ||
27 | + message: string; | ||
28 | + data: { | ||
29 | + err_info: string; //错误信息 | ||
30 | + image: string; //抠图完成后的图片URL | ||
31 | + image_height: number; //抠图完成后的图片高 | ||
32 | + image_width: number; //抠图完成后的图片宽 | ||
33 | + output_type: number; //返回图片 1为返回图片和蒙版 2为图片 3为蒙版 | ||
34 | + result_type: string; //图片前景类型 | ||
35 | + return_type: number; //返回图片的类型 1为图片URL 2为base64 | ||
36 | + type: string; //图片前景类型 | ||
37 | + task_id: string; //任务队列ID | ||
38 | + state: number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。 | ||
39 | + state_detail: string; //结果为Completed表示转换完成 | ||
40 | + }; | ||
41 | +}; | ||
42 | +export type GetGenerateTaskResponse = { | ||
43 | + status: number; | ||
44 | + message: string; | ||
45 | + data: { | ||
46 | + /**错误信息 */ | ||
47 | + err_info: string; | ||
48 | + /**抠图完成后的图片URL */ | ||
49 | + image_1: string; | ||
50 | + /**抠图完成后的图片高 */ | ||
51 | + image_height: number; | ||
52 | + /**抠图完成后的图片宽 */ | ||
53 | + image_width: number; | ||
54 | + /**返回图片 1为返回图片和蒙版 2为图片 3为蒙版 */ | ||
55 | + output_type: number; | ||
56 | + /**图片前景类型 */ | ||
57 | + result_type: string; | ||
58 | + /**返回图片的类型 1为图片URL 2为base64 */ | ||
59 | + return_type: number; | ||
60 | + /**图片前景类型 */ | ||
61 | + type: string; | ||
62 | + /**任务队列ID */ | ||
63 | + task_id: string; | ||
64 | + state: number; //任务状态码。1 为成功,大于 1 为处理中,小于 0 为失败。 | ||
65 | + /**结果为Completed表示转换完成 */ | ||
66 | + state_detail: string; | ||
67 | + }; | ||
68 | +}; |
-
请 注册 或 登录 后发表评论