作者 202304001

1、对话界面增加:生成文章

2、增加深度思考中
3、导出过滤思考内容
4、增加 风格 是 用途的 二级联动
... ... @@ -55,6 +55,7 @@ import WordIcon from "../icons/word.svg";
import MindIcon from "../icons/mind.svg";
import PptIcon from "../icons/ppt.svg";
import FileIcon from "../icons/file.svg";
import WriteIcon from "../icons/write.svg";
import {
BOT_HELLO,
... ... @@ -139,8 +140,9 @@ import { getAvailableClientsCount, isMcpEnabled } from "../mcp/actions";
import { getExcelData, toExcel } from "../utils/fileExport/export2Excel";
import { exportWord, getWordData } from "../utils/fileExport/word";
import { getMindPrompt } from "../utils/prompt";
import { message } from "antd";
import { message as msgModal } from "antd";
import { getPdfData } from "../utils/fileExport/toPdf";
import { removeDeepThink } from "../utils/deepThink";
const localStorage = safeLocalStorage();
const ttsPlayer = createTTSPlayer();
... ... @@ -1757,7 +1759,7 @@ function _Chat() {
if (message.content === content) {
newMessages.push({
role: "user",
content: getMindPrompt(content, true),
content: getMindPrompt(removeDeepThink(content), true),
});
break;
}
... ... @@ -1768,7 +1770,15 @@ function _Chat() {
//20250328新增PPT导出
function toPowerpoint(pptMessage: string) {
navigate("/powerpoint", { state: { msg: true, pptMessage: pptMessage } });
navigate(Path.Powerpoint, {
state: { msg: true, pptMessage: removeDeepThink(pptMessage) },
});
}
function toWrite(message: string) {
navigate(Path.Writing, {
state: { msg: true, writeMessage: removeDeepThink(message) },
});
}
//20250402新增上传文件
const [fileData, setFileData] = useState("");
... ... @@ -1782,7 +1792,7 @@ function _Chat() {
fileInput.style.display = "none";
const handleFileResult = (fileName: string, data: any) => {
if (!data) {
message.error("未读取到内容");
msgModal.error(Locale.ComError.Notread);
return;
}
setFileData(`'''filedata
... ... @@ -1791,9 +1801,12 @@ function _Chat() {
'''filedata`);
setFileName(fileName);
};
const handleError = (error: any, defaultMsg = "上传失败") => {
const handleError = (
error: any,
defaultMsg = Locale.ComError.UploadErr,
) => {
console.error(`${defaultMsg}:`, error);
message.error(defaultMsg);
msgModal.error(defaultMsg);
};
// 文件处理器映射
const fileHandlers: Record<string, (file: File) => Promise<any>> = {
... ... @@ -1812,7 +1825,7 @@ function _Chat() {
.slice(file.name.lastIndexOf("."));
// 校验文件类型
if (!Object.keys(fileHandlers).includes(fileExt)) {
message.error("不支持的文件类型");
msgModal.error(Locale.ComError.UnsupportedFile);
return;
}
// 获取处理器并执行
... ... @@ -2077,11 +2090,17 @@ function _Chat() {
<ChatAction
text={Locale.Export.Excel}
icon={<ExcelIcon />}
onClick={() =>
onClick={() => {
try {
toExcel(
getMessageTextContent(message),
)
);
} catch (error) {
msgModal.error(
Locale.ComError.ExcelErr,
);
}
}}
/>
{!isTableContent(
getMessageTextContent(message),
... ... @@ -2117,6 +2136,15 @@ function _Chat() {
)
}
/>
<ChatAction
text={Locale.Chat.Actions.Write}
icon={<WriteIcon />}
onClick={() =>
toWrite(
getMessageTextContent(message),
)
}
/>
{/* 以上 20250317 新增Word excel导出按钮 */}
{config.ttsConfig.enable && (
<ChatAction
... ... @@ -2189,6 +2217,7 @@ function _Chat() {
fontFamily={fontFamily}
parentRef={scrollRef}
defaultShow={i >= messages.length - 6}
isUser={isUser}
/>
{getMessageImages(message).length == 1 && (
<img
... ...
... ... @@ -28,6 +28,10 @@ import clsx from "clsx";
import { ChartComponentProps, extractDataFromText } from "./chart/getChartData";
import { ChartComponent } from "./chart";
import styles from "./chat.module.scss";
import { Collapse } from "antd";
import { useDebounce } from "../utils/hooks";
import { createDeepThink } from "../utils/deepThink";
export function Mermaid(props: { code: string }) {
const ref = useRef<HTMLDivElement>(null);
const [hasError, setHasError] = useState(false);
... ... @@ -276,15 +280,8 @@ function tryWrapHtmlCode(text: string) {
},
);
}
// 首先定义完善的类型
type FileMatch = {
fullMatch: string;
fileName: string;
start: number;
end: number;
};
function _MarkDownContent(props: { content: string }) {
function _MarkDownContent(props: { content: string; isUser: boolean }) {
const escapedContent = useMemo(() => {
return tryWrapHtmlCode(escapeBrackets(props.content));
}, [props.content]);
... ... @@ -303,7 +300,6 @@ function _MarkDownContent(props: { content: string }) {
type Segment = TextSegment | ElementSegment;
// 将子节点转换为可分析的段落段
function parseChildrenToSegments(children: React.ReactNode): Segment[] {
const segments: Segment[] = [];
let textBuffer = "";
... ... @@ -346,7 +342,6 @@ function _MarkDownContent(props: { content: string }) {
return segments;
}
// 主处理函数
function CustomParagraph({ children }: { children: React.ReactNode }) {
const segments = parseChildrenToSegments(children);
const fullText = segments
... ... @@ -408,6 +403,54 @@ function _MarkDownContent(props: { content: string }) {
return <p dir="auto">{newChildren}</p>;
}
const CollapsibleBlockquote = ({
children,
}: {
children: React.ReactNode;
}) => {
const [isFinalized, setIsFinalized] = useState(false);
const [lastUpdated, setLastUpdated] = useState(Date.now());
const contentString = React.Children.toArray(children).join("");
// 使用防抖检测内容是否稳定
const debouncedCheck = useDebounce(() => {
if (Date.now() - lastUpdated > 2000) {
// 2秒内无更新视为最终
setIsFinalized(true);
}
}, 2000);
useEffect(() => {
setIsFinalized(false);
setLastUpdated(Date.now());
debouncedCheck();
}, [contentString]);
return (
<Collapse
defaultActiveKey={["1"]}
size="small"
items={[
{
key: "1",
label: isFinalized ? "已深度思考" : "思考中...",
children: (
<blockquote
style={{
padding: "10px",
borderLeft: "2px solid #ccc",
transition: "all 0.3s ease",
fontSize: "12px",
}}
>
{children}
</blockquote>
),
},
]}
/>
);
};
return (
<ReactMarkdown
remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
... ... @@ -424,7 +467,15 @@ function _MarkDownContent(props: { content: string }) {
components={{
pre: PreCode,
code: CustomCode,
p: CustomParagraph,
p: props.isUser
? CustomParagraph
: (pProps) => <p {...pProps} dir="auto" />,
blockquote: ({ children }) =>
props.isUser ? (
<blockquote>{children}</blockquote>
) : (
<CollapsibleBlockquote>{children}</CollapsibleBlockquote>
),
a: (aProps) => {
const href = aProps.href || "";
if (/\.(aac|mp3|opus|wav)$/.test(href)) {
... ... @@ -462,6 +513,7 @@ export function Markdown(
fontFamily?: string;
parentRef?: RefObject<HTMLDivElement>;
defaultShow?: boolean;
isUser: boolean;
} & React.DOMAttributes<HTMLDivElement>,
) {
const mdRef = useRef<HTMLDivElement>(null);
... ... @@ -481,7 +533,10 @@ export function Markdown(
{props.loading ? (
<LoadingIcon />
) : (
<MarkdownContent content={props.content} />
<MarkdownContent
content={createDeepThink(props.content)}
isUser={props.isUser}
/>
)}
</div>
);
... ...
... ... @@ -8,8 +8,7 @@ import { useChatStore } from "@/app/store";
import { getWrtingPrompt } from "@/app/utils/prompt";
import type { writePromptParam } from "@/app/types/prompt";
// 定义mergedData数据结构
const mergedData = [
export const mergedData = [
{
title: "写作用途",
required: true,
... ... @@ -79,6 +78,40 @@ const mergedData = [
},
];
// 20250408新增写作风格选项映射
const getWritingStyleOptions = (purpose: string) => {
switch (purpose) {
case "公司官网":
return [
{ name: "专业", value: "professional" },
{ name: "活泼", value: "lively" },
{ name: "严谨", value: "strict" },
];
case "小红书":
return [
{ name: "俏皮", value: "playful" },
{ name: "幽默", value: "humorous" },
];
case "微信公众号":
return [
{ name: "夸张", value: "exaggerated" },
{ name: "可爱", value: "cute" },
];
case "今日头条":
return [
{ name: "丰满", value: "full" },
{ name: "可爱", value: "cute" },
{ name: "健康", value: "healthy" },
];
default:
return [
{ name: "专业", value: "professional" },
{ name: "活泼", value: "lively" },
{ name: "严谨", value: "strict" },
];
}
};
export interface WritePanelProps {
htmlCode: string;
setHtmlCode: React.Dispatch<React.SetStateAction<string>>;
... ... @@ -96,7 +129,6 @@ export function WritingPanel(props: WritePanelProps) {
setWidth,
setHtmlheader,
} = props;
// 为每个选择框单独声明状态,存储name
const chatStore = useChatStore();
const [writingPurposeName, setWritingPurposeName] = useState("公司官网"); // 写作用途
const [imageModeName, setImageModeName] = useState("免费配图"); // 图片模式
... ... @@ -108,34 +140,49 @@ export function WritingPanel(props: WritePanelProps) {
const [writingCount, setWritingCount] = useState("200"); // 写作字数
const [prompt, setPrompt] = useState(""); // 提示词
const [isLoading, setIsLoading] = useState(false);
// 生成动态数据
const dynamicMergedData = mergedData.map((item) => {
if (item.title === "写作风格") {
return {
...item,
options: getWritingStyleOptions(writingPurposeName),
};
}
return item;
});
// 处理选择框变更事件
const handleSelectChange = (index: number, value: string) => {
const options = mergedData[index].options;
const selectedName = options.find((opt) => opt.value === value)?.name || "";
const selectedValue =
options.find((opt) => opt.value === value)?.value || "";
switch (index) {
case 0:
const item = dynamicMergedData[index];
const selectedOption = item.options.find((opt) => opt.value === value);
const selectedName = selectedOption?.name || "";
switch (item.title) {
case "写作用途":
setWritingPurposeName(selectedName);
setWidth(selectedValue);
setWidth(value);
// 自动更新写作风格为对应选项的第一个
const newStyles = getWritingStyleOptions(selectedName);
if (newStyles.length > 0) {
setWritingStyleName(newStyles[0].name);
}
break;
case 1:
case "图片模式":
setImageModeName(selectedName);
break;
case 2:
case "写作风格":
setWritingStyleName(selectedName);
break;
case 3:
case "写作语言":
setWritingLanguageName(selectedName);
break;
case 4:
case "写作类型":
setWritingTypeName(selectedName);
break;
case 5:
case "是否图文":
setIsImgName(selectedName);
break;
default:
break;
}
};
... ... @@ -174,7 +221,6 @@ export function WritingPanel(props: WritePanelProps) {
if (cleanedContent.endsWith("```")) {
cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4);
}
//保存html头部
const bodyTagRegex = /<body[^>]*>/i;
const bodyTagMatch = cleanedContent.match(bodyTagRegex);
... ... @@ -198,30 +244,27 @@ export function WritingPanel(props: WritePanelProps) {
return (
<div>
{/* 动态渲染选择框 */}
{mergedData.map((item, index) => {
{dynamicMergedData.map((item, index) => {
let currentValue = "";
switch (index) {
case 0:
switch (item.title) {
case "写作用途":
currentValue = writingPurposeName;
break;
case 1:
case "图片模式":
currentValue = imageModeName;
break;
case 2:
case "写作风格":
currentValue = writingStyleName;
break;
case 3:
case "写作语言":
currentValue = writingLanguageName;
break;
case 4:
case "写作类型":
currentValue = writingTypeName;
break;
case 5:
case "是否图文":
currentValue = isImgName;
break;
default:
currentValue = "";
break;
}
return (
... ...
... ... @@ -9,10 +9,16 @@ import { useMobileScreen } from "@/app/utils";
import { IconButton } from "../button";
import Locale from "@/app/locales";
import { Path } from "@/app/constant";
import { useNavigate } from "react-router-dom";
import { useLocation, useNavigate } from "react-router-dom";
import { getClientConfig } from "@/app/config/client";
import React, { useCallback, useMemo, useRef, useState } from "react";
import { useAppConfig, useMindMapStore } from "@/app/store";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useAppConfig, useChatStore, useMindMapStore } from "@/app/store";
import { ChatAction } from "../chat";
import { useWindowSize } from "@/app/utils";
import { exportHtmlToWord } from "@/app/utils/fileExport/word";
... ... @@ -37,11 +43,14 @@ import HtmlIcon from "@/app/icons/HTML.svg";
import { message } from "antd";
import { HTMLPreview } from "../artifacts";
import { getMindPrompt } from "@/app/utils/prompt";
import { getMindPrompt, getWrtingPrompt } from "@/app/utils/prompt";
import { htmlToPdf2 } from "@/app/utils/fileExport/toPdf";
import { htmlToExcel } from "@/app/utils/fileExport/export2Excel";
import { hasTable, htmlToExcel } from "@/app/utils/fileExport/export2Excel";
import { writePromptParam } from "@/app/types/prompt";
import { mergedData } from "./writie-panel";
export function WritingPage() {
const chatStore = useChatStore();
const isMobileScreen = useMobileScreen();
const navigate = useNavigate();
const clientConfig = useMemo(() => getClientConfig(), []);
... ... @@ -58,6 +67,8 @@ export function WritingPage() {
const [htmlCode, setHtmlCode] = useState(
localStorage.getItem("htmlCode") || "",
);
const query = useLocation(); //获取路由参数
let { msg, writeMessage } = query.state || {}; //获取路由参数
//编辑器
const toolbarOptions = [
... ... @@ -69,9 +80,66 @@ export function WritingPage() {
["link", "image"],
];
useEffect(() => {
if (!msg) {
return;
}
if (!writeMessage) {
return;
}
const navigateGetData = async () => {
try {
const param: writePromptParam = {
writingPurposeName: mergedData[0].default,
writingStyleName: mergedData[2].default,
writingLanguageName: mergedData[3].default,
prompt: writeMessage,
writingTypeName: mergedData[4].default,
isImgName: mergedData[5].default,
writingCount: "200",
};
const input = getWrtingPrompt(param);
setLoading(true);
console.log("------------------------" + input);
const response = await chatStore.directLlmInvoke(input, "gpt-4o-mini");
let cleanedContent = response.startsWith("```html")
? response.substring(8)
: response;
if (cleanedContent.endsWith("```")) {
cleanedContent = cleanedContent.substring(
0,
cleanedContent.length - 4,
);
}
//保存html头部
const bodyTagRegex = /<body[^>]*>/i;
const bodyTagMatch = cleanedContent.match(bodyTagRegex);
if (bodyTagMatch && bodyTagMatch.index !== undefined) {
// 截取从文档开头到 <body> 标签的起始位置
const contentUpToBody = cleanedContent.slice(
0,
bodyTagMatch.index + bodyTagMatch[0].length,
);
setHtmlheader(contentUpToBody); //保存html头部
}
localStorage.setItem("htmlCode", cleanedContent);
setHtmlCode(cleanedContent);
} catch (error) {
message.error("生成失败,请重试");
} finally {
setLoading(false);
}
};
navigateGetData();
}, []);
// 生成完整HTML内容
const generateFullHtml = useCallback(
() => `${htmlHeader}${htmlCode}</body></html>`,
() => `${htmlHeader}
<div style="width:${width}">
${htmlCode}
</div>
</body></html>`,
[htmlHeader, htmlCode],
);
... ... @@ -87,7 +155,7 @@ export function WritingPage() {
};
//跳转到ppt页面
function toPowerpoint(pptMessage: string) {
navigate("/powerpoint", { state: { msg: true, pptMessage: pptMessage } });
navigate(Path.Powerpoint, { state: { msg: true, pptMessage: pptMessage } });
}
// 转至思维导图页面
const toMind = useCallback(
... ... @@ -102,7 +170,7 @@ export function WritingPage() {
],
content,
);
navigate("/mind", { state: { msg: true } });
navigate(Path.Mind, { state: { msg: true } });
},
[navigate],
);
... ... @@ -124,12 +192,6 @@ export function WritingPage() {
}
}, [generateFullHtml]);
function hasTable(htmlContent: string): boolean {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlContent, "text/html");
return doc.querySelector("table") !== null;
}
return (
<>
<WriteSiderBar
... ... @@ -201,7 +263,8 @@ export function WritingPage() {
icon={<PdfIcon />}
onClick={async () => {
setLoading(true);
await htmlToPdf2(htmlCode);
const html = `<div style="width:${width}">${htmlCode}</div>`;
await htmlToPdf2(html);
setLoading(false);
}}
disabled={isEdit}
... ... @@ -210,11 +273,7 @@ export function WritingPage() {
text={Locale.Export.Word}
icon={<WordIcon />}
onClick={() => {
const html = `${htmlHeader}
${htmlCode}
</body>
</html>
`;
const html = generateFullHtml();
exportHtmlToWord(html);
}}
disabled={isEdit}
... ...
... ... @@ -28,7 +28,7 @@ export const TENCENT_BASE_URL = "https://hunyuan.tencentcloudapi.com";
export const MOONSHOT_BASE_URL = "https://api.moonshot.cn";
export const IFLYTEK_BASE_URL = "https://spark-api-open.xf-yun.com";
export const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
export const DEEPSEEK_BASE_URL = "https://openapi.baolinai.top";
export const XAI_BASE_URL = "https://api.x.ai";
... ... @@ -490,7 +490,7 @@ const openaiModels = [
// as it is cheaper, more capable, multimodal, and just as fast. gpt-3.5-turbo is still available for use in the API.
"gpt-3.5-turbo",
"gpt-3.5-turbo-1106",
"gpt-3.5-turbo-0125",
"deepseek-r1",
"gpt-4",
"gpt-4-0613",
"gpt-4-32k",
... ... @@ -840,3 +840,4 @@ export const DEFAULT_GA_ID = "G-89WN60ZK2E";
export const SAAS_CHAT_URL = "https://nextchat.club";
export const SAAS_CHAT_UTM_URL = "https://nextchat.club?utm=github";
export const UPLOAD_FILE_MAX_LINE = 100;
... ...
... ... @@ -62,6 +62,7 @@ const cn = {
//20250317新增
ReWrite: "重写",
Chart: "查看图表",
Write: "生成文章",
},
Commands: {
new: "新建聊天",
... ... @@ -886,6 +887,14 @@ const cn = {
generateBg: "生成背景",
promptTitle: "背景提示词",
},
//20250408新增错误信息
ComError: {
ExcelErr: "未找到表格内容",
UploadErr: "上传失败",
UnsupportedFile: "不支持的文件类型",
Notread: "未读取到内容",
},
};
type DeepPartial<T> = T extends object
... ...
export function createDeepThink(content: string) {
const lines = content.split("\n");
let deepThink: string[] = [];
let j = 0;
let isBreak = false;
for (let i = 0; i < lines.length; i++) {
if (lines[i] === "") {
lines.splice(i, 1); // 删除空行
i--;
continue;
}
if (
lines[i].startsWith(">") ||
lines[i].startsWith("2") ||
lines[i].startsWith("3") ||
lines[i].startsWith("4")
) {
if (j !== 0 && lines[i].startsWith(">")) {
lines[i] = lines[i].substring(1);
}
deepThink.push(lines[i]);
lines.splice(i, 1);
j++;
i--;
} else {
break;
}
}
const deepThinkStr = deepThink.join("");
const linesStr = lines.join("\n");
const result = [deepThinkStr, "", linesStr].join("\n");
return result;
}
export function removeDeepThink(content: string) {
const lines = content.split("\n");
let deepThink: string[] = [];
let j = 0;
let isBreak = false;
for (let i = 0; i < lines.length; i++) {
if (lines[i] === "") {
lines.splice(i, 1); // 删除空行
i--;
continue;
}
if (
lines[i].startsWith(">") ||
lines[i].startsWith("2") ||
lines[i].startsWith("3") ||
lines[i].startsWith("4")
) {
if (j !== 0 && lines[i].startsWith(">")) {
lines[i] = lines[i].substring(1);
}
deepThink.push(lines[i]);
lines.splice(i, 1);
j++;
i--;
} else {
break;
}
}
return lines.join("\n");
}
... ...
/* eslint-disable */
import { UPLOAD_FILE_MAX_LINE } from "@/app/constant";
import * as XLSX from "xlsx";
export function toExcel(content: string) {
if (hasTable(content)) {
htmlToExcel(content);
} else {
markdownToExcel(content);
}
}
export function hasTable(htmlContent: string): boolean {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlContent, "text/html");
return doc.querySelector("table") !== null;
}
export function markdownToExcel(content: string) {
let sheetName = "result"; // 默认表名
let tableContent = "";
... ... @@ -26,7 +41,7 @@ export function toExcel(content: string) {
}
if (tableStartIndex === -1) {
console.error("表格内容未找到");
throw new Error("表格内容未找到");
return;
}
... ... @@ -114,7 +129,7 @@ export function getExcelData(file: File): Promise<any[][]> {
const jsonData = XLSX.utils.sheet_to_json(worksheet, {
header: 1,
}) as any[][];
resolve(jsonData.slice(0, 100));
resolve(jsonData.slice(0, UPLOAD_FILE_MAX_LINE));
} catch (error) {
reject(error);
}
... ...
import { UPLOAD_FILE_MAX_LINE } from "@/app/constant";
import { Document, Packer, Paragraph } from "docx";
import { saveAs } from "file-saver";
import * as mammoth from "mammoth";
export function removeDeepThink(content: string) {
const lines = content.split("\n");
let deepThink: string[] = [];
let j = 0;
let isBreak = false;
for (let i = 0; i < lines.length; i++) {
if (lines[i] === "") {
lines.splice(i, 1); // 删除空行
i--;
continue;
}
if (
lines[i].startsWith(">") ||
lines[i].startsWith("2") ||
lines[i].startsWith("3") ||
lines[i].startsWith("4")
) {
if (j !== 0 && lines[i].startsWith(">")) {
lines[i] = lines[i].substring(1);
}
deepThink.push(lines[i]);
lines.splice(i, 1);
j++;
i--;
} else {
break;
}
}
return lines.join("\n");
}
export function exportWord(content: string) {
console.log(content);
content = removeDeepThink(content);
// 简单类型检测示例
const isHTML = (text: string): boolean => {
return (
... ... @@ -83,7 +115,7 @@ export async function getWordData(file: File) {
try {
const arrayBuffer = await file.arrayBuffer();
const { value, messages } = await mammoth.extractRawText({ arrayBuffer });
return value;
return value.slice(0, UPLOAD_FILE_MAX_LINE);
} catch (error) {
console.error("Error extracting Word content:", error);
throw error;
... ...
import { useMemo } from "react";
import { useEffect, useMemo, useRef } from "react";
import { useAccessStore, useAppConfig } from "../store";
import { collectModelsWithDefaultModel } from "./model";
... ... @@ -20,3 +20,24 @@ export function useAllModels() {
return models;
}
export function useDebounce(callback: () => void, delay: number) {
const timeoutRef = useRef<NodeJS.Timeout>();
useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
callback();
}, delay);
};
}
... ...
import type { writePromptParam } from "@/app/types/prompt";
//生成文章提示词
export function getWrtingPrompt(param: writePromptParam): string {
const {
isImgName,
... ... @@ -11,17 +12,23 @@ export function getWrtingPrompt(param: writePromptParam): string {
writingCount,
} = param;
// 根据用途调整文案类型描述
const purposeMap: Record<string, string> = {
公司官网: "公司官网的介绍",
小红书: "小红书的介绍",
微信: "微信的介绍",
公众号: "公众号的介绍",
今日头条: "今日头条的介绍",
公司官网: "正式的公司官网文案",
小红书: "符合小红书平台风格的文案",
微信公众号: "适合微信公众号传播的文案",
今日头条: "今日头条风格的热点文案",
};
const styleMap: Record<string, string> = {
专业: "专业的风格",
活泼: "活泼的风格",
严谨: "严谨的风格",
专业: "专业严谨",
活泼: "生动活泼",
严谨: "严谨细致",
俏皮: "俏皮可爱",
幽默: "幽默风趣",
夸张: "夸张吸睛",
可爱: "可爱亲切",
丰满: "内容丰满",
健康: "健康积极",
};
const typeMap: Record<string, string> = {
产品推广文案: "产品推广的文案",
... ... @@ -35,22 +42,29 @@ export function getWrtingPrompt(param: writePromptParam): string {
const purpose = purposeMap[rawPurpose] || "公司官网的介绍";
const style = styleMap[rawStyle] || "专业的风格";
isImg = `文案要配上图片,实现图文混排,要美观,要符合${purpose}的排版标准和写作风格,写作风格要${style},
isImg = `要求图文混排,需符合以下要求:
文案要配上图片,实现图文混排,要美观,要符合${purpose}的排版标准和写作风格,写作风格要${style},
你没有图片没关系,把图文混排的效果实现,并在你认为要插入图片的地方将图片的Prompt用英文输出给:![description](https://image.pollinations.ai/prompt/description?nologo=true),记得图片地址后面的?nologo=true一定不能去掉了,
因为这个语法可以自动按照提示生成并渲染图片。你可以帮我大幅提高生成图片质量和丰富程度,比如增加相机光圈、具体场景描述等内容,注意图片一定要用<img,否则在HTML下图片可能显示不了`;
}
const writingTypeName = typeMap[rawType] || "产品推广文案";
const input = `帮我使用${writingLanguageName}写一篇主题是${prompt}的${writingTypeName},${isImg},字数要求不少于${writingCount}字,
字数不包括html代码和图片Prompt。输出成标准的html并且样式必须为内联样式,直接给结果,不要做任何解释`;
return input;
return `请用${writingLanguageName}撰写一篇关于【${prompt}】的${writingTypeName}:
${isImg}
具体要求:
1. 写作风格:${styleMap[rawStyle] || "专业"}
2. 字数要求:不少于${writingCount}字(不计代码)
3. 输出格式:标准HTML带内联样式
4. 特殊要求:直接输出结果,不要额外解释`;
}
//生成图片提示词
export function getBgPrompt(content: string) {
const input = `你现扮演生成创意思图片的提示词工程师,参考我的描述“${content}”帮我做优化润色5组,返回的数据用''分割,直接输出结果,不要做解释`;
return input;
}
//思维导图提示词
export function getMindPrompt(content: string, isContext: boolean) {
const context = `联系上下文`;
let prompt = `请你帮我生成一份以"${content}"为主题的思维导图数据,请严格遵循以下要求生成思维导图数据:
... ...