正在显示
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" |
-
请 注册 或 登录 后发表评论