正在显示
21 个修改的文件
包含
631 行增加
和
154 行删除
@@ -16,7 +16,10 @@ import { handle as xaiHandler } from "../../xai"; | @@ -16,7 +16,10 @@ import { handle as xaiHandler } from "../../xai"; | ||
16 | import { handle as chatglmHandler } from "../../glm"; | 16 | import { handle as chatglmHandler } from "../../glm"; |
17 | import { handle as proxyHandler } from "../../proxy"; | 17 | import { handle as proxyHandler } from "../../proxy"; |
18 | //20250321 新增佐糖API | 18 | //20250321 新增佐糖API |
19 | -import {handle as zuotangHandler} from "../../zuotang"; | 19 | +import { handle as zuotangHandler } from "../../zuotang"; |
20 | +//20250328新增PPT API | ||
21 | +import { handle as docmeeHandler } from "../../docmee"; | ||
22 | +import { handle as generateImgHandler } from "../../generateImg"; | ||
20 | 23 | ||
21 | async function handle( | 24 | async function handle( |
22 | req: NextRequest, | 25 | req: NextRequest, |
@@ -55,7 +58,11 @@ async function handle( | @@ -55,7 +58,11 @@ async function handle( | ||
55 | case ApiPath.OpenAI: | 58 | case ApiPath.OpenAI: |
56 | return openaiHandler(req, { params }); | 59 | return openaiHandler(req, { params }); |
57 | case ApiPath.ZuoTang: | 60 | case ApiPath.ZuoTang: |
58 | - return zuotangHandler(req,{ params }) | 61 | + return zuotangHandler(req, { params }); |
62 | + case ApiPath.Docmee: | ||
63 | + return docmeeHandler(req, { params }); | ||
64 | + case ApiPath.OpenAiImg: | ||
65 | + return generateImgHandler(req, { params }); | ||
59 | default: | 66 | default: |
60 | return proxyHandler(req, { params }); | 67 | return proxyHandler(req, { params }); |
61 | } | 68 | } |
app/api/docmee.ts
0 → 100644
1 | +import { getServerSideConfig } from "@/app/config/server"; | ||
2 | +import { NextRequest, NextResponse } from "next/server"; | ||
3 | + | ||
4 | +export async function handle( | ||
5 | + req: NextRequest, | ||
6 | + { params }: { params: { path: string[] } }, | ||
7 | +) { | ||
8 | + const config = getServerSideConfig(); | ||
9 | + const baseUrl = config.docmeeUrl; | ||
10 | + const subPath = params.path.join("/"); | ||
11 | + // if(subPath==='createApiToken'){const reqUrl = `${baseUrl}/api/user/${subPath}`;} | ||
12 | + const reqUrl = `${baseUrl}/api/user/${subPath}`; | ||
13 | + console.log(reqUrl); | ||
14 | + try { | ||
15 | + // 获取 accessCode | ||
16 | + const body = await new Response(req.body).text(); | ||
17 | + const uid = JSON.parse(body); | ||
18 | + const headers = new Headers({ | ||
19 | + "Api-Key": config.docmeeApiKey, | ||
20 | + "Content-Type": "application/json", | ||
21 | + }); | ||
22 | + console.log("********************" + config.docmeeApiKey); | ||
23 | + // 使用 async/await 处理 fetch 请求 | ||
24 | + const response = await fetch(reqUrl, { | ||
25 | + headers, | ||
26 | + method: "POST", | ||
27 | + body: JSON.stringify({ uid: uid, limit: config.docmeeMaxDailyUses }), | ||
28 | + }); | ||
29 | + if (!response.ok) { | ||
30 | + throw new Error( | ||
31 | + `HTTP error! status: ${response.status} ${response.text()}`, | ||
32 | + ); | ||
33 | + } | ||
34 | + const data = await response.json(); | ||
35 | + console.log("-----------------data", data); | ||
36 | + // 返回固定的 token | ||
37 | + return NextResponse.json({ | ||
38 | + data: data, | ||
39 | + status: 200, | ||
40 | + }); | ||
41 | + } catch (error) { | ||
42 | + console.error("处理请求时出错:", error); | ||
43 | + return NextResponse.json({ | ||
44 | + data: "处理请求时出错", | ||
45 | + status: 500, | ||
46 | + }); | ||
47 | + } | ||
48 | +} |
app/api/generateImg.ts
0 → 100644
1 | +import { getServerSideConfig } from "@/app/config/server"; | ||
2 | +import { NextRequest, NextResponse } from "next/server"; | ||
3 | + | ||
4 | +export async function handle( | ||
5 | + req: NextRequest, | ||
6 | + { params }: { params: { path: string[] } }, | ||
7 | +) { | ||
8 | + const config = getServerSideConfig(); | ||
9 | + const baseUrl = config.baseUrl; | ||
10 | + const subPath = params.path.join("/"); | ||
11 | + // if(subPath==='createApiToken'){const reqUrl = `${baseUrl}/api/user/${subPath}`;} | ||
12 | + const reqUrl = `${baseUrl}/v1/images/${subPath}`; | ||
13 | + const apiKey = config.apiKey; | ||
14 | + try { | ||
15 | + const headers = new Headers({ | ||
16 | + Authorization: `Bearer ${apiKey}`, | ||
17 | + "Content-Type": "application/json", | ||
18 | + }); | ||
19 | + const body = await new Response(req.body).text(); | ||
20 | + const prompt = JSON.parse(body); | ||
21 | + const response = await fetch(reqUrl, { | ||
22 | + headers, | ||
23 | + method: "POST", | ||
24 | + body: JSON.stringify({ | ||
25 | + model: "dall-e-3", | ||
26 | + prompt: prompt, | ||
27 | + n: 1, | ||
28 | + size: "1024x1024", | ||
29 | + }), | ||
30 | + }); | ||
31 | + const data = await response.json(); | ||
32 | + return NextResponse.json({ | ||
33 | + data: data, | ||
34 | + status: 200, | ||
35 | + }); | ||
36 | + } catch { | ||
37 | + return NextResponse.json({ | ||
38 | + data: "处理请求时出错", | ||
39 | + status: 500, | ||
40 | + }); | ||
41 | + } | ||
42 | +} |
@@ -30,7 +30,6 @@ export async function handle( | @@ -30,7 +30,6 @@ export async function handle( | ||
30 | req: NextRequest, | 30 | req: NextRequest, |
31 | { params }: { params: { path: string[] } }, | 31 | { params }: { params: { path: string[] } }, |
32 | ) { | 32 | ) { |
33 | - console.log("------------------------------------进入opanai handle") | ||
34 | console.log("[OpenAI Route] params ", params); | 33 | console.log("[OpenAI Route] params ", params); |
35 | 34 | ||
36 | if (req.method === "OPTIONS") { | 35 | if (req.method === "OPTIONS") { |
@@ -61,7 +60,6 @@ export async function handle( | @@ -61,7 +60,6 @@ export async function handle( | ||
61 | 60 | ||
62 | try { | 61 | try { |
63 | const response = await requestOpenai(req); | 62 | const response = await requestOpenai(req); |
64 | - | ||
65 | // list models | 63 | // list models |
66 | if (subpath === OpenaiPath.ListModelPath && response.status === 200) { | 64 | if (subpath === OpenaiPath.ListModelPath && response.status === 200) { |
67 | const resJson = (await response.json()) as OpenAIListModelResponse; | 65 | const resJson = (await response.json()) as OpenAIListModelResponse; |
1 | import { getServerSideConfig } from "@/app/config/server"; | 1 | import { getServerSideConfig } from "@/app/config/server"; |
2 | -import type { CreateTaskResponse, GetTaskResponse, GetGenerateTaskResponse, LocalData } from "../types/zuotang"; | 2 | +import type { |
3 | + CreateTaskResponse, | ||
4 | + GetTaskResponse, | ||
5 | + GetGenerateTaskResponse, | ||
6 | + LocalData, | ||
7 | +} from "../types/zuotang"; | ||
3 | import { NextRequest, NextResponse } from "next/server"; | 8 | import { NextRequest, NextResponse } from "next/server"; |
4 | -import { error } from "console"; | ||
5 | -import { message } from "antd"; | ||
6 | import md5 from "spark-md5"; | 9 | import md5 from "spark-md5"; |
7 | 10 | ||
8 | - | ||
9 | // 类型守卫函数 | 11 | // 类型守卫函数 |
10 | function isString(value: unknown): value is string { | 12 | function isString(value: unknown): value is string { |
11 | - return typeof value === "string"; | 13 | + return typeof value === "string"; |
12 | } | 14 | } |
13 | 15 | ||
14 | // 统一错误响应生成器 | 16 | // 统一错误响应生成器 |
15 | function createErrorResponse( | 17 | function createErrorResponse( |
16 | - message: string, | ||
17 | - status: number, | ||
18 | - maxDailyUses?: number | 18 | + message: string, |
19 | + status: number, | ||
20 | + maxDailyUses?: number, | ||
19 | ): NextResponse<CreateTaskResponse> { | 21 | ): NextResponse<CreateTaskResponse> { |
20 | - const response: CreateTaskResponse = { | ||
21 | - status, | ||
22 | - message, | ||
23 | - data: { task_id: "" }, | ||
24 | - maxDailyUses, | ||
25 | - }; | ||
26 | - return NextResponse.json(response, { status, headers: { "Content-Type": "application/json" } }); | 22 | + const response: CreateTaskResponse = { |
23 | + status, | ||
24 | + message, | ||
25 | + data: { task_id: "" }, | ||
26 | + maxDailyUses, | ||
27 | + }; | ||
28 | + return NextResponse.json(response, { | ||
29 | + status, | ||
30 | + headers: { "Content-Type": "application/json" }, | ||
31 | + }); | ||
27 | } | 32 | } |
28 | 33 | ||
29 | // 处理每日使用限制逻辑 | 34 | // 处理每日使用限制逻辑 |
30 | function parseDailyUsage(allowNum: string, configMax: number): number { | 35 | function parseDailyUsage(allowNum: string, configMax: number): number { |
31 | - if (allowNum === "first") return configMax; | ||
32 | - const parsed = parseInt(allowNum, 10); | ||
33 | - return Number.isNaN(parsed) ? configMax : parsed; | 36 | + if (allowNum === "first") return configMax; |
37 | + const parsed = parseInt(allowNum, 10); | ||
38 | + return Number.isNaN(parsed) ? configMax : parsed; | ||
34 | } | 39 | } |
35 | 40 | ||
36 | - | ||
37 | export async function handle( | 41 | export async function handle( |
38 | - req: NextRequest, | ||
39 | - { params }: { params: { path: string[] } } | 42 | + req: NextRequest, |
43 | + { params }: { params: { path: string[] } }, | ||
40 | ) { | 44 | ) { |
41 | - const config = getServerSideConfig(); | ||
42 | - const baseUrl = config.bgRemovalUrl; | ||
43 | - const subPath = params.path.join("/"); | ||
44 | - const reqUrl = `${baseUrl}/api/tasks/${subPath}`; | ||
45 | - | ||
46 | - try { | ||
47 | - if (req.method === "POST") { | ||
48 | - const formData = await req.formData(); | ||
49 | - | ||
50 | - // 验证访问码 | ||
51 | - const accessCode = formData.get("accessCode"); | ||
52 | - if (!isString(accessCode) || !config.codes.has(md5.hash(accessCode))) { | ||
53 | - return createErrorResponse("无效访问密码!", 401); | ||
54 | - } | ||
55 | - | ||
56 | - // 解析使用限制数据 | ||
57 | - const localData = formData.get("localData"); | ||
58 | - if (!isString(localData)) { | ||
59 | - return createErrorResponse("无效请求参数", 400); | ||
60 | - } | ||
61 | - | ||
62 | - const localDataObj: LocalData = JSON.parse(localData); | ||
63 | - const maxDailyUses = parseDailyUsage(localDataObj.maxDailyUses, config.maxDailyUses); | ||
64 | - | ||
65 | - if (maxDailyUses <= 0) { | ||
66 | - return createErrorResponse("今日次数已用完!", 429, 0); | ||
67 | - } | ||
68 | - | ||
69 | - // 准备API请求 | ||
70 | - const imageFile = formData.get("image_file"); | ||
71 | - if (!(imageFile instanceof Blob)) { | ||
72 | - return createErrorResponse("无效图片文件", 400); | ||
73 | - } | ||
74 | - | ||
75 | - const headers = new Headers({ "X-API-KEY": config.bgRemovalApiKey }); | ||
76 | - const newFormData = new FormData(); | ||
77 | - newFormData.append("image_file", imageFile); | ||
78 | - | ||
79 | - if (subPath === "visual/r-background") { | ||
80 | - newFormData.append("batch_size", "1"); | ||
81 | - const prompt = formData.get("prompt") as string; | ||
82 | - const trimmedPrompt = prompt ? prompt.trim() : null; | ||
83 | - if (!trimmedPrompt) { | ||
84 | - return createErrorResponse("背景提示词不能为空!", 400); | ||
85 | - } | ||
86 | - newFormData.append("prompt", trimmedPrompt); | ||
87 | - } | ||
88 | - | ||
89 | - const response = await fetch(reqUrl, { | ||
90 | - headers, | ||
91 | - method: "POST", | ||
92 | - body: newFormData, | ||
93 | - }); | ||
94 | - | ||
95 | - if (!response.ok) { | ||
96 | - throw new Error(`API请求失败: ${response.statusText}`); | ||
97 | - } | ||
98 | - | ||
99 | - const responseData: CreateTaskResponse = await response.json(); | ||
100 | - responseData.maxDailyUses = maxDailyUses - 1; | ||
101 | - | ||
102 | - return NextResponse.json(responseData, { | ||
103 | - status: response.status, | ||
104 | - headers: { "Content-Type": "application/json" }, | ||
105 | - }); | ||
106 | - | ||
107 | - } else if (req.method === "GET") { | ||
108 | - const headers = { "X-API-KEY": config.bgRemovalApiKey }; | ||
109 | - const response = await fetch(reqUrl, { headers }); | ||
110 | - | ||
111 | - if (!response.ok) { | ||
112 | - throw new Error(`API请求失败: ${response.statusText}`); | ||
113 | - } | ||
114 | - | ||
115 | - const isVisualRoute = subPath.includes("visual/r-background"); | ||
116 | - const responseData = isVisualRoute | ||
117 | - ? (await response.json() as GetTaskResponse) | ||
118 | - : (await response.json() as GetGenerateTaskResponse); | ||
119 | - | ||
120 | - return NextResponse.json(responseData, { | ||
121 | - status: response.status, | ||
122 | - headers: { "Content-Type": "application/json" }, | ||
123 | - }); | 45 | + const config = getServerSideConfig(); |
46 | + const baseUrl = config.bgRemovalUrl; | ||
47 | + const subPath = params.path.join("/"); | ||
48 | + const reqUrl = `${baseUrl}/api/tasks/${subPath}`; | ||
49 | + | ||
50 | + try { | ||
51 | + if (req.method === "POST") { | ||
52 | + const formData = await req.formData(); | ||
53 | + | ||
54 | + // 验证访问码 | ||
55 | + const accessCode = formData.get("accessCode"); | ||
56 | + if (!isString(accessCode) || !config.codes.has(md5.hash(accessCode))) { | ||
57 | + return createErrorResponse("无效访问密码!", 401); | ||
58 | + } | ||
59 | + // 解析使用限制数据 | ||
60 | + const localData = formData.get("localData"); | ||
61 | + if (!isString(localData)) { | ||
62 | + return createErrorResponse("无效请求参数", 400); | ||
63 | + } | ||
64 | + const localDataObj: LocalData = JSON.parse(localData); | ||
65 | + const maxDailyUses = parseDailyUsage( | ||
66 | + localDataObj.maxDailyUses, | ||
67 | + config.maxDailyUses, | ||
68 | + ); | ||
69 | + | ||
70 | + if (maxDailyUses <= 0) { | ||
71 | + return createErrorResponse("今日次数已用完!", 429, 0); | ||
72 | + } | ||
73 | + | ||
74 | + // 准备API请求 | ||
75 | + const imageFile = formData.get("image_file"); | ||
76 | + if (!(imageFile instanceof Blob)) { | ||
77 | + return createErrorResponse("无效图片文件", 400); | ||
78 | + } | ||
79 | + | ||
80 | + const headers = new Headers({ "X-API-KEY": config.bgRemovalApiKey }); | ||
81 | + const newFormData = new FormData(); | ||
82 | + newFormData.append("image_file", imageFile); | ||
83 | + | ||
84 | + if (subPath === "visual/r-background") { | ||
85 | + newFormData.append("batch_size", "1"); | ||
86 | + const prompt = formData.get("prompt") as string; | ||
87 | + const trimmedPrompt = prompt ? prompt.trim() : null; | ||
88 | + if (!trimmedPrompt) { | ||
89 | + return createErrorResponse("背景提示词不能为空!", 400); | ||
124 | } | 90 | } |
125 | - | ||
126 | - return createErrorResponse("方法不允许", 405); | ||
127 | - | ||
128 | - } catch (error) { | ||
129 | - console.error("请求处理错误:", error); | ||
130 | - return createErrorResponse( | ||
131 | - error instanceof Error ? error.message : "服务器内部错误", | ||
132 | - 500 | ||
133 | - ); | 91 | + newFormData.append("prompt", trimmedPrompt); |
92 | + } | ||
93 | + | ||
94 | + const response = await fetch(reqUrl, { | ||
95 | + headers, | ||
96 | + method: "POST", | ||
97 | + body: newFormData, | ||
98 | + }); | ||
99 | + | ||
100 | + if (!response.ok) { | ||
101 | + throw new Error(`API请求失败: ${response.statusText}`); | ||
102 | + } | ||
103 | + | ||
104 | + const responseData: CreateTaskResponse = await response.json(); | ||
105 | + responseData.maxDailyUses = maxDailyUses - 1; | ||
106 | + | ||
107 | + return NextResponse.json(responseData, { | ||
108 | + status: response.status, | ||
109 | + headers: { "Content-Type": "application/json" }, | ||
110 | + }); | ||
111 | + } else if (req.method === "GET") { | ||
112 | + const headers = { "X-API-KEY": config.bgRemovalApiKey }; | ||
113 | + const response = await fetch(reqUrl, { headers }); | ||
114 | + | ||
115 | + if (!response.ok) { | ||
116 | + throw new Error(`API请求失败: ${response.statusText}`); | ||
117 | + } | ||
118 | + | ||
119 | + const isVisualRoute = subPath.includes("visual/r-background"); | ||
120 | + const responseData = isVisualRoute | ||
121 | + ? ((await response.json()) as GetTaskResponse) | ||
122 | + : ((await response.json()) as GetGenerateTaskResponse); | ||
123 | + | ||
124 | + return NextResponse.json(responseData, { | ||
125 | + status: response.status, | ||
126 | + headers: { "Content-Type": "application/json" }, | ||
127 | + }); | ||
134 | } | 128 | } |
129 | + | ||
130 | + return createErrorResponse("方法不允许", 405); | ||
131 | + } catch (error) { | ||
132 | + console.error("请求处理错误:", error); | ||
133 | + return createErrorResponse( | ||
134 | + error instanceof Error ? error.message : "服务器内部错误", | ||
135 | + 500, | ||
136 | + ); | ||
137 | + } | ||
135 | } | 138 | } |
@@ -278,6 +278,25 @@ export function BgPanel(props: FileProps) { | @@ -278,6 +278,25 @@ export function BgPanel(props: FileProps) { | ||
278 | const { pollTask } = useTaskPoller(); | 278 | const { pollTask } = useTaskPoller(); |
279 | const { updateLocalUsage, getLocalData } = useLocalStorage(); | 279 | const { updateLocalUsage, getLocalData } = useLocalStorage(); |
280 | 280 | ||
281 | + const handleGenerateImg = async () => { | ||
282 | + if (!prompt.trim()) { | ||
283 | + return message.error("请先输入提示词"); | ||
284 | + } | ||
285 | + 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); | ||
293 | + } | ||
294 | + const responseData = await res.json(); | ||
295 | + console.log(responseData.data.data[0]); | ||
296 | + setPreviewUrl(responseData.data.data[0].url); | ||
297 | + setIsLoading(false); | ||
298 | + }; | ||
299 | + | ||
281 | const handleApiRequest = async (endpoint: string) => { | 300 | const handleApiRequest = async (endpoint: string) => { |
282 | if (!previewUrl) { | 301 | if (!previewUrl) { |
283 | message.error(Locale.BgRemoval.error.selectImg); | 302 | message.error(Locale.BgRemoval.error.selectImg); |
@@ -391,6 +410,13 @@ export function BgPanel(props: FileProps) { | @@ -391,6 +410,13 @@ export function BgPanel(props: FileProps) { | ||
391 | <ControlParamItem title={Locale.BgRemoval.subTitle}> | 410 | <ControlParamItem title={Locale.BgRemoval.subTitle}> |
392 | <div className={styles["ai-models"]}> | 411 | <div className={styles["ai-models"]}> |
393 | <IconButton | 412 | <IconButton |
413 | + text={Locale.BgRemoval.generateImg} | ||
414 | + type="primary" | ||
415 | + shadow | ||
416 | + onClick={handleGenerateImg} | ||
417 | + disabled={isLoading} | ||
418 | + /> | ||
419 | + <IconButton | ||
394 | text={Locale.BgRemoval.bgRemoveBtn} | 420 | text={Locale.BgRemoval.bgRemoveBtn} |
395 | type="primary" | 421 | type="primary" |
396 | shadow | 422 | shadow |
@@ -53,6 +53,7 @@ import HeadphoneIcon from "../icons/headphone.svg"; | @@ -53,6 +53,7 @@ import HeadphoneIcon from "../icons/headphone.svg"; | ||
53 | import ExcelIcon from "../icons/excel.svg"; | 53 | import ExcelIcon from "../icons/excel.svg"; |
54 | import WordIcon from "../icons/word.svg"; | 54 | import WordIcon from "../icons/word.svg"; |
55 | import MindIcon from "../icons/mind.svg"; | 55 | import MindIcon from "../icons/mind.svg"; |
56 | +import PptIcon from "../icons/ppt.svg"; | ||
56 | 57 | ||
57 | import { | 58 | import { |
58 | BOT_HELLO, | 59 | BOT_HELLO, |
@@ -1739,6 +1740,11 @@ function _Chat() { | @@ -1739,6 +1740,11 @@ function _Chat() { | ||
1739 | navigate("/mind", { state: { msg: true } }); | 1740 | navigate("/mind", { state: { msg: true } }); |
1740 | } | 1741 | } |
1741 | 1742 | ||
1743 | + //20250328新增PPT导出 | ||
1744 | + function toPowerpoint(pptMessage: string) { | ||
1745 | + navigate("/powerpoint", { state: { pptMessage: pptMessage, msg: true } }); | ||
1746 | + } | ||
1747 | + | ||
1742 | return ( | 1748 | return ( |
1743 | <> | 1749 | <> |
1744 | <div className={styles.chat} key={session.id}> | 1750 | <div className={styles.chat} key={session.id}> |
@@ -2019,6 +2025,15 @@ function _Chat() { | @@ -2019,6 +2025,15 @@ function _Chat() { | ||
2019 | /> | 2025 | /> |
2020 | </> | 2026 | </> |
2021 | )} | 2027 | )} |
2028 | + <ChatAction | ||
2029 | + text={Locale.Chat.Actions.Ppt} | ||
2030 | + icon={<PptIcon />} | ||
2031 | + onClick={() => | ||
2032 | + toPowerpoint( | ||
2033 | + getMessageTextContent(message), | ||
2034 | + ) | ||
2035 | + } | ||
2036 | + /> | ||
2022 | {/* 以上 20250317 新增Word excel导出按钮 */} | 2037 | {/* 以上 20250317 新增Word excel导出按钮 */} |
2023 | {config.ttsConfig.enable && ( | 2038 | {config.ttsConfig.enable && ( |
2024 | <ChatAction | 2039 | <ChatAction |
@@ -86,21 +86,29 @@ const McpMarketPage = dynamic( | @@ -86,21 +86,29 @@ const McpMarketPage = dynamic( | ||
86 | loading: () => <Loading noLogo />, | 86 | loading: () => <Loading noLogo />, |
87 | }, | 87 | }, |
88 | ); | 88 | ); |
89 | -//以下新增思维导图路由,抠图路由 20250319 | 89 | +//以下新增思维导图路由20250319 |
90 | const Mind = dynamic(async () => (await import("./mind")).MindPage, { | 90 | const Mind = dynamic(async () => (await import("./mind")).MindPage, { |
91 | loading: () => <Loading noLogo />, | 91 | loading: () => <Loading noLogo />, |
92 | }); | 92 | }); |
93 | 93 | ||
94 | +//以下新增抠图页面20250319 | ||
94 | const BgRemoval = dynamic(async () => (await import("./bgRemoval")).BgRemoval, { | 95 | const BgRemoval = dynamic(async () => (await import("./bgRemoval")).BgRemoval, { |
95 | loading: () => <Loading noLogo />, | 96 | loading: () => <Loading noLogo />, |
96 | }); | 97 | }); |
97 | - | 98 | +//以下新增写作页面20250325 |
98 | const WritingPage = dynamic( | 99 | const WritingPage = dynamic( |
99 | async () => (await import("./writing")).WritingPage, | 100 | async () => (await import("./writing")).WritingPage, |
100 | { | 101 | { |
101 | loading: () => <Loading noLogo />, | 102 | loading: () => <Loading noLogo />, |
102 | }, | 103 | }, |
103 | ); | 104 | ); |
105 | +//以下新增PPT制作 页面 20250328 | ||
106 | +const PowerPoint = dynamic( | ||
107 | + async () => (await import("./powerpoint")).PowerPoint, | ||
108 | + { | ||
109 | + loading: () => <Loading noLogo />, | ||
110 | + }, | ||
111 | +); | ||
104 | 112 | ||
105 | export function useSwitchTheme() { | 113 | export function useSwitchTheme() { |
106 | const config = useAppConfig(); | 114 | const config = useAppConfig(); |
@@ -189,6 +197,7 @@ function Screen() { | @@ -189,6 +197,7 @@ function Screen() { | ||
189 | const isMind = location.pathname === Path.Mind; | 197 | const isMind = location.pathname === Path.Mind; |
190 | const isBgRemoval = location.pathname === Path.BgRemoval; | 198 | const isBgRemoval = location.pathname === Path.BgRemoval; |
191 | const isWrting = location.pathname === Path.Writing; | 199 | const isWrting = location.pathname === Path.Writing; |
200 | + const isPowerpoint = location.pathname === Path.Powerpoint; | ||
192 | 201 | ||
193 | const isMobileScreen = useMobileScreen(); | 202 | const isMobileScreen = useMobileScreen(); |
194 | const shouldTightBorder = | 203 | const shouldTightBorder = |
@@ -215,6 +224,8 @@ function Screen() { | @@ -215,6 +224,8 @@ function Screen() { | ||
215 | if (isBgRemoval) return <BgRemoval />; | 224 | if (isBgRemoval) return <BgRemoval />; |
216 | //20250325新增AI写作界面 | 225 | //20250325新增AI写作界面 |
217 | if (isWrting) return <WritingPage />; | 226 | if (isWrting) return <WritingPage />; |
227 | + //20250328新增ppt制作页面 | ||
228 | + if (isPowerpoint) return <PowerPoint />; | ||
218 | 229 | ||
219 | return ( | 230 | return ( |
220 | <> | 231 | <> |
@@ -49,6 +49,8 @@ export function MindPage() { | @@ -49,6 +49,8 @@ export function MindPage() { | ||
49 | // 初始化配置项 | 49 | // 初始化配置项 |
50 | const options: Options = { | 50 | const options: Options = { |
51 | el: containerRef.current, | 51 | el: containerRef.current, |
52 | + locale: "zh_CN", | ||
53 | + draggable: true, | ||
52 | contextMenu: true, | 54 | contextMenu: true, |
53 | toolBar: true, | 55 | toolBar: true, |
54 | nodeMenu: true, | 56 | nodeMenu: true, |
@@ -66,7 +68,6 @@ export function MindPage() { | @@ -66,7 +68,6 @@ export function MindPage() { | ||
66 | newMessages, | 68 | newMessages, |
67 | "gpt-4o-mini", | 69 | "gpt-4o-mini", |
68 | ); | 70 | ); |
69 | - console.log("原始响应:", response); | ||
70 | let cleanedContent = response.startsWith("```json") | 71 | let cleanedContent = response.startsWith("```json") |
71 | ? response.substring(8) | 72 | ? response.substring(8) |
72 | : response; | 73 | : response; |
@@ -77,7 +78,6 @@ export function MindPage() { | @@ -77,7 +78,6 @@ export function MindPage() { | ||
77 | ); | 78 | ); |
78 | } | 79 | } |
79 | const parsedData: MindElixirData = JSON.parse(cleanedContent); | 80 | const parsedData: MindElixirData = JSON.parse(cleanedContent); |
80 | - console.log("解析后响应:", parsedData); | ||
81 | // 增强校验逻辑 | 81 | // 增强校验逻辑 |
82 | if ( | 82 | if ( |
83 | !parsedData?.nodeData?.id || | 83 | !parsedData?.nodeData?.id || |
app/components/powerpoint/index.tsx
0 → 100644
1 | +export * from "./powerpoint"; |
app/components/powerpoint/powerpoint.tsx
0 → 100644
1 | +import styles from "./powerpoint.module.scss"; | ||
2 | +import chatStyles from "@/app/components/chat.module.scss"; | ||
3 | +import clsx from "clsx"; | ||
4 | + | ||
5 | +import { IconButton } from "../button"; | ||
6 | +import Locale from "@/app/locales"; | ||
7 | +import { useNavigate, useLocation } from "react-router-dom"; | ||
8 | +import { useMobileScreen } from "@/app/utils"; | ||
9 | +import { Path } from "@/app/constant"; | ||
10 | +import { useRef, useEffect, useMemo } from "react"; | ||
11 | +import { CreatorType, DocmeeUI } from "@docmee/sdk-ui"; | ||
12 | +import { getClientConfig } from "@/app/config/client"; | ||
13 | +import { useAppConfig, useAccessStore } from "@/app/store"; | ||
14 | +import type { generateError, generateOutline } from "@/app/types/docmee"; | ||
15 | +import axios from "axios"; | ||
16 | +import ReturnIcon from "@/app/icons/return.svg"; | ||
17 | +import MinIcon from "@/app/icons/min.svg"; | ||
18 | +import MaxIcon from "@/app/icons/max.svg"; | ||
19 | +import { message } from "antd"; | ||
20 | + | ||
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() { | ||
42 | + const accessStore = useAccessStore(); | ||
43 | + const containerRef = useRef<HTMLDivElement>(null); | ||
44 | + const isPowerpoint = location.pathname === Path.Powerpoint; | ||
45 | + const isMobileScreen = useMobileScreen(); | ||
46 | + const navigate = useNavigate(); | ||
47 | + const clientConfig = useMemo(() => getClientConfig(), []); | ||
48 | + const showMaxIcon = !isMobileScreen && !clientConfig?.isApp; | ||
49 | + const config = useAppConfig(); | ||
50 | + const scrollRef = useRef<HTMLDivElement>(null); | ||
51 | + | ||
52 | + const query = useLocation(); | ||
53 | + const { msg, pptMessage } = query.state || {}; | ||
54 | + | ||
55 | + const getToken = async () => { | ||
56 | + if (!accessStore.accessCode) { | ||
57 | + return message.error("请先输入登录秘钥"); | ||
58 | + } | ||
59 | + const res = await fetch("/api/ppt/createApiToken", { | ||
60 | + method: "POST", | ||
61 | + body: JSON.stringify(accessStore.accessCode), | ||
62 | + }); | ||
63 | + const data = await res.json(); | ||
64 | + console.log(data); | ||
65 | + if (data.status == 200) { | ||
66 | + return data.data.data.token; | ||
67 | + } else { | ||
68 | + message.error(data.error || "获取 token 失败"); | ||
69 | + } | ||
70 | + return ""; | ||
71 | + }; | ||
72 | + | ||
73 | + useEffect(() => { | ||
74 | + const initializeDocmee = async () => { | ||
75 | + let token = localStorage.getItem("token"); | ||
76 | + // 如果本地没有token,则获取新token | ||
77 | + if (!token) { | ||
78 | + token = await getToken(); | ||
79 | + if (!token) { | ||
80 | + message.error("无效token请检查登录密码!"); | ||
81 | + return navigate(Path.Settings); // 跳转回聊天页 | ||
82 | + } | ||
83 | + localStorage.setItem("token", token); | ||
84 | + } | ||
85 | + if (!containerRef.current) { | ||
86 | + throw new Error("Container element not found"); | ||
87 | + } | ||
88 | + const docmee = new DocmeeUI({ | ||
89 | + container: containerRef.current, | ||
90 | + page: "creator-v2", | ||
91 | + token: token, | ||
92 | + mode: "light", | ||
93 | + lang: "zh", | ||
94 | + isMobile: isMobileScreen, | ||
95 | + creatorData: { | ||
96 | + type: CreatorType.AI_GEN, | ||
97 | + subject: "Ai行业未来10年的发展预测", | ||
98 | + }, | ||
99 | + }); | ||
100 | + if (msg) { | ||
101 | + docmee.on("mounted", (msg: generateOutline) => { | ||
102 | + docmee.changeCreatorData({ text: pptMessage }, true); | ||
103 | + }); | ||
104 | + } | ||
105 | + docmee.on("beforeGenerate", (msg: generateOutline) => { | ||
106 | + axios.post("https://docmee.cn/api/ppt/v2/generateContent", msg, { | ||
107 | + headers: { token: token }, | ||
108 | + }); | ||
109 | + }); | ||
110 | + docmee.on("error", (msg: generateError) => { | ||
111 | + if (msg.data.code == 98) { | ||
112 | + docmee.updateToken(token); | ||
113 | + } | ||
114 | + message.error(msg.data.message); | ||
115 | + }); | ||
116 | + return () => docmee.destroy(); | ||
117 | + }; | ||
118 | + initializeDocmee().catch(console.error); | ||
119 | + }, [navigate, isMobileScreen, msg, pptMessage]); | ||
120 | + | ||
121 | + return ( | ||
122 | + <> | ||
123 | + <div style={{ width: "100%", height: "100%" }}> | ||
124 | + <div className={chatStyles.chat} key={"1"}> | ||
125 | + <div className="window-header" data-tauri-drag-region> | ||
126 | + <div | ||
127 | + className={clsx( | ||
128 | + "window-header-title", | ||
129 | + chatStyles["chat-body-title"], | ||
130 | + )} | ||
131 | + > | ||
132 | + <div className={`window-header-main-title`}>PPT制作</div> | ||
133 | + </div> | ||
134 | + <div className={chatStyles["chat-message-actions"]}> | ||
135 | + <div className={chatStyles["chat-input-actions"]}></div> | ||
136 | + </div> | ||
137 | + <div className="window-actions"> | ||
138 | + <IconButton | ||
139 | + aria="返回首页" | ||
140 | + icon={<ReturnIcon />} | ||
141 | + bordered | ||
142 | + title={Locale.Chat.Actions.ChatList} | ||
143 | + onClick={() => navigate(Path.Chat)} | ||
144 | + /> | ||
145 | + {showMaxIcon && ( | ||
146 | + <div className="window-action-button"> | ||
147 | + <IconButton | ||
148 | + aria={Locale.Chat.Actions.FullScreen} | ||
149 | + icon={config.tightBorder ? <MinIcon /> : <MaxIcon />} | ||
150 | + bordered | ||
151 | + onClick={() => { | ||
152 | + config.update( | ||
153 | + (config) => (config.tightBorder = !config.tightBorder), | ||
154 | + ); | ||
155 | + }} | ||
156 | + /> | ||
157 | + </div> | ||
158 | + )} | ||
159 | + </div> | ||
160 | + </div> | ||
161 | + <div className={chatStyles["chat-body"]} ref={scrollRef}> | ||
162 | + <div ref={containerRef} className={styles["container"]}></div> | ||
163 | + </div> | ||
164 | + </div> | ||
165 | + </div> | ||
166 | + </> | ||
167 | + ); | ||
168 | +} |
app/components/powerpoint/ppt-siderbar.tsx
0 → 100644
1 | +import { useMobileScreen } from "@/app/utils"; | ||
2 | +import dynamic from "next/dynamic"; | ||
3 | +import { | ||
4 | + SideBarContainer, | ||
5 | + SideBarHeader, | ||
6 | + useDragSideBar, | ||
7 | + useHotKey, | ||
8 | +} from "@/app/components/sidebar"; | ||
9 | +import { IconButton } from "@/app/components/button"; | ||
10 | +import ReturnIcon from "@/app/icons/return.svg"; | ||
11 | +import HistoryIcon from "@/app/icons/history.svg"; | ||
12 | +import Locale from "@/app/locales"; | ||
13 | +import { Path } from "@/app/constant"; | ||
14 | +import { useNavigate } from "react-router-dom"; | ||
15 | +import SDIcon from "@/app/icons/sd.svg"; | ||
16 | + | ||
17 | +const MindPanel = dynamic( | ||
18 | + async () => (await import("@/app/components/mind")).MindPanel, | ||
19 | + { | ||
20 | + loading: () => null, | ||
21 | + }, | ||
22 | +); | ||
23 | + | ||
24 | +export function PptSiderBar(props: { className?: string }) { | ||
25 | + const isMobileScreen = useMobileScreen(); | ||
26 | + const { onDragStart, shouldNarrow } = useDragSideBar(); | ||
27 | + const navigate = useNavigate(); | ||
28 | + useHotKey(); | ||
29 | + return ( | ||
30 | + <> | ||
31 | + <SideBarContainer | ||
32 | + onDragStart={onDragStart} | ||
33 | + shouldNarrow={shouldNarrow} | ||
34 | + {...props} | ||
35 | + > | ||
36 | + {isMobileScreen ? ( | ||
37 | + <div | ||
38 | + className="window-header" | ||
39 | + data-tauri-drag-region | ||
40 | + style={{ | ||
41 | + paddingLeft: 0, | ||
42 | + paddingRight: 0, | ||
43 | + }} | ||
44 | + > | ||
45 | + <div className="window-actions"> | ||
46 | + <div className="window-action-button"> | ||
47 | + <IconButton | ||
48 | + icon={<ReturnIcon />} | ||
49 | + bordered | ||
50 | + title={Locale.Sd.Actions.ReturnHome} | ||
51 | + onClick={() => navigate(Path.Home)} | ||
52 | + /> | ||
53 | + </div> | ||
54 | + </div> | ||
55 | + <SDIcon width={50} height={50} /> | ||
56 | + <div className="window-actions"> | ||
57 | + <div className="window-action-button"> | ||
58 | + <IconButton | ||
59 | + icon={<HistoryIcon />} | ||
60 | + bordered | ||
61 | + title={Locale.Sd.Actions.History} | ||
62 | + onClick={() => navigate(Path.SdNew)} | ||
63 | + /> | ||
64 | + </div> | ||
65 | + </div> | ||
66 | + </div> | ||
67 | + ) : ( | ||
68 | + <SideBarHeader | ||
69 | + title={ | ||
70 | + <IconButton | ||
71 | + icon={<ReturnIcon />} | ||
72 | + bordered | ||
73 | + title={Locale.Sd.Actions.ReturnHome} | ||
74 | + onClick={() => navigate(Path.Home)} | ||
75 | + /> | ||
76 | + } | ||
77 | + ></SideBarHeader> | ||
78 | + )} | ||
79 | + </SideBarContainer> | ||
80 | + </> | ||
81 | + ); | ||
82 | +} |
@@ -685,6 +685,10 @@ export function Settings() { | @@ -685,6 +685,10 @@ 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")) { | ||
690 | + localStorage.removeItem("token"); | ||
691 | + } //20250328新增更改访问密码删除本地储存token | ||
688 | accessStore.update( | 692 | accessStore.update( |
689 | (access) => (access.accessCode = e.currentTarget.value), | 693 | (access) => (access.accessCode = e.currentTarget.value), |
690 | ); | 694 | ); |
@@ -38,8 +38,9 @@ const DISCOVERY = [ | @@ -38,8 +38,9 @@ const DISCOVERY = [ | ||
38 | { name: "Stable Diffusion", path: Path.Sd }, | 38 | { name: "Stable Diffusion", path: Path.Sd }, |
39 | { name: Locale.SearchChat.Page.Title, path: Path.SearchChat }, | 39 | { name: Locale.SearchChat.Page.Title, path: Path.SearchChat }, |
40 | { name: "智能抠图", path: Path.BgRemoval }, | 40 | { name: "智能抠图", path: Path.BgRemoval }, |
41 | - { name: "AI-writing", path: Path.Writing }, | 41 | + { name: "AI-Writing", path: Path.Writing }, |
42 | { name: "思维导图", path: Path.Mind }, | 42 | { name: "思维导图", path: Path.Mind }, |
43 | + { name: "AI-PPT", path: Path.Powerpoint }, | ||
43 | ]; | 44 | ]; |
44 | 45 | ||
45 | const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, { | 46 | const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, { |
@@ -98,11 +98,14 @@ declare global { | @@ -98,11 +98,14 @@ declare global { | ||
98 | BACKGROUND_REMOVAL_API_KEY: string; | 98 | BACKGROUND_REMOVAL_API_KEY: string; |
99 | MAX_DAILY_USES: number; | 99 | MAX_DAILY_USES: number; |
100 | 100 | ||
101 | - NXET_PUBLIC_BGREMOVAL_MODEL : string; | ||
102 | - NXET_PUBLIC_WRITING_MODEL :string; | 101 | + DOCMEE_URL: string; |
102 | + DOCMEE_API_KEY: string; | ||
103 | + | ||
104 | + NXET_PUBLIC_BGREMOVAL_MODEL: string; | ||
105 | + NXET_PUBLIC_WRITING_MODEL: string; | ||
106 | + } | ||
103 | } | 107 | } |
104 | } | 108 | } |
105 | -} | ||
106 | 109 | ||
107 | const ACCESS_CODES = (function getAccessCodes(): Set<string> { | 110 | const ACCESS_CODES = (function getAccessCodes(): Set<string> { |
108 | const code = process.env.CODE; | 111 | const code = process.env.CODE; |
@@ -124,7 +127,8 @@ function getApiKey(keys?: string) { | @@ -124,7 +127,8 @@ function getApiKey(keys?: string) { | ||
124 | const apiKey = apiKeys[randomIndex]; | 127 | const apiKey = apiKeys[randomIndex]; |
125 | if (apiKey) { | 128 | if (apiKey) { |
126 | console.log( | 129 | console.log( |
127 | - `[Server Config] using ${randomIndex + 1} of ${apiKeys.length | 130 | + `[Server Config] using ${randomIndex + 1} of ${ |
131 | + apiKeys.length | ||
128 | } api key - ${apiKey}`, | 132 | } api key - ${apiKey}`, |
129 | ); | 133 | ); |
130 | } | 134 | } |
@@ -277,8 +281,12 @@ export const getServerSideConfig = () => { | @@ -277,8 +281,12 @@ export const getServerSideConfig = () => { | ||
277 | bgRemovalUrl: process.env.BACKGROUND_REMOVAL_URL ?? "", | 281 | bgRemovalUrl: process.env.BACKGROUND_REMOVAL_URL ?? "", |
278 | bgRemovalApiKey: process.env.BACKGROUND_REMOVAL_API_KEY ?? "", | 282 | bgRemovalApiKey: process.env.BACKGROUND_REMOVAL_API_KEY ?? "", |
279 | maxDailyUses: process.env.MAX_DAILY_USES, | 283 | maxDailyUses: process.env.MAX_DAILY_USES, |
284 | + //20250328新增 ppt api | ||
285 | + docmeeUrl: process.env.DOCMEE_URL, | ||
286 | + docmeeApiKey: process.env.DOCMEE_API_KEY ?? "", | ||
287 | + docmeeMaxDailyUses: process.env.DOCMEE_MAX_DAILY_USES, | ||
280 | 288 | ||
281 | - bgRemovalModel : process.env.NXET_PUBLIC_BGREMOVAL_MODEL, | 289 | + bgRemovalModel: process.env.NXET_PUBLIC_BGREMOVAL_MODEL, |
282 | writingModel: process.env.NXET_PUBLIC_WRITING_MODEL, | 290 | writingModel: process.env.NXET_PUBLIC_WRITING_MODEL, |
283 | }; | 291 | }; |
284 | }; | 292 | }; |
@@ -54,8 +54,9 @@ export enum Path { | @@ -54,8 +54,9 @@ export enum Path { | ||
54 | McpMarket = "/mcp-market", | 54 | McpMarket = "/mcp-market", |
55 | //20250317新增路由 思维导图 | 55 | //20250317新增路由 思维导图 |
56 | Mind = "/mind", | 56 | Mind = "/mind", |
57 | - BgRemoval="/background-removal", | ||
58 | - Writing="/aiWriting" | 57 | + BgRemoval = "/background-removal", |
58 | + Writing = "/aiWriting", | ||
59 | + Powerpoint = "/powerpoint", | ||
59 | } | 60 | } |
60 | 61 | ||
61 | export enum ApiPath { | 62 | export enum ApiPath { |
@@ -77,7 +78,9 @@ export enum ApiPath { | @@ -77,7 +78,9 @@ export enum ApiPath { | ||
77 | DeepSeek = "/api/deepseek", | 78 | DeepSeek = "/api/deepseek", |
78 | SiliconFlow = "/api/siliconflow", | 79 | SiliconFlow = "/api/siliconflow", |
79 | //20250321 新增佐糖API | 80 | //20250321 新增佐糖API |
80 | - ZuoTang="/api/tasks" | 81 | + ZuoTang = "/api/tasks", |
82 | + Docmee = "/api/ppt", | ||
83 | + OpenAiImg = "/api/v1", | ||
81 | } | 84 | } |
82 | ///api/tasks/visual/segmentation | 85 | ///api/tasks/visual/segmentation |
83 | //api/tasks/visual/segmentation/{task_id} | 86 | //api/tasks/visual/segmentation/{task_id} |
1 | -import { title } from "process"; | ||
2 | import { getClientConfig } from "../config/client"; | 1 | import { getClientConfig } from "../config/client"; |
3 | import { SubmitKey } from "../store/config"; | 2 | import { SubmitKey } from "../store/config"; |
4 | import { SAAS_CHAT_UTM_URL } from "@/app/constant"; | 3 | import { SAAS_CHAT_UTM_URL } from "@/app/constant"; |
@@ -62,11 +61,11 @@ const cn = { | @@ -62,11 +61,11 @@ const cn = { | ||
62 | //20250317新增 | 61 | //20250317新增 |
63 | Word: "导出Word", | 62 | Word: "导出Word", |
64 | Excel: "下载Excel", | 63 | Excel: "下载Excel", |
65 | - Pdf:"导出PDF", | ||
66 | - Ppt:"导出PPT", | 64 | + Pdf: "导出PDF", |
65 | + Ppt: "导出PPT", | ||
67 | Mind: "生成思维导图", | 66 | Mind: "生成思维导图", |
68 | Drag: "拖动模式", | 67 | Drag: "拖动模式", |
69 | - ReWrite:"重写", | 68 | + ReWrite: "重写", |
70 | }, | 69 | }, |
71 | Commands: { | 70 | Commands: { |
72 | new: "新建聊天", | 71 | new: "新建聊天", |
@@ -860,26 +859,27 @@ const cn = { | @@ -860,26 +859,27 @@ const cn = { | ||
860 | }, | 859 | }, |
861 | 860 | ||
862 | // 20250320新增 | 861 | // 20250320新增 |
863 | - BgRemoval:{ | ||
864 | - Title:"智能抠图", | ||
865 | - subTitle:"AI抠图", | ||
866 | - error:{ | ||
867 | - reqErr:"请求失败", | ||
868 | - selectImg:"请选择图片", | ||
869 | - code:"请先输入访问密码", | ||
870 | - prompt:"请输入背景提示词", | ||
871 | - resultErr:"结果图片加载失败", | ||
872 | - downLoadErr:"请先完成图片处理", | ||
873 | - statuErr:"状态查询失败", | ||
874 | - timeoutErr:"处理超时,请稍后重试", | ||
875 | - imgLoadingErr:"图片加载失败", | ||
876 | - }, | ||
877 | - success:"图片处理成功,请在一小时内保存图片!", | ||
878 | - bgRemoveBtn:"一键抠图", | ||
879 | - downloadImg:"下载图片", | ||
880 | - generateBg:"生成背景", | ||
881 | - promptTitle:"背景提示词", | ||
882 | - } | 862 | + BgRemoval: { |
863 | + Title: "智能抠图", | ||
864 | + subTitle: "AI抠图", | ||
865 | + error: { | ||
866 | + reqErr: "请求失败", | ||
867 | + selectImg: "请选择图片", | ||
868 | + code: "请先输入访问密码", | ||
869 | + prompt: "请输入背景提示词", | ||
870 | + resultErr: "结果图片加载失败", | ||
871 | + downLoadErr: "请先完成图片处理", | ||
872 | + statuErr: "状态查询失败", | ||
873 | + timeoutErr: "处理超时,请稍后重试", | ||
874 | + imgLoadingErr: "图片加载失败", | ||
875 | + }, | ||
876 | + success: "图片处理成功,请在一小时内保存图片!", | ||
877 | + generateImg: "生成图片", | ||
878 | + bgRemoveBtn: "一键抠图", | ||
879 | + downloadImg: "下载图片", | ||
880 | + generateBg: "生成背景", | ||
881 | + promptTitle: "背景提示词", | ||
882 | + }, | ||
883 | }; | 883 | }; |
884 | 884 | ||
885 | type DeepPartial<T> = T extends object | 885 | type DeepPartial<T> = T extends object |
app/types/docmee.d.ts
0 → 100644
1 | +export type generateOutline = { | ||
2 | + data: { | ||
3 | + fields: { | ||
4 | + enableWeb: boolean; | ||
5 | + length: string; | ||
6 | + prompt: string; | ||
7 | + subject: string; | ||
8 | + _lang: string; | ||
9 | + text?: string; | ||
10 | + file?: File; | ||
11 | + website?: string; | ||
12 | + outline?: File; | ||
13 | + }; | ||
14 | + subtype: string; | ||
15 | + }; | ||
16 | + type: string; | ||
17 | +}; | ||
18 | +export type generateError = { | ||
19 | + data: { | ||
20 | + code: number; | ||
21 | + message: string; | ||
22 | + }; | ||
23 | + type: string; | ||
24 | +}; |
@@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
21 | "test:ci": "node --no-warnings --experimental-vm-modules $(yarn bin jest) --ci" | 21 | "test:ci": "node --no-warnings --experimental-vm-modules $(yarn bin jest) --ci" |
22 | }, | 22 | }, |
23 | "dependencies": { | 23 | "dependencies": { |
24 | + "@docmee/sdk-ui": "^1.1.17", | ||
24 | "@fortaine/fetch-event-source": "^3.0.6", | 25 | "@fortaine/fetch-event-source": "^3.0.6", |
25 | "@hello-pangea/dnd": "^16.5.0", | 26 | "@hello-pangea/dnd": "^16.5.0", |
26 | "@modelcontextprotocol/sdk": "^1.0.4", | 27 | "@modelcontextprotocol/sdk": "^1.0.4", |
@@ -1371,6 +1371,13 @@ | @@ -1371,6 +1371,13 @@ | ||
1371 | dependencies: | 1371 | dependencies: |
1372 | "@jridgewell/trace-mapping" "0.3.9" | 1372 | "@jridgewell/trace-mapping" "0.3.9" |
1373 | 1373 | ||
1374 | +"@docmee/sdk-ui@^1.1.17": | ||
1375 | + version "1.1.17" | ||
1376 | + resolved "https://registry.npmmirror.com/@docmee/sdk-ui/-/sdk-ui-1.1.17.tgz#549ee8b20dfe07eada422e9943b651d5a5196dd0" | ||
1377 | + integrity sha512-K/pWu2tg9ZrE9wbI5Naylh+LVd86kwMG7A9pu5urN1XjV+MAHj7ruOMrmqMkGbN5fVfFN8DbxWx4yUMcCMHTxA== | ||
1378 | + dependencies: | ||
1379 | + query-string "^9.1.1" | ||
1380 | + | ||
1374 | "@emotion/hash@^0.8.0": | 1381 | "@emotion/hash@^0.8.0": |
1375 | version "0.8.0" | 1382 | version "0.8.0" |
1376 | resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz" | 1383 | resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz" |
@@ -4266,6 +4273,11 @@ decode-named-character-reference@^1.0.0: | @@ -4266,6 +4273,11 @@ decode-named-character-reference@^1.0.0: | ||
4266 | dependencies: | 4273 | dependencies: |
4267 | character-entities "^2.0.0" | 4274 | character-entities "^2.0.0" |
4268 | 4275 | ||
4276 | +decode-uri-component@^0.4.1: | ||
4277 | + version "0.4.1" | ||
4278 | + resolved "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz#2ac4859663c704be22bf7db760a1494a49ab2cc5" | ||
4279 | + integrity sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ== | ||
4280 | + | ||
4269 | dedent@^1.0.0: | 4281 | dedent@^1.0.0: |
4270 | version "1.5.3" | 4282 | version "1.5.3" |
4271 | resolved "https://registry.npmmirror.com/dedent/-/dedent-1.5.3.tgz" | 4283 | resolved "https://registry.npmmirror.com/dedent/-/dedent-1.5.3.tgz" |
@@ -5136,6 +5148,11 @@ fill-range@^7.0.1: | @@ -5136,6 +5148,11 @@ fill-range@^7.0.1: | ||
5136 | dependencies: | 5148 | dependencies: |
5137 | to-regex-range "^5.0.1" | 5149 | to-regex-range "^5.0.1" |
5138 | 5150 | ||
5151 | +filter-obj@^5.1.0: | ||
5152 | + version "5.1.0" | ||
5153 | + resolved "https://registry.npmmirror.com/filter-obj/-/filter-obj-5.1.0.tgz#5bd89676000a713d7db2e197f660274428e524ed" | ||
5154 | + integrity sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng== | ||
5155 | + | ||
5139 | find-cache-dir@^3.3.1: | 5156 | find-cache-dir@^3.3.1: |
5140 | version "3.3.2" | 5157 | version "3.3.2" |
5141 | resolved "https://registry.npmmirror.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz" | 5158 | resolved "https://registry.npmmirror.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz" |
@@ -8035,6 +8052,15 @@ pure-rand@^6.0.0: | @@ -8035,6 +8052,15 @@ pure-rand@^6.0.0: | ||
8035 | resolved "https://registry.npmmirror.com/pure-rand/-/pure-rand-6.1.0.tgz" | 8052 | resolved "https://registry.npmmirror.com/pure-rand/-/pure-rand-6.1.0.tgz" |
8036 | integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== | 8053 | integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== |
8037 | 8054 | ||
8055 | +query-string@^9.1.1: | ||
8056 | + version "9.1.1" | ||
8057 | + resolved "https://registry.npmmirror.com/query-string/-/query-string-9.1.1.tgz#dbfebb4196aeb2919915f2b2b81b91b965cf03a0" | ||
8058 | + integrity sha512-MWkCOVIcJP9QSKU52Ngow6bsAWAPlPK2MludXvcrS2bGZSl+T1qX9MZvRIkqUIkGLJquMJHWfsT6eRqUpp4aWg== | ||
8059 | + dependencies: | ||
8060 | + decode-uri-component "^0.4.1" | ||
8061 | + filter-obj "^5.1.0" | ||
8062 | + split-on-first "^3.0.0" | ||
8063 | + | ||
8038 | querystringify@^2.1.1: | 8064 | querystringify@^2.1.1: |
8039 | version "2.2.0" | 8065 | version "2.2.0" |
8040 | resolved "https://registry.npmmirror.com/querystringify/-/querystringify-2.2.0.tgz" | 8066 | resolved "https://registry.npmmirror.com/querystringify/-/querystringify-2.2.0.tgz" |
@@ -9068,6 +9094,11 @@ spawn-command@0.0.2: | @@ -9068,6 +9094,11 @@ spawn-command@0.0.2: | ||
9068 | resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz" | 9094 | resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz" |
9069 | integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== | 9095 | integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== |
9070 | 9096 | ||
9097 | +split-on-first@^3.0.0: | ||
9098 | + version "3.0.0" | ||
9099 | + resolved "https://registry.npmmirror.com/split-on-first/-/split-on-first-3.0.0.tgz#f04959c9ea8101b9b0bbf35a61b9ebea784a23e7" | ||
9100 | + integrity sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA== | ||
9101 | + | ||
9071 | sprintf-js@~1.0.2: | 9102 | sprintf-js@~1.0.2: |
9072 | version "1.0.3" | 9103 | version "1.0.3" |
9073 | resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz" | 9104 | resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz" |
-
请 注册 或 登录 后发表评论