智能会话和知识库
							parent
							
								
									0c72a94fed
								
							
						
					
					
						commit
						615976e315
					
				| @ -0,0 +1,50 @@ | |||||||
|  | // import StructuredData from '@/components/StructuredData';
 | ||||||
|  | import { Locales } from '@/locales/resources'; | ||||||
|  | // import { ldModule } from '@/server/ld';
 | ||||||
|  | import { metadataModule } from '@/server/metadata'; | ||||||
|  | // import { DiscoverService } from '@/server/services/discover';
 | ||||||
|  | import { translation } from '@/server/translation'; | ||||||
|  | // import { isMobileDevice } from '@/utils/responsive';
 | ||||||
|  | import ApplicationSet from "./applicationset"; | ||||||
|  | 
 | ||||||
|  | // import {Button} from "antd";
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | type Props = { searchParams: { hl?: Locales } }; | ||||||
|  | 
 | ||||||
|  | export const generateMetadata = async ({ searchParams }: Props) => { | ||||||
|  |   const { t, locale } = await translation('metadata', searchParams?.hl); | ||||||
|  |   return metadataModule.generate({ | ||||||
|  |     alternate: true, | ||||||
|  |     description: t('files.description'), | ||||||
|  |     locale, | ||||||
|  |     title: t('files.title'), | ||||||
|  |     url: '/files', | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const Page = async () => { | ||||||
|  |   // const { t, locale } = await translation('metadata', searchParams?.hl);
 | ||||||
|  |   // const mobile = isMobileDevice();
 | ||||||
|  | 
 | ||||||
|  |   // const discoverService = new DiscoverService();
 | ||||||
|  |   // const items = await discoverService.getAssistantList(locale);
 | ||||||
|  | 
 | ||||||
|  |   // const ld = ldModule.generate({
 | ||||||
|  |   //   description: t('files.description'),
 | ||||||
|  |   //   title: t('files.title'),
 | ||||||
|  |   //   url: '/files',
 | ||||||
|  |   //   webpage: {
 | ||||||
|  |   //     enable: true,
 | ||||||
|  |   //     search: '/files/search',
 | ||||||
|  |   //   },
 | ||||||
|  |   // });
 | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |       <ApplicationSet /> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Page.DisplayName = 'DiscoverAssistants'; | ||||||
|  | 
 | ||||||
|  | export default Page; | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | import { Markdown } from '@lobehub/ui'; | ||||||
|  | import { memo } from 'react'; | ||||||
|  | 
 | ||||||
|  | import { useContainerStyles } from '../style'; | ||||||
|  | 
 | ||||||
|  | const Preview = memo<{ content: string }>(({ content }) => { | ||||||
|  |   const { styles } = useContainerStyles(); | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <div className={styles.preview} style={{ padding: 12 }}> | ||||||
|  |       <Markdown>{content}</Markdown> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | export default Preview; | ||||||
| @ -0,0 +1,102 @@ | |||||||
|  | // import { Form, type FormItemProps, Icon, copyToClipboard } from '@lobehub/ui';
 | ||||||
|  | import { Button } from 'antd'; | ||||||
|  | import isEqual from 'fast-deep-equal'; | ||||||
|  | // import { CopyIcon } from 'lucide-react';
 | ||||||
|  | import { memo } from 'react'; | ||||||
|  | import { useTranslation } from 'react-i18next'; | ||||||
|  | import { Flexbox } from 'react-layout-kit'; | ||||||
|  | 
 | ||||||
|  | // import { FORM_STYLE } from '@/const/layoutTokens';
 | ||||||
|  | import { useIsMobile } from '@/hooks/useIsMobile'; | ||||||
|  | import { useAgentStore } from '@/store/agent'; | ||||||
|  | import { agentSelectors } from '@/store/agent/selectors'; | ||||||
|  | import { useChatStore } from '@/store/chat'; | ||||||
|  | import { chatSelectors, topicSelectors } from '@/store/chat/selectors'; | ||||||
|  | import { FieldType } from './type'; | ||||||
|  | import { LOADING_FLAT } from '@/const/message'; | ||||||
|  | import { stringify as csvStringify } from 'csv-stringify'; | ||||||
|  | 
 | ||||||
|  | const DEFAULT_FIELD_VALUE: FieldType = { | ||||||
|  |   includeTool: true, | ||||||
|  |   includeUser: true, | ||||||
|  |   withRole: true, | ||||||
|  |   withSystemRole: false, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const ShareText = memo(() => { | ||||||
|  |   // const [fieldValue, setFieldValue] = useState(DEFAULT_FIELD_VALUE);
 | ||||||
|  |   const { t } = useTranslation(['chat', 'common']); | ||||||
|  | 
 | ||||||
|  |   // const { message } = App.useApp();
 | ||||||
|  | 
 | ||||||
|  |   const [systemRole] = useAgentStore((s) => [agentSelectors.currentAgentSystemRole(s)]); | ||||||
|  |   const messages = useChatStore(chatSelectors.currentChats, isEqual); | ||||||
|  |   const topic = useChatStore(topicSelectors.currentActiveTopic, isEqual); | ||||||
|  |   console.log(systemRole,messages,'83737373737') | ||||||
|  |   let messagesNew = messages | ||||||
|  |     .filter((m) => m.content !== LOADING_FLAT) | ||||||
|  |     .filter((m) => (!DEFAULT_FIELD_VALUE.includeUser ? m.role !== 'user' : true)) | ||||||
|  |     .filter((m) => (!DEFAULT_FIELD_VALUE.includeTool ? m.role !== 'tool' : true)) | ||||||
|  | 
 | ||||||
|  |   console.log(messagesNew,'111111111111111') | ||||||
|  |   const topicTitle = topic?.title || t('shareModal.exportTitle'); | ||||||
|  |   console.log(topicTitle,'22222222222222222') | ||||||
|  |   const isMobile = useIsMobile(); | ||||||
|  |   const downloadCSV = () => { | ||||||
|  |     const data = [ | ||||||
|  |         ["question", "answer"], | ||||||
|  |     ]; | ||||||
|  |     let arrItem = []; | ||||||
|  |     messagesNew.forEach((chat)=> { | ||||||
|  |        if (chat.role === 'assistant') { | ||||||
|  |           arrItem.push(chat.content) | ||||||
|  |        } else if(chat.role === 'user') { | ||||||
|  |           arrItem.unshift(chat.content) | ||||||
|  |        } | ||||||
|  |        if(arrItem.length >= 2) { | ||||||
|  |          data.push(arrItem) | ||||||
|  |          arrItem = []; | ||||||
|  |        } | ||||||
|  |     }) | ||||||
|  |     console.log(data,'9999111111') | ||||||
|  |     // 将数据转换为CSV字符串
 | ||||||
|  |     let csvContent = ""; | ||||||
|  |     csvStringify(data, (err, output) => { | ||||||
|  |       if (err) { | ||||||
|  |         console.error('Error generating CSV:', err); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // 输出 CSV 字符串
 | ||||||
|  |       console.log(output,'66666666666666'); | ||||||
|  |       csvContent = output | ||||||
|  | 
 | ||||||
|  |       // 创建一个Blob对象
 | ||||||
|  |       const blob = new Blob([csvContent], { type: 'text/csv' }); | ||||||
|  | 
 | ||||||
|  |       // 创建一个URL并指向Blob对象
 | ||||||
|  |       const url = URL.createObjectURL(blob); | ||||||
|  | 
 | ||||||
|  |       // 创建一个隐藏的<a>标签并点击它以触发下载
 | ||||||
|  |       const a = document.createElement('a'); | ||||||
|  |       a.setAttribute('hidden', ''); | ||||||
|  |       a.setAttribute('href', url); | ||||||
|  |       a.setAttribute('download', topicTitle + '.csv'); | ||||||
|  |       document.body.append(a); | ||||||
|  |       a.click(); | ||||||
|  | 
 | ||||||
|  |       // 移除<a>标签
 | ||||||
|  |       a.remove(); | ||||||
|  | 
 | ||||||
|  |       // 释放URL对象
 | ||||||
|  |       URL.revokeObjectURL(url); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   return ( | ||||||
|  |     <Flexbox gap={16} horizontal={!isMobile}> | ||||||
|  |       <Button onClick={() => downloadCSV()} shape="round" style={{borderColor: '#2E62FF', color: "#2E62FF",fontSize: '13px',height: '30px'}}>会话导出</Button> | ||||||
|  |     </Flexbox> | ||||||
|  |   ); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | export default ShareText; | ||||||
| @ -0,0 +1,178 @@ | |||||||
|  | import { describe, expect, it } from 'vitest'; | ||||||
|  | 
 | ||||||
|  | import { LOADING_FLAT } from '@/const/message'; | ||||||
|  | import { ChatMessage } from '@/types/message'; | ||||||
|  | 
 | ||||||
|  | import { generateMarkdown } from './template'; | ||||||
|  | 
 | ||||||
|  | describe('generateMarkdown', () => { | ||||||
|  |   // 创建测试用的消息数据
 | ||||||
|  |   const mockMessages = [ | ||||||
|  |     { | ||||||
|  |       id: '1', | ||||||
|  |       content: 'Hello', | ||||||
|  |       role: 'user', | ||||||
|  |       createdAt: Date.now(), | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       id: '2', | ||||||
|  |       content: 'Hi there', | ||||||
|  |       role: 'assistant', | ||||||
|  |       createdAt: Date.now(), | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       id: '3', | ||||||
|  |       content: LOADING_FLAT, | ||||||
|  |       role: 'assistant', | ||||||
|  |       createdAt: Date.now(), | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       id: '4', | ||||||
|  |       content: '{"result": "tool data"}', | ||||||
|  |       role: 'tool', | ||||||
|  |       createdAt: Date.now(), | ||||||
|  |       tool_call_id: 'tool1', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       id: '5', | ||||||
|  |       content: 'Message with tools', | ||||||
|  |       role: 'assistant', | ||||||
|  |       createdAt: Date.now(), | ||||||
|  |       tools: [{ name: 'calculator', result: '42' }], | ||||||
|  |     }, | ||||||
|  |   ] as ChatMessage[]; | ||||||
|  | 
 | ||||||
|  |   const defaultParams = { | ||||||
|  |     messages: mockMessages, | ||||||
|  |     title: 'Chat Title', | ||||||
|  |     includeTool: false, | ||||||
|  |     includeUser: true, | ||||||
|  |     withSystemRole: false, | ||||||
|  |     withRole: false, | ||||||
|  |     systemRole: '', | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   it('should generate basic markdown with title', () => { | ||||||
|  |     const result = generateMarkdown(defaultParams); | ||||||
|  | 
 | ||||||
|  |     expect(result).toContain('# Chat Title'); | ||||||
|  |     expect(result).toContain('Hello'); | ||||||
|  |     expect(result).toContain('Hi there'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should include system role when withSystemRole is true', () => { | ||||||
|  |     const systemRole = 'I am a helpful assistant'; | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       withSystemRole: true, | ||||||
|  |       systemRole, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).toContain('````md\nI am a helpful assistant\n````'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should not include system role when withSystemRole is false', () => { | ||||||
|  |     const systemRole = 'I am a helpful assistant'; | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       withSystemRole: false, | ||||||
|  |       systemRole, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).not.toContain('```\nI am a helpful assistant\n```'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should add role labels when withRole is true', () => { | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       withRole: true, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).toContain('##### User:'); | ||||||
|  |     expect(result).toContain('##### Assistant:'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should not add role labels when withRole is false', () => { | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       withRole: false, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).not.toContain('##### User:'); | ||||||
|  |     expect(result).not.toContain('##### Assistant:'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should include tool messages when includeTool is true', () => { | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       includeTool: true, | ||||||
|  |       withRole: true, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).toContain('##### Tools Calling:'); | ||||||
|  |     expect(result).toContain('```json\n{"result": "tool data"}\n```'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should exclude tool messages when includeTool is false', () => { | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       includeTool: false, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).not.toContain('{"result": "tool data"}'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should exclude user messages when includeUser is false', () => { | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       includeUser: false, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).not.toContain('Hello'); | ||||||
|  |     expect(result).toContain('Hi there'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should filter out loading messages', () => { | ||||||
|  |     const result = generateMarkdown(defaultParams); | ||||||
|  | 
 | ||||||
|  |     expect(result).not.toContain(LOADING_FLAT); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should include tools data when includeTool is true', () => { | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       includeTool: true, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).toContain('"name": "calculator"'); | ||||||
|  |     expect(result).toContain('"result": "42"'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should handle empty messages array', () => { | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       messages: [], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).toContain('# Chat Title'); | ||||||
|  |     // Should not throw error and should contain at least the title
 | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should handle messages with special characters', () => { | ||||||
|  |     const messagesWithSpecialChars = [ | ||||||
|  |       { | ||||||
|  |         id: '1', | ||||||
|  |         content: '**Bold** *Italic* `Code`', | ||||||
|  |         role: 'user', | ||||||
|  |         createdAt: Date.now(), | ||||||
|  |       }, | ||||||
|  |     ] as ChatMessage[]; | ||||||
|  | 
 | ||||||
|  |     const result = generateMarkdown({ | ||||||
|  |       ...defaultParams, | ||||||
|  |       messages: messagesWithSpecialChars, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(result).toContain('**Bold** *Italic* `Code`'); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @ -0,0 +1,79 @@ | |||||||
|  | import { template } from 'lodash-es'; | ||||||
|  | 
 | ||||||
|  | import { LOADING_FLAT } from '@/const/message'; | ||||||
|  | import { FieldType } from '@/features/ShareModal/ShareText/type'; | ||||||
|  | import { ChatMessage } from '@/types/message'; | ||||||
|  | 
 | ||||||
|  | const markdownTemplate = template( | ||||||
|  |   `# {{title}}
 | ||||||
|  | 
 | ||||||
|  | <% if (systemRole) { %> | ||||||
|  | \`\`\`\`md
 | ||||||
|  | {{systemRole}} | ||||||
|  | \`\`\`\` | ||||||
|  | <% } %> | ||||||
|  | 
 | ||||||
|  | <% messages.forEach(function(chat) { %> | ||||||
|  | 
 | ||||||
|  | <% if (withRole) { %> | ||||||
|  | 
 | ||||||
|  | <% if (chat.role === 'user') { %> | ||||||
|  | ##### User: | ||||||
|  | <% } else if (chat.role === 'assistant') { %> | ||||||
|  | ##### Assistant: | ||||||
|  | <% } else if (chat.role === 'tool') { %> | ||||||
|  | ##### Tools Calling: | ||||||
|  | <% } %> | ||||||
|  | 
 | ||||||
|  | <% } %> | ||||||
|  | 
 | ||||||
|  | <% if (chat.role === 'tool') { %> | ||||||
|  | \`\`\`json
 | ||||||
|  | {{chat.content}} | ||||||
|  | \`\`\` | ||||||
|  | <% } else { %> | ||||||
|  | 
 | ||||||
|  | {{chat.content}} | ||||||
|  | 
 | ||||||
|  | <% if (includeTool && chat.tools) { %> | ||||||
|  | 
 | ||||||
|  | \`\`\`json
 | ||||||
|  | {{JSON.stringify(chat.tools, null, 2)}} | ||||||
|  | \`\`\` | ||||||
|  | 
 | ||||||
|  | <% } %> | ||||||
|  | <% } %> | ||||||
|  | 
 | ||||||
|  | <% }); %> | ||||||
|  | `,
 | ||||||
|  |   { | ||||||
|  |     evaluate: /<%([\S\s]+?)%>/g, | ||||||
|  |     interpolate: /{{([\S\s]+?)}}/g, | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | interface MarkdownParams extends FieldType { | ||||||
|  |   messages: ChatMessage[]; | ||||||
|  |   systemRole: string; | ||||||
|  |   title: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const generateMarkdown = ({ | ||||||
|  |   messages, | ||||||
|  |   title, | ||||||
|  |   includeTool, | ||||||
|  |   includeUser, | ||||||
|  |   withSystemRole, | ||||||
|  |   withRole, | ||||||
|  |   systemRole, | ||||||
|  | }: MarkdownParams) => | ||||||
|  |   markdownTemplate({ | ||||||
|  |     includeTool, | ||||||
|  |     messages: messages | ||||||
|  |       .filter((m) => m.content !== LOADING_FLAT) | ||||||
|  |       .filter((m) => (!includeUser ? m.role !== 'user' : true)) | ||||||
|  |       .filter((m) => (!includeTool ? m.role !== 'tool' : true)), | ||||||
|  |     systemRole: withSystemRole ? systemRole : undefined, | ||||||
|  |     title, | ||||||
|  |     withRole, | ||||||
|  |   }); | ||||||
| @ -0,0 +1,6 @@ | |||||||
|  | export type FieldType = { | ||||||
|  |   includeTool: boolean; | ||||||
|  |   includeUser: boolean; | ||||||
|  |   withRole: boolean; | ||||||
|  |   withSystemRole: boolean; | ||||||
|  | }; | ||||||
| @ -1,52 +0,0 @@ | |||||||
| import StructuredData from '@/components/StructuredData'; |  | ||||||
| import { Locales } from '@/locales/resources'; |  | ||||||
| import { ldModule } from '@/server/ld'; |  | ||||||
| import { metadataModule } from '@/server/metadata'; |  | ||||||
| import { DiscoverService } from '@/server/services/discover'; |  | ||||||
| import { translation } from '@/server/translation'; |  | ||||||
| import { isMobileDevice } from '@/utils/responsive'; |  | ||||||
| import Filescon from "./filescon"; |  | ||||||
| 
 |  | ||||||
| import {Button} from "antd"; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| type Props = { searchParams: { hl?: Locales } }; |  | ||||||
| 
 |  | ||||||
| export const generateMetadata = async ({ searchParams }: Props) => { |  | ||||||
|   const { t, locale } = await translation('metadata', searchParams?.hl); |  | ||||||
|   return metadataModule.generate({ |  | ||||||
|     alternate: true, |  | ||||||
|     description: t('files.description'), |  | ||||||
|     locale, |  | ||||||
|     title: t('files.title'), |  | ||||||
|     url: '/files', |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const Page = async ({ searchParams }: Props) => { |  | ||||||
|   const { t, locale } = await translation('metadata', searchParams?.hl); |  | ||||||
|   const mobile = isMobileDevice(); |  | ||||||
| 
 |  | ||||||
|   const discoverService = new DiscoverService(); |  | ||||||
|   const items = await discoverService.getAssistantList(locale); |  | ||||||
| 
 |  | ||||||
|   const ld = ldModule.generate({ |  | ||||||
|     description: t('files.description'), |  | ||||||
|     title: t('files.title'), |  | ||||||
|     url: '/files', |  | ||||||
|     webpage: { |  | ||||||
|       enable: true, |  | ||||||
|       search: '/files/search', |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   return ( |  | ||||||
|     <> |  | ||||||
|       <Filescon /> |  | ||||||
|     </> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| Page.DisplayName = 'DiscoverAssistants'; |  | ||||||
| 
 |  | ||||||
| export default Page; |  | ||||||
| @ -0,0 +1,76 @@ | |||||||
|  | import { Col, Form, Input, Modal, Row } from 'antd'; | ||||||
|  | import React from 'react'; | ||||||
|  | import { createStyles } from 'antd-style'; | ||||||
|  | 
 | ||||||
|  | const { TextArea } = Input; | ||||||
|  | const FormItem = Form.Item; | ||||||
|  | const useStyles = createStyles(({ css }) => ({ | ||||||
|  |   formStyle: css` | ||||||
|  |      .ant-form-item-label { | ||||||
|  |        width: 100px !important; | ||||||
|  |      } | ||||||
|  |   `,
 | ||||||
|  |   modalStyle: css` | ||||||
|  |     .ant-modal-body { | ||||||
|  |       padding: 20px 0; | ||||||
|  |     } | ||||||
|  |     .ant-modal-footer { | ||||||
|  |       .ant-btn:nth-child(1) { | ||||||
|  |         width: 73px; | ||||||
|  |         height: 36px; | ||||||
|  |         border-radius: 4px; | ||||||
|  |         opacity: 1; | ||||||
|  |         background: #EBF4FF; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         border: 1px solid #B8D8FF; | ||||||
|  |         color: #177FFF; | ||||||
|  |       } | ||||||
|  |       .ant-btn:nth-child(2) { | ||||||
|  |         width: 73px; | ||||||
|  |         height: 36px; | ||||||
|  |         border-radius: 4px; | ||||||
|  |         opacity: 1; | ||||||
|  | 
 | ||||||
|  |         background: #80B9FF; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   `,
 | ||||||
|  | })); | ||||||
|  | const KnowledgeCreateForm = (props) => { | ||||||
|  |     const { styles } = useStyles(); | ||||||
|  |     const [form] = Form.useForm(); | ||||||
|  | 
 | ||||||
|  |     const { open, handleAdd, handleModalVisible } = props; | ||||||
|  | 
 | ||||||
|  |     const okHandle = () => { | ||||||
|  |         form.validateFields() | ||||||
|  |             .then((fieldsValue) => { | ||||||
|  |                 form.resetFields(); | ||||||
|  |                 handleAdd(fieldsValue); | ||||||
|  |             }) | ||||||
|  |             .catch(() => {}); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <Modal className={styles.modalStyle} destroyOnClose onCancel={() => handleModalVisible(false)} onOk={okHandle} open={open} title="创建知识库" > | ||||||
|  |             <Form className={styles.formStyle} form={form}> | ||||||
|  |                 <Row gutter={{ lg: 24, md: 8, xl: 48 }}> | ||||||
|  |                     <Col md={24} sm={24}> | ||||||
|  |                         <FormItem label="知识库名称" name="name" rules={[{ message: '请输入!', min: 1, required: true}]}> | ||||||
|  |                             <Input placeholder="请输入" /> | ||||||
|  |                         </FormItem> | ||||||
|  |                     </Col> | ||||||
|  |                 </Row> | ||||||
|  |                 <Row gutter={{ lg: 24, md: 8, xl: 48 }}> | ||||||
|  |                     <Col md={24} sm={24}> | ||||||
|  |                         <FormItem label="知识库描述" name="description" rules={[{ message: '请输入!', min: 1 , required: false}]}> | ||||||
|  |                            <TextArea maxLength={255} placeholder="请输入"  rows={4} /> | ||||||
|  |                         </FormItem> | ||||||
|  |                     </Col> | ||||||
|  |                 </Row> | ||||||
|  |             </Form> | ||||||
|  |         </Modal> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default KnowledgeCreateForm; | ||||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								| @ -0,0 +1,83 @@ | |||||||
|  | import { Col, Form, Input, Modal, Row } from 'antd'; | ||||||
|  | import React from 'react'; | ||||||
|  | import { createStyles } from 'antd-style'; | ||||||
|  | 
 | ||||||
|  | const { TextArea } = Input; | ||||||
|  | const FormItem = Form.Item; | ||||||
|  | const useStyles = createStyles(({ css }) => ({ | ||||||
|  |   formStyle: css` | ||||||
|  |      .ant-form-item-label { | ||||||
|  |        width: 100px !important; | ||||||
|  |      } | ||||||
|  |   `,
 | ||||||
|  |   modalStyle: css` | ||||||
|  |     .ant-modal-body { | ||||||
|  |       padding: 20px 0; | ||||||
|  |     } | ||||||
|  |     .ant-modal-footer { | ||||||
|  |       .ant-btn:nth-child(1) { | ||||||
|  |         width: 73px; | ||||||
|  |         height: 36px; | ||||||
|  |         border-radius: 4px; | ||||||
|  |         opacity: 1; | ||||||
|  |         background: #EBF4FF; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         border: 1px solid #B8D8FF; | ||||||
|  |         color: #177FFF; | ||||||
|  |       } | ||||||
|  |       .ant-btn:nth-child(2) { | ||||||
|  |         width: 73px; | ||||||
|  |         height: 36px; | ||||||
|  |         border-radius: 4px; | ||||||
|  |         opacity: 1; | ||||||
|  | 
 | ||||||
|  |         background: #80B9FF; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   `,
 | ||||||
|  | })); | ||||||
|  | const KnowledgeUpdateForm = (props) => { | ||||||
|  |     const { styles } = useStyles(); | ||||||
|  |     const [form] = Form.useForm(); | ||||||
|  | 
 | ||||||
|  |     const { handleUpdate, open, handleUpdateModalVisible, values } = props; | ||||||
|  | 
 | ||||||
|  |     React.useEffect(() => { | ||||||
|  |         form.setFieldsValue({ | ||||||
|  |             description: props.values.description, | ||||||
|  |             id: props.values.id, | ||||||
|  |             title: props.values.title, | ||||||
|  |         }); | ||||||
|  |     }, []); | ||||||
|  | 
 | ||||||
|  |     const handleLocalUpdate = () => { | ||||||
|  |         form.validateFields() | ||||||
|  |             .then((fieldsValue) => { | ||||||
|  |                 handleUpdate({ ...values, ...fieldsValue }); | ||||||
|  |             }) | ||||||
|  |             .catch(() => {}); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <Modal afterClose={() => handleUpdateModalVisible()} className={styles.modalStyle} destroyOnClose  onCancel={() => handleUpdateModalVisible(false, values)}  onOk={() => handleLocalUpdate()}  open={open} title="编辑知识库"> | ||||||
|  |             <Form className={styles.formStyle} form={form}> | ||||||
|  |                 <Row gutter={{ lg: 24, md: 8, xl: 48 }}> | ||||||
|  |                     <Col md={24} sm={24}> | ||||||
|  |                         <FormItem label="知识库名称" name="title" rules={[{ message: '请输入!', min: 1, required: true }]}> | ||||||
|  |                             <Input placeholder="请输入" /> | ||||||
|  |                         </FormItem> | ||||||
|  |                     </Col> | ||||||
|  |                 </Row> | ||||||
|  |                 <Row gutter={{ lg: 24, md: 8,xl: 48 }}> | ||||||
|  |                     <Col md={24} sm={24}> | ||||||
|  |                         <FormItem label="知识库描述" name="description" rules={[{ message: '请输入!', min: 1,  required: false }]}> | ||||||
|  |                            <TextArea maxLength={255} placeholder="请输入"  rows={4} /> | ||||||
|  |                         </FormItem> | ||||||
|  |                     </Col> | ||||||
|  |                 </Row> | ||||||
|  |             </Form> | ||||||
|  |         </Modal> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default KnowledgeUpdateForm; | ||||||
| @ -1,38 +0,0 @@ | |||||||
| import { WelcomeLogo } from '@/components/Branding'; |  | ||||||
| import StructuredData from '@/components/StructuredData'; |  | ||||||
| import { BRANDING_NAME } from '@/const/branding'; |  | ||||||
| import { ldModule } from '@/server/ld'; |  | ||||||
| import { metadataModule } from '@/server/metadata'; |  | ||||||
| import { translation } from '@/server/translation'; |  | ||||||
| import { isMobileDevice } from '@/utils/responsive'; |  | ||||||
| 
 |  | ||||||
| export const generateMetadata = async () => { |  | ||||||
|   const { t } = await translation('metadata'); |  | ||||||
|   return metadataModule.generate({ |  | ||||||
|     description: t('model.description', { appName: BRANDING_NAME }), |  | ||||||
|     title: t('model.title', { appName: BRANDING_NAME }), |  | ||||||
|     url: '/model', |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const Page = async () => { |  | ||||||
|   const mobile = isMobileDevice(); |  | ||||||
|   const { t } = await translation('metadata'); |  | ||||||
|   const ld = ldModule.generate({ |  | ||||||
|     description: t('model.description', { appName: BRANDING_NAME }), |  | ||||||
|     title: t('model.title', { appName: BRANDING_NAME }), |  | ||||||
|     url: '/model', |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   return ( |  | ||||||
|     <> |  | ||||||
|       {/*<StructuredData ld={ld} />*/} |  | ||||||
|       {/*<WelcomeLogo mobile={mobile} />*/} |  | ||||||
|       <div>模型</div> |  | ||||||
|     </> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| Page.displayName = 'Model'; |  | ||||||
| 
 |  | ||||||
| export default Page; |  | ||||||
| @ -1,38 +0,0 @@ | |||||||
| import { WelcomeLogo } from '@/components/Branding'; |  | ||||||
| import StructuredData from '@/components/StructuredData'; |  | ||||||
| import { BRANDING_NAME } from '@/const/branding'; |  | ||||||
| import { ldModule } from '@/server/ld'; |  | ||||||
| import { metadataModule } from '@/server/metadata'; |  | ||||||
| import { translation } from '@/server/translation'; |  | ||||||
| import { isMobileDevice } from '@/utils/responsive'; |  | ||||||
| 
 |  | ||||||
| export const generateMetadata = async () => { |  | ||||||
|   const { t } = await translation('metadata'); |  | ||||||
|   return metadataModule.generate({ |  | ||||||
|     description: t('plugins.description', { appName: BRANDING_NAME }), |  | ||||||
|     title: t('plugins.title', { appName: BRANDING_NAME }), |  | ||||||
|     url: '/plugins', |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const Page = async () => { |  | ||||||
|   const mobile = isMobileDevice(); |  | ||||||
|   const { t } = await translation('metadata'); |  | ||||||
|   const ld = ldModule.generate({ |  | ||||||
|     description: t('plugins.description', { appName: BRANDING_NAME }), |  | ||||||
|     title: t('plugins.title', { appName: BRANDING_NAME }), |  | ||||||
|     url: '/plugins', |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   return ( |  | ||||||
|     <> |  | ||||||
|       {/*<StructuredData ld={ld} />*/} |  | ||||||
|       {/*<WelcomeLogo mobile={mobile} />*/} |  | ||||||
|       <div>插件</div> |  | ||||||
|     </> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| Page.displayName = 'Robot'; |  | ||||||
| 
 |  | ||||||
| export default Page; |  | ||||||
| @ -1,32 +1,144 @@ | |||||||
| 'use client'; | 'use client'; | ||||||
| 
 | 
 | ||||||
| import isEqual from 'fast-deep-equal'; | import { SiDiscord, SiGithub, SiMedium, SiRss, SiX } from '@icons-pack/react-simple-icons'; | ||||||
|  | import { Form } from '@lobehub/ui'; | ||||||
|  | import { Divider } from 'antd'; | ||||||
|  | import { createStyles } from 'antd-style'; | ||||||
| import { memo } from 'react'; | import { memo } from 'react'; | ||||||
|  | import { useTranslation } from 'react-i18next'; | ||||||
|  | import { Flexbox } from 'react-layout-kit'; | ||||||
| 
 | 
 | ||||||
| import { INBOX_SESSION_ID } from '@/const/session'; | import { BRANDING_NAME } from '@/const/branding'; | ||||||
| import { AgentSettingAbout } from '@/features/AgentSetting'; | import { | ||||||
| import { useUserStore } from '@/store/user'; |   BLOG, | ||||||
| import { settingsSelectors } from '@/store/user/selectors'; |   DISCORD, | ||||||
|  |   EMAIL_BUSINESS, | ||||||
|  |   EMAIL_SUPPORT, | ||||||
|  |   GITHUB, | ||||||
|  |   MEDIDUM, | ||||||
|  |   OFFICIAL_SITE, | ||||||
|  |   PRIVACY_URL, | ||||||
|  |   TERMS_URL, | ||||||
|  |   X, | ||||||
|  |   mailTo, | ||||||
|  | } from '@/const/url'; | ||||||
|  | import { useServerConfigStore } from '@/store/serverConfig'; | ||||||
|  | import { serverConfigSelectors } from '@/store/serverConfig/selectors'; | ||||||
| 
 | 
 | ||||||
| const Page = memo(() => { | import AboutList from './features/AboutList'; | ||||||
|   const config = useUserStore(settingsSelectors.defaultAgentConfig, isEqual); | import Analytics from './features/Analytics'; | ||||||
|   const meta = useUserStore(settingsSelectors.defaultAgentMeta, isEqual); | import ItemCard from './features/ItemCard'; | ||||||
|   const [updateAgent] = useUserStore((s) => [s.updateDefaultAgent]); | import ItemLink from './features/ItemLink'; | ||||||
|  | import Version from './features/Version'; | ||||||
|  | 
 | ||||||
|  | const useStyles = createStyles(({ css, token }) => ({ | ||||||
|  |   title: css` | ||||||
|  |     font-size: 14px; | ||||||
|  |     font-weight: bold; | ||||||
|  |     color: ${token.colorTextSecondary}; | ||||||
|  |   `,
 | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | const Page = memo<{ mobile?: boolean }>(({ mobile }) => { | ||||||
|  |   const { t } = useTranslation('common'); | ||||||
|  |   const { styles } = useStyles(); | ||||||
|  |   const enabledTelemetryChat = useServerConfigStore(serverConfigSelectors.enabledTelemetryChat); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <AgentSettingAbout |     <> | ||||||
|       config={config} |       <Form.Group | ||||||
|       id={INBOX_SESSION_ID} |         style={{ width: '100%' }} | ||||||
|       meta={meta} |         title={`${t('about')} ${BRANDING_NAME}`} | ||||||
|       onConfigChange={(config) => { |         variant={'pure'} | ||||||
|         updateAgent({ config }); |       > | ||||||
|       }} |         <Flexbox gap={20} paddingBlock={20} width={'100%'}> | ||||||
|       onMetaChange={(meta) => { |           <div className={styles.title}>{t('version')}</div> | ||||||
|         updateAgent({ meta }); |           <Version mobile={mobile} /> | ||||||
|       }} |           <Divider style={{ marginBlock: 0 }} /> | ||||||
|  |           <div className={styles.title}>{t('contact')}</div> | ||||||
|  |           <AboutList | ||||||
|  |             ItemRender={ItemLink} | ||||||
|  |             items={[ | ||||||
|  |               { | ||||||
|  |                 href: OFFICIAL_SITE, | ||||||
|  |                 label: t('officialSite'), | ||||||
|  |                 value: 'officialSite', | ||||||
|  |               }, | ||||||
|  |               { | ||||||
|  |                 href: mailTo(EMAIL_SUPPORT), | ||||||
|  |                 label: t('mail.support'), | ||||||
|  |                 value: 'support', | ||||||
|  |               }, | ||||||
|  |               { | ||||||
|  |                 href: mailTo(EMAIL_BUSINESS), | ||||||
|  |                 label: t('mail.business'), | ||||||
|  |                 value: 'business', | ||||||
|  |               }, | ||||||
|  |             ]} | ||||||
|  |           /> | ||||||
|  |           <Divider style={{ marginBlock: 0 }} /> | ||||||
|  |           <div className={styles.title}>{t('information')}</div> | ||||||
|  |           <AboutList | ||||||
|  |             ItemRender={ItemCard} | ||||||
|  |             grid | ||||||
|  |             items={[ | ||||||
|  |               { | ||||||
|  |                 href: BLOG, | ||||||
|  |                 icon: SiRss, | ||||||
|  |                 label: t('blog'), | ||||||
|  |                 value: 'blog', | ||||||
|  |               }, | ||||||
|  |               { | ||||||
|  |                 href: GITHUB, | ||||||
|  |                 icon: SiGithub, | ||||||
|  |                 label: 'GitHub', | ||||||
|  |                 value: 'feedback', | ||||||
|  |               }, | ||||||
|  |               { | ||||||
|  |                 href: DISCORD, | ||||||
|  |                 icon: SiDiscord, | ||||||
|  |                 label: 'Discord', | ||||||
|  |                 value: 'discord', | ||||||
|  |               }, | ||||||
|  |               { | ||||||
|  |                 href: X, | ||||||
|  |                 icon: SiX as any, | ||||||
|  |                 label: 'X / Twitter', | ||||||
|  |                 value: 'x', | ||||||
|  |               }, | ||||||
|  | 
 | ||||||
|  |               { | ||||||
|  |                 href: MEDIDUM, | ||||||
|  |                 icon: SiMedium, | ||||||
|  |                 label: 'Medium', | ||||||
|  |                 value: 'medium', | ||||||
|  |               }, | ||||||
|  |             ]} | ||||||
|  |           /> | ||||||
|  |           <Divider style={{ marginBlock: 0 }} /> | ||||||
|  |           <div className={styles.title}>{t('legal')}</div> | ||||||
|  |           <AboutList | ||||||
|  |             ItemRender={ItemLink} | ||||||
|  |             items={[ | ||||||
|  |               { | ||||||
|  |                 href: TERMS_URL, | ||||||
|  |                 label: t('terms'), | ||||||
|  |                 value: 'terms', | ||||||
|  |               }, | ||||||
|  |               { | ||||||
|  |                 href: PRIVACY_URL, | ||||||
|  |                 label: t('privacy'), | ||||||
|  |                 value: 'privacy', | ||||||
|  |               }, | ||||||
|  |             ]} | ||||||
|           /> |           /> | ||||||
|  |         </Flexbox> | ||||||
|  |       </Form.Group> | ||||||
|  |       {enabledTelemetryChat && <Analytics />} | ||||||
|  |     </> | ||||||
|   ); |   ); | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
| Page.displayName = 'AboutSetting'; | Page.displayName = 'AboutSetting'; | ||||||
| 
 | 
 | ||||||
| export default Page; | export default Page; | ||||||
|  | |||||||
| @ -1,317 +0,0 @@ | |||||||
| 'use client'; |  | ||||||
| 
 |  | ||||||
| import {memo, useEffect, useState} from 'react'; |  | ||||||
| import {Form, Select, Radio, Slider, InputNumber, Image} from "antd"; |  | ||||||
| import {createStyles} from "antd-style"; |  | ||||||
| 
 |  | ||||||
| const ysOptions = [ |  | ||||||
|   {id: '1', name: '男声', icon: '/images/per.png/'}, |  | ||||||
|   {id: '2', name: '男声', icon: '/images/per.png/'}, |  | ||||||
|   {id: '3', name: '男声', icon: '/images/per.png/'}, |  | ||||||
|   {id: '4', name: '男声', icon: '/images/per.png/'}, |  | ||||||
|   {id: '5', name: '男声', icon: '/images/per.png/'}, |  | ||||||
|   {id: '6', name: '男声', icon: '/images/per.png/'}, |  | ||||||
|   {id: '7', name: '男声', icon: '/images/per.png/'}, |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| const useStyles = createStyles(({ css, token }) => ({ |  | ||||||
|   cricle: css` |  | ||||||
|     width: 8px; |  | ||||||
|     height: 8px; |  | ||||||
|     border-radius: 8px; |  | ||||||
|     display: inline-block; |  | ||||||
|     margin-right: 15px; |  | ||||||
|     background-color: #4F4F4F; |  | ||||||
|   `,
 |  | ||||||
|   onlyDiv: css` |  | ||||||
|     padding: 15px 40px; |  | ||||||
|   `,
 |  | ||||||
|   leftText: css` |  | ||||||
|     width: 200px; |  | ||||||
|     font-size: 18px; |  | ||||||
|     color: #333; |  | ||||||
|     display: inline-block |  | ||||||
|   `,
 |  | ||||||
|   leftDir: css` |  | ||||||
|     color: #999999; |  | ||||||
|     font-size: 16px; |  | ||||||
|     display: inline-block; |  | ||||||
|     margin-left: 5px; |  | ||||||
|   `,
 |  | ||||||
|   rightText: css` |  | ||||||
|     width: calc(100% - 215px); |  | ||||||
|     text-align: right; |  | ||||||
|     color: #333333; |  | ||||||
|     font-size: 16px; |  | ||||||
|     display: inline-block; |  | ||||||
|     margin-right: 15px; |  | ||||||
|   `,
 |  | ||||||
|   childrenLeftText: css` |  | ||||||
|     margin-left: 50px; |  | ||||||
|   `,
 |  | ||||||
|   childrenRightText: css` |  | ||||||
|     width: calc(100% - 265px); |  | ||||||
|   `,
 |  | ||||||
|   childrenlangText: css` |  | ||||||
|     margin-left: 50px; |  | ||||||
|     width: calc(100% - 65px); |  | ||||||
|     text-align: left; |  | ||||||
|   `,
 |  | ||||||
|   circleImg: css` |  | ||||||
|     width: 62px; |  | ||||||
|     height: 62px; |  | ||||||
|     line-height: 62px; |  | ||||||
|     display: inline-block; |  | ||||||
|     margin-right: 15px; |  | ||||||
|     text-align: center; |  | ||||||
|     position: relative; |  | ||||||
|     border-radius: 62px; |  | ||||||
|     background-color: #B8C8FF; |  | ||||||
|     border: 1px solid #B8C8FF; |  | ||||||
|   `,
 |  | ||||||
|   optName: css` |  | ||||||
|     display: inline-block; |  | ||||||
|     position: absolute; |  | ||||||
|     line-height: normal; |  | ||||||
|     font-size: 13px; |  | ||||||
|     background: #C1CFFF; |  | ||||||
|     border-radius: 18px; |  | ||||||
|     color: #3A61CB; |  | ||||||
|     bottom: -5px; |  | ||||||
|     left: 10px; |  | ||||||
|     padding: 2px 6px; |  | ||||||
|   `,
 |  | ||||||
|   circleSeleImg: css` |  | ||||||
|     border: 1px solid #0044FF; |  | ||||||
|   `,
 |  | ||||||
|   optSeleName: css` |  | ||||||
|     background: #0044FF; |  | ||||||
|     color: #fff; |  | ||||||
|   `,
 |  | ||||||
|   radioRigh: css` |  | ||||||
|     margin-right: 24px |  | ||||||
|   `,
 |  | ||||||
|   topTitle: css` |  | ||||||
|     font-size: 18px; |  | ||||||
|     font-weight: bold; |  | ||||||
|     color: #333333; |  | ||||||
|   `,
 |  | ||||||
| })) |  | ||||||
| 
 |  | ||||||
| const szrOptions = [ |  | ||||||
|   { |  | ||||||
|     value: '1', |  | ||||||
|     label: 'Jack', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     value: '2', |  | ||||||
|     label: 'Lucy', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     value: '3', |  | ||||||
|     label: 'yiminghe', |  | ||||||
|   }, |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| const yyOptions = [ |  | ||||||
|   { |  | ||||||
|     label: '普通话', |  | ||||||
|     value: 'pth', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     label: '英文', |  | ||||||
|     value: 'yw', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     label: '法语', |  | ||||||
|     value: 'fy', |  | ||||||
|   }, |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| const Page = memo(() => { |  | ||||||
|   const [form] = Form.useForm() |  | ||||||
|   const { styles, cx } = useStyles() |  | ||||||
|   const [optValue, setOptValue] = useState("") |  | ||||||
| 
 |  | ||||||
|   useEffect(() => { |  | ||||||
|     form.setFieldsValue({ |  | ||||||
|       szr: '1', |  | ||||||
|       yy: 'pth', |  | ||||||
|       ys: '1.0', |  | ||||||
|       ysnum: '1.0', |  | ||||||
|       yd: '1.0', |  | ||||||
|       ydnum: '1.0', |  | ||||||
|       yl: '1.0', |  | ||||||
|       ylnum: '1.0', |  | ||||||
|     }) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   const onChangeYs = (val) => { |  | ||||||
|     form.setFieldsValue({ |  | ||||||
|       ysnum: val |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   const onChangeYd = (val) => { |  | ||||||
|     form.setFieldsValue({ |  | ||||||
|       ydnum: val |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   const onChangeYl = (val) => { |  | ||||||
|     form.setFieldsValue({ |  | ||||||
|       ylnum: val |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   const onClickYin = (e) => { |  | ||||||
|     setOptValue(e.id) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return ( |  | ||||||
|     <> |  | ||||||
|       <Form form={form} style={{ marginBottom: '30px' }}> |  | ||||||
|         <div className={cx(styles.onlyDiv, styles.topTitle)}> |  | ||||||
|           <div className={cx(styles.leftText)}>数字人形象</div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>选择数字人</div> |  | ||||||
|           <div className={cx(styles.rightText)}> |  | ||||||
|             <Form.Item label="" name="szr"> |  | ||||||
|               <Select |  | ||||||
|                 style={{ width: 120, textAlign: 'left' }} |  | ||||||
|                 options={szrOptions} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>数字人形象</div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.rightText, styles.childrenlangText)} style={{ textAlgin: 'center' }}> |  | ||||||
|             <Image alt={'数字人形象'} src="/images/szrxx.png" preview={false} /> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv, styles.topTitle)}> |  | ||||||
|           <div className={cx(styles.leftText)}>声音设置</div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>语言</div> |  | ||||||
|           <div className={cx(styles.rightText)}> |  | ||||||
|             <Form.Item label="" name="yy"> |  | ||||||
|               <Select |  | ||||||
|                 style={{ width: 120, textAlign: 'left' }} |  | ||||||
|                 options={yyOptions} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>风格</div> |  | ||||||
|           <div className={cx(styles.rightText)}> |  | ||||||
|             <Form.Item label="" name="fg"> |  | ||||||
|               <Radio.Group disabled buttonStyle="solid"> |  | ||||||
|                 <Radio.Button className={styles.radioRigh} value="mr">默认</Radio.Button> |  | ||||||
|                 <Radio.Button className={styles.radioRigh} value="xw">新闻</Radio.Button> |  | ||||||
|                 <Radio.Button className={styles.radioRigh} value="xx">小说</Radio.Button> |  | ||||||
|                 <Radio.Button className={styles.radioRigh} value="zs">知识</Radio.Button> |  | ||||||
|               </Radio.Group> |  | ||||||
|             </Form.Item> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>语速</div> |  | ||||||
|           <div className={cx(styles.rightText)}> |  | ||||||
|             <Form.Item style={{ display: 'inline-block'}} label="" name="ys"> |  | ||||||
|               <Slider |  | ||||||
|                 style={{ width: "120px" }} |  | ||||||
|                 min={0} |  | ||||||
|                 max={2} |  | ||||||
|                 onChange={(e) => onChangeYs(e)} |  | ||||||
|                 step={0.1} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|             <Form.Item style={{ display: 'inline-block'}} label="" name="ysnum"> |  | ||||||
|               <InputNumber |  | ||||||
|                 min={0} |  | ||||||
|                 max={2} |  | ||||||
|                 style={{ |  | ||||||
|                   margin: '0 16px', |  | ||||||
|                 }} |  | ||||||
|                 step={0.1} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>语调</div> |  | ||||||
|           <div className={cx(styles.rightText)}> |  | ||||||
|             <Form.Item style={{ display: 'inline-block'}} label="" name="yd"> |  | ||||||
|               <Slider |  | ||||||
|                 style={{ width: "120px" }} |  | ||||||
|                 min={0} |  | ||||||
|                 max={2} |  | ||||||
|                 onChange={(e) => onChangeYd(e)} |  | ||||||
|                 step={0.1} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|             <Form.Item style={{ display: 'inline-block'}} label="" name="ydnum"> |  | ||||||
|               <InputNumber |  | ||||||
|                 min={0} |  | ||||||
|                 max={2} |  | ||||||
|                 style={{ |  | ||||||
|                   margin: '0 16px', |  | ||||||
|                 }} |  | ||||||
|                 step={0.1} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>音量</div> |  | ||||||
|           <div className={cx(styles.rightText)}> |  | ||||||
|             <Form.Item style={{ display: 'inline-block'}} label="" name="yl"> |  | ||||||
|               <Slider |  | ||||||
|                 style={{ width: "120px" }} |  | ||||||
|                 min={0} |  | ||||||
|                 max={2} |  | ||||||
|                 onChange={(e) => onChangeYl(e)} |  | ||||||
|                 step={0.1} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|             <Form.Item style={{ display: 'inline-block'}} label="" name="ylnum"> |  | ||||||
|               <InputNumber |  | ||||||
|                 min={0} |  | ||||||
|                 max={2} |  | ||||||
|                 style={{ |  | ||||||
|                   margin: '0 16px', |  | ||||||
|                 }} |  | ||||||
|                 step={0.1} |  | ||||||
|               /> |  | ||||||
|             </Form.Item> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div className={cx(styles.onlyDiv)}> |  | ||||||
|           <div className={cx(styles.leftText)}>音色</div> |  | ||||||
|           <div className={cx(styles.rightText)}> |  | ||||||
|             { |  | ||||||
|               ysOptions.map(e => { |  | ||||||
|                 return ( |  | ||||||
|                   <div className={cx(styles.circleImg, optValue==e.id&&styles.circleSeleImg)} onClick={() => onClickYin(e)}> |  | ||||||
|                     <Image alt={e.name} src={e.icon} preview={false} /> |  | ||||||
|                     <span className={cx(styles.optName, optValue==e.id&&styles.optSeleName)}>{e.name}</span> |  | ||||||
|                   </div> |  | ||||||
|                 ) |  | ||||||
|               }) |  | ||||||
|             } |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </Form> |  | ||||||
|     </> |  | ||||||
|   ); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| Page.displayName = 'SzrSetting'; |  | ||||||
| 
 |  | ||||||
| export default Page; |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| import { metadataModule } from '@/server/metadata'; |  | ||||||
| import { translation } from '@/server/translation'; |  | ||||||
| 
 |  | ||||||
| export const generateMetadata = async () => { |  | ||||||
|   const { t } = await translation('setting'); |  | ||||||
|   return metadataModule.generate({ |  | ||||||
|     description: t('header.desc'), |  | ||||||
|     title: t('tab.szr'), |  | ||||||
|     url: '/settings/szr', |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| export { default } from './index'; |  | ||||||
| @ -1,3 +1,3 @@ | |||||||
| export { AgentSettings, AgentSettingChat, AgentSettingLlm, AgentSettingTts, AgentSettingAbout } from './AgentSettings'; | export { AgentSettings } from './AgentSettings'; | ||||||
| export { AgentSettingsStore } from './AgentSettingsStore'; | export { AgentSettingsStore } from './AgentSettingsStore'; | ||||||
| export type { AgentSettingsInstance } from './hooks/useAgentSettings'; | export type { AgentSettingsInstance } from './hooks/useAgentSettings'; | ||||||
|  | |||||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								| @ -0,0 +1,64 @@ | |||||||
|  | [2025-02-12 11:45:49.403] [INFO ] [kground-preinit] [       org.hibernate.validator.internal.util.Version:21] : HV000001: Hibernate Validator 6.2.5.Final | ||||||
|  | [2025-02-12 11:45:49.424] [INFO ] [           main] [               com.pjilisense.flxai.FlxAiApplication:55] : Starting FlxAiApplication using Java 17.0.12 on DESKTOP-O4CA5AM with PID 20716 (D:\AInew\JZ_QGNB\flx-ai\target\classes started by sunboy in D:\AInew\JZ_QGNB\flx-ai) | ||||||
|  | [2025-02-12 11:45:49.426] [INFO ] [           main] [              com.pjilisense.flxai.FlxAiApplication:637] : The following 1 profile is active: "dev" | ||||||
|  | [2025-02-12 11:45:52.746] [INFO ] [           main] [     o.s.d.r.config.RepositoryConfigurationDelegate:262] : Multiple Spring Data modules found, entering strict repository configuration mode | ||||||
|  | [2025-02-12 11:45:52.756] [INFO ] [           main] [     o.s.d.r.config.RepositoryConfigurationDelegate:132] : Bootstrapping Spring Data Redis repositories in DEFAULT mode. | ||||||
|  | [2025-02-12 11:45:52.815] [INFO ] [           main] [     o.s.d.r.config.RepositoryConfigurationDelegate:201] : Finished Spring Data repository scanning in 24 ms. Found 0 Redis repository interfaces. | ||||||
|  | [2025-02-12 11:45:54.602] [INFO ] [           main] [       o.s.boot.web.embedded.tomcat.TomcatWebServer:108] : Tomcat initialized with port(s): 18080 (http) | ||||||
|  | [2025-02-12 11:45:54.629] [INFO ] [           main] [         org.apache.coyote.http11.Http11NioProtocol:173] : Initializing ProtocolHandler ["http-nio-18080"] | ||||||
|  | [2025-02-12 11:45:54.633] [INFO ] [           main] [           org.apache.catalina.core.StandardService:173] : Starting service [Tomcat] | ||||||
|  | [2025-02-12 11:45:54.633] [INFO ] [           main] [            org.apache.catalina.core.StandardEngine:173] : Starting Servlet engine: [Apache Tomcat/9.0.79] | ||||||
|  | [2025-02-12 11:45:54.915] [INFO ] [           main] [            o.a.c.c.C.[Tomcat].[localhost].[/flxai]:173] : Initializing Spring embedded WebApplicationContext | ||||||
|  | [2025-02-12 11:45:54.920] [INFO ] [           main] [     o.s.b.w.s.c.ServletWebServerApplicationContext:292] : Root WebApplicationContext: initialization completed in 5350 ms | ||||||
|  | [2025-02-12 11:45:55.134] [INFO ] [           main] [            c.a.d.s.b.a.DruidDataSourceAutoConfigure:55] : Init DruidDataSource | ||||||
|  | [2025-02-12 11:45:56.557] [INFO ] [           main] [             com.alibaba.druid.pool.DruidDataSource:975] : {dataSource-1} inited | ||||||
|  | [2025-02-12 11:45:59.480] [INFO ] [           main] [    o.s.b.actuate.endpoint.web.EndpointLinksResolver:58] : Exposing 14 endpoint(s) beneath base path '/actuator' | ||||||
|  | [2025-02-12 11:46:01.227] [INFO ] [           main] [         org.apache.coyote.http11.Http11NioProtocol:173] : Starting ProtocolHandler ["http-nio-18080"] | ||||||
|  | [2025-02-12 11:46:01.311] [INFO ] [           main] [       o.s.boot.web.embedded.tomcat.TomcatWebServer:220] : Tomcat started on port(s): 18080 (http) with context path '/flxai' | ||||||
|  | [2025-02-12 11:46:03.003] [INFO ] [           main] [               com.pjilisense.flxai.FlxAiApplication:61] : Started FlxAiApplication in 15.061 seconds (JVM running for 17.224) | ||||||
|  | [2025-02-12 11:46:06.247] [INFO ] [4)-192.168.56.1] [            o.a.c.c.C.[Tomcat].[localhost].[/flxai]:173] : Initializing Spring DispatcherServlet 'dispatcherServlet' | ||||||
|  | [2025-02-12 11:46:06.252] [INFO ] [4)-192.168.56.1] [  org.springframework.web.servlet.DispatcherServlet:525] : Initializing Servlet 'dispatcherServlet' | ||||||
|  | [2025-02-12 11:46:06.259] [INFO ] [4)-192.168.56.1] [  org.springframework.web.servlet.DispatcherServlet:547] : Completed initialization in 7 ms | ||||||
|  | [2025-02-12 11:46:08.498] [WARN ] [oundedElastic-1] [    o.s.b.actuate.redis.RedisReactiveHealthIndicator:92] : Redis health check failed | ||||||
|  | org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1/<unresolved>:6379 | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1689) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1597) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1383) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getConnection(LettuceConnectionFactory.java:1366) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getSharedReactiveConnection(LettuceConnectionFactory.java:1117) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getReactiveConnection(LettuceConnectionFactory.java:509) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getReactiveConnection(LettuceConnectionFactory.java:103) | ||||||
|  | 	at reactor.core.publisher.MonoSupplier.call(MonoSupplier.java:86) | ||||||
|  | 	at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:227) | ||||||
|  | 	at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) | ||||||
|  | 	at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) | ||||||
|  | 	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) | ||||||
|  | 	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) | ||||||
|  | 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) | ||||||
|  | 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) | ||||||
|  | 	at java.base/java.lang.Thread.run(Thread.java:840) | ||||||
|  | Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1/<unresolved>:6379 | ||||||
|  | 	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78) | ||||||
|  | 	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56) | ||||||
|  | 	at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:330) | ||||||
|  | 	at io.lettuce.core.RedisClient.connect(RedisClient.java:216) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.lambda$getConnection$1(StandaloneConnectionProvider.java:115) | ||||||
|  | 	at java.base/java.util.Optional.orElseGet(Optional.java:364) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.getConnection(StandaloneConnectionProvider.java:115) | ||||||
|  | 	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1595) | ||||||
|  | 	... 14 common frames omitted | ||||||
|  | Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: getsockopt: /127.0.0.1:6379 | ||||||
|  | Caused by: java.net.ConnectException: Connection refused: getsockopt | ||||||
|  | 	at java.base/sun.nio.ch.Net.pollConnect(Native Method) | ||||||
|  | 	at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) | ||||||
|  | 	at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:946) | ||||||
|  | 	at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:337) | ||||||
|  | 	at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) | ||||||
|  | 	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:776) | ||||||
|  | 	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) | ||||||
|  | 	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) | ||||||
|  | 	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) | ||||||
|  | 	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) | ||||||
|  | 	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) | ||||||
|  | 	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) | ||||||
|  | 	at java.base/java.lang.Thread.run(Thread.java:840) | ||||||
					Loading…
					
					
				
		Reference in New Issue