ソースを参照

优化 按钮样式 btn-cancel btn-back ant-btn-primary

Ryuiso 3 ヶ月 前
コミット
fa762d3d1c

+ 140 - 0
src/pages/deepseek/questionAnswer/info/README.md

@@ -0,0 +1,140 @@
+# 提示词模板配置系统
+
+## 概述
+
+这个配置系统用于管理问答应用中的提示词模板,避免在代码中硬编码长文本,提高代码的可维护性和可扩展性。
+
+## 文件结构
+
+```
+src/pages/deepseek/questionAnswer/info/
+├── promptTemplates.ts    # 提示词模板配置文件
+├── index.tsx            # 主组件文件
+└── README.md           # 说明文档
+```
+
+## 使用方法
+
+### 1. 基本使用
+
+```typescript
+import { DEFAULT_PROMPT_TEMPLATE, getPromptTemplate } from './promptTemplates';
+
+// 使用默认模板
+const defaultPrompt = DEFAULT_PROMPT_TEMPLATE;
+
+// 使用特定模板
+const chatPrompt = getPromptTemplate('CHAT_ASSISTANT');
+```
+
+### 2. 在组件中使用
+
+```typescript
+import { DEFAULT_PROMPT_TEMPLATE } from './promptTemplates';
+
+// 在FormItem中使用
+<FormItem 
+  name='prompt'
+  initialValue={DEFAULT_PROMPT_TEMPLATE}
+  rules={[{ required: true, message: '提示词不能为空' }]}
+>
+  <TextArea placeholder="提示词" rows={50} />
+</FormItem>
+```
+
+### 3. 添加新的提示词模板
+
+在 `promptTemplates.ts` 中添加新的模板:
+
+```typescript
+export const PROMPT_TEMPLATES = {
+  // 现有模板...
+  
+  // 新增模板
+  CUSTOM_ASSISTANT: `你是一个自定义助手,请根据以下要求提供服务:
+
+用户需求: {{用户}}
+参考文档: {{知识}}
+
+请按照要求完成任务。`
+};
+```
+
+### 4. 验证和格式化
+
+```typescript
+import { 
+  validatePromptTemplate, 
+  formatPromptTemplate 
+} from './promptTemplates';
+
+// 验证模板是否包含必要占位符
+const isValid = validatePromptTemplate(template);
+
+// 格式化模板(替换占位符)
+const formattedPrompt = formatPromptTemplate(
+  template, 
+  '知识库内容', 
+  '用户输入'
+);
+```
+
+## 模板类型
+
+| 类型 | 描述 | 用途 |
+|------|------|------|
+| `KNOWLEDGE_RETRIEVAL_ASSISTANT` | 知识检索助手 | 基于知识库内容回答问题 |
+| `CHAT_ASSISTANT` | 聊天助手 | 提供友好的对话服务 |
+| `DOCUMENT_SUMMARY` | 文档总结 | 提取文档关键信息 |
+| `CODE_ASSISTANT` | 代码助手 | 提供代码解决方案 |
+| `TRANSLATION_ASSISTANT` | 翻译助手 | 多语言翻译服务 |
+
+## 占位符说明
+
+- `{{知识}}`: 知识库内容占位符
+- `{{用户}}`: 用户输入占位符
+
+## 最佳实践
+
+1. **保持模板简洁**: 避免在模板中包含过多的逻辑判断
+2. **使用占位符**: 统一使用 `{{知识}}` 和 `{{用户}}` 占位符
+3. **添加描述**: 为每个模板添加清晰的描述
+4. **验证模板**: 使用 `validatePromptTemplate` 验证模板格式
+5. **版本控制**: 对模板的修改进行版本控制
+
+## 扩展功能
+
+### 动态模板选择
+
+可以添加一个下拉选择器让用户选择不同的提示词模板:
+
+```typescript
+import { 
+  getAvailableTemplateTypes, 
+  PROMPT_TEMPLATE_DESCRIPTIONS 
+} from './promptTemplates';
+
+const templateTypes = getAvailableTemplateTypes();
+
+<Select 
+  placeholder="选择提示词模板"
+  onChange={(value) => setSelectedTemplate(value)}
+>
+  {templateTypes.map(type => (
+    <Option key={type} value={type}>
+      {PROMPT_TEMPLATE_DESCRIPTIONS[type]}
+    </Option>
+  ))}
+</Select>
+```
+
+### 模板预览
+
+可以添加模板预览功能,让用户在应用前查看模板内容。
+
+## 注意事项
+
+1. 修改模板后需要重新测试应用功能
+2. 确保所有模板都包含必要的占位符
+3. 保持模板的向后兼容性
+4. 定期审查和更新模板内容

+ 28 - 17
src/pages/deepseek/questionAnswer/info/index.tsx

@@ -7,7 +7,7 @@ import {
     Radio, Switch, Row, Col, Slider, Space, RadioChangeEvent,
     Spin, message
 } from 'antd';
-import { PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons';
+import { PlusCircleOutlined, MinusCircleOutlined, ArrowLeftOutlined } from '@ant-design/icons';
 import { apis } from '@/apis';
 import router from '@/router';
 import LocalStorage from '@/LocalStorage';
@@ -503,7 +503,7 @@ const QuestionAnswerInfo: React.FC = () => {
                         
                         <div style={{ display: 'flex', gap: '12px', marginTop: '24px', paddingTop: '24px', borderTop: '1px solid #f0f0f0' }}>
                             <Button
-                                className='btn-secondary'
+                                className='btn-cancel'
                                 onClick={() => {
                                     router.navigate({ pathname: '/deepseek/questionAnswer' });
                                 }}
@@ -527,16 +527,27 @@ const QuestionAnswerInfo: React.FC = () => {
                     </div>
 
                     <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
-                        <div className='flex-end padding-bottom-10'>
+                        <div className='flex-between padding-bottom-10'>
                             <div>
                                 <Button
-                                    className='btn-secondary'
+                                    className='btn-back'
+                                    icon={<ArrowLeftOutlined />}
                                     onClick={() => {
                                         setStep(1);
                                     }}
                                 >
                                     上一步
                                 </Button>
+                            </div>
+                            <div style={{ display: 'flex', gap: '12px' }}>
+                                <Button
+                                    className='btn-cancel'
+                                    onClick={() => {
+                                        router.navigate({ pathname: '/deepseek/questionAnswer' });
+                                    }}
+                                >
+                                    取消
+                                </Button>
                                 {
                                     createFlag &&
                                     <Button
@@ -647,30 +658,30 @@ const QuestionAnswerInfo: React.FC = () => {
                                             className='textarea-full-width textarea-fixed-height'
                                         />
                                     </div>
-                                    <Divider plain></Divider>
                                     <div >
                                         <FormItem name='prompt'
-                                            initialValue={`你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。
-
+                                            initialValue={
+                                                `你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。 \n
 知识片段如下:
 {{知识}}
 
 规定要求:
-- 找到答案就仅使用知识片段中的原文回答用户的提问;
-- 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
+- 找到答案就仅使用知识片段中的原文回答用户的提问;- 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
 - 所引用的文本片段中所包含的示意图占位符必须进行返回,占位符格式参考:【示意图序号_编号】
-  - 严禁输出任何知识片段中不存在的示意图占位符;
-  - 输出的内容必须删除其中包含的任何图注、序号等信息。例如:“进入登录页面(图1.1)”需要从文字中删除图序,回复效果为:“进入登录页面”;“如图所示1.1”,回复效果为:“如图所示”;
-- 格式规范
-  - 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
-  - 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
-  - 避免使用代码块语法回复信息;
-  - 回复的开头语不要输出诸如:“我想”,“我认为”,“think”等相关语义的文本。
+- 严禁输出任何知识片段中不存在的示意图占位符;
+- 输出的内容必须删除其中包含的任何图注、序号等信息。例如:“进入登录页面(图1.1)”需要从文字中删除图序,回复效果为:“进入登录页面”;“如图所示1.1”,回复效果为:“如图所示”;
+
+格式规范:
+- 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
+- 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
+- 避免使用代码块语法回复信息;
+- 回复的开头语不要输出诸如:“我想”,“我认为”,“think”等相关语义的文本。
 
 严格执行规定要求,不要复述问题,直接开始回答。
 
 用户输入问题:
-{{用户}}`}
+{{用户}}`
+                                            }
                                             rules={[{ required: true, message: '提示词不能为空' }]}>
                                             <TextArea
                                                 placeholder="提示词"

+ 96 - 0
src/pages/deepseek/questionAnswer/info/promptTemplates.ts

@@ -0,0 +1,96 @@
+// 提示词模板配置文件
+export const PROMPT_TEMPLATES = {
+  // 知识检索助手提示词模板
+  KNOWLEDGE_RETRIEVAL_ASSISTANT: `你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。
+
+知识片段如下:
+{{知识}} 
+
+规定要求:
+- 找到答案就仅使用知识片段中的原文回答用户的提问;
+- 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
+- 所引用的文本片段中所包含的示意图占位符必须进行返回,占位符格式参考:【示意图序号_编号】
+  - 严禁输出任何知识片段中不存在的示意图占位符;
+  - 输出的内容必须删除其中包含的任何图注、序号等信息。例如:"进入登录页面(图1.1)"需要从文字中删除图序,回复效果为:"进入登录页面";"如图所示1.1",回复效果为:"如图所示";
+
+格式规范:
+  - 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
+  - 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
+  - 避免使用代码块语法回复信息;
+  - 回复的开头语不要输出诸如:"我想","我认为","think"等相关语义的文本。
+
+严格执行规定要求,不要复述问题,直接开始回答。
+
+用户输入的问题:
+{{用户}} `,
+
+  // 可以添加更多提示词模板
+  CHAT_ASSISTANT: `你是一个友好的聊天助手,请根据用户的问题提供有帮助的回答。
+
+用户问题: {{用户}}`,
+
+  // 文档总结助手
+  DOCUMENT_SUMMARY: `请对以下文档内容进行总结,提取关键信息:
+
+文档内容:
+{{知识}}
+
+用户要求:
+{{用户}}`,
+
+  // 代码助手
+  CODE_ASSISTANT: `你是一个专业的代码助手,请根据用户的需求提供代码解决方案。
+
+用户需求: {{用户}}
+
+相关文档: {{知识}}`,
+
+  // 翻译助手
+  TRANSLATION_ASSISTANT: `你是一个专业的翻译助手,请将用户提供的内容翻译成目标语言。
+
+原文内容: {{用户}}
+
+参考文档: {{知识}}`
+};
+
+// 提示词模板类型定义
+export type PromptTemplateType = keyof typeof PROMPT_TEMPLATES;
+
+// 获取提示词模板的函数
+export const getPromptTemplate = (templateType: PromptTemplateType): string => {
+  return PROMPT_TEMPLATES[templateType];
+};
+
+// 默认提示词模板
+export const DEFAULT_PROMPT_TEMPLATE = PROMPT_TEMPLATES.KNOWLEDGE_RETRIEVAL_ASSISTANT;
+
+// 提示词模板描述
+export const PROMPT_TEMPLATE_DESCRIPTIONS = {
+  KNOWLEDGE_RETRIEVAL_ASSISTANT: '知识检索助手 - 基于知识库内容回答问题',
+  CHAT_ASSISTANT: '聊天助手 - 提供友好的对话服务',
+  DOCUMENT_SUMMARY: '文档总结 - 提取文档关键信息',
+  CODE_ASSISTANT: '代码助手 - 提供代码解决方案',
+  TRANSLATION_ASSISTANT: '翻译助手 - 多语言翻译服务'
+};
+
+// 验证提示词模板是否包含必要的占位符
+export const validatePromptTemplate = (template: string): boolean => {
+  const requiredPlaceholders = ['{{知识}}', '{{用户}}'];
+  return requiredPlaceholders.every(placeholder => template.includes(placeholder));
+};
+
+// 格式化提示词模板(替换占位符)
+export const formatPromptTemplate = (
+  template: string, 
+  knowledge: string = '', 
+  userInput: string = ''
+): string => {
+  return template
+    .replace(/\{\{知识\}\}/g, knowledge)
+    .replace(/\{\{用户\}\}/g, userInput);
+};
+
+// 获取所有可用的模板类型
+export const getAvailableTemplateTypes = (): PromptTemplateType[] => {
+  return Object.keys(PROMPT_TEMPLATES) as PromptTemplateType[];
+};

+ 58 - 6
src/pages/deepseek/questionAnswer/info/style.less

@@ -116,13 +116,60 @@
   margin-left: 20px;
 }
 
-.question-icon {
-  margin-left: 20px;
-}
-
 // 按钮样式
-.btn-secondary {
+.btn-cancel {
   background: #f5f5f5;
+  border: none;
+  color: #000000;
+  transition: all 0.3s ease;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  
+  &:hover {
+    background: #e8e8e8;
+    color: #000000;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+    transform: translateY(-1px);
+  }
+  
+  &:active {
+    background: #dcdcdc;
+    color: #000000;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+    transform: translateY(0);
+  }
+  
+  &:focus {
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
+}
+
+.btn-back {
+  background: #ffffff;
+  border: 1px solid #d9d9d9;
+  color: #595959;
+  transition: all 0.3s ease;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  
+  &:hover {
+    background: #fafafa;
+    border-color: #40a9ff;
+    color: #40a9ff;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+    transform: translateY(-1px);
+  }
+  
+  &:active {
+    background: #f0f0f0;
+    border-color: #1890ff;
+    color: #1890ff;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+    transform: translateY(0);
+  }
+  
+  &:focus {
+    border-color: #40a9ff;
+    box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+  }
 }
 
 // 容器样式
@@ -141,6 +188,12 @@
   justify-content: flex-end;
 }
 
+.flex-between {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
 .flex-center {
   display: flex;
   justify-content: center;
@@ -260,4 +313,3 @@
 }
 
 // 移除重复的 Ant Design 组件样式,使用全局样式
-// 只保留组件特有的样式覆盖

+ 40 - 0
src/style/global.less

@@ -92,3 +92,43 @@ ul li {
 //.ant-form-item {
 //    margin-bottom: 16px !important;
 //}
+
+// 全局按钮样式
+.ant-btn-primary {
+  background: #1890ff;
+  border: 1px solid #1890ff;
+  color: #ffffff;
+  transition: all 0.3s ease;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  
+  &:hover {
+    background: #40a9ff;
+    border-color: #40a9ff;
+    color: #ffffff;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+    transform: translateY(-1px);
+  }
+  
+  &:active {
+    background: #096dd9;
+    border-color: #096dd9;
+    color: #ffffff;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+    transform: translateY(0);
+  }
+  
+  &:focus {
+    background: #1890ff;
+    border-color: #1890ff;
+    color: #ffffff;
+    box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+  }
+  
+  &:disabled {
+    background: #f5f5f5;
+    border-color: #d9d9d9;
+    color: rgba(0, 0, 0, 0.25);
+    box-shadow: none;
+    transform: none;
+  }
+}