diff --git a/locales/en_US/chat.json b/locales/en_US/chat.json index 3e41ef2bec..3bbdf11123 100644 --- a/locales/en_US/chat.json +++ b/locales/en_US/chat.json @@ -1,23 +1,23 @@ { - "agentDefaultMessage": "Hello, I'm **{{name}}**. You can start chatting with me right away or go to [Assistant Settings](/chat/settings#session={{id}}) to improve my information.", + "agentDefaultMessage": "Hello, I'm **{{name}}**. You can start chatting with me right away or go to [Agent Settings](/chat/settings#session={{id}}) to improve my information.", "agentDefaultMessageWithSystemRole": "Hello, I'm **{{name}}**, {{systemRole}}. Let's start the conversation!", "backToBottom": "Go to Latest Messages", "clearCurrentMessages": "Clear Current Session Messages", "confirmClearCurrentMessages": "You are about to clear the current session messages. Once cleared, they cannot be recovered. Please confirm your operation.", - "confirmRemoveSessionItemAlert": "You are about to delete this assistant. Once deleted, it cannot be recovered. Please confirm your operation.", - "defaultAgent": "Custom Assistant", - "defaultSession": "Custom Assistant", + "confirmRemoveSessionItemAlert": "You are about to delete this agent. Once deleted, it cannot be recovered. Please confirm your operation.", + "defaultAgent": "Custom Agent", + "defaultSession": "Custom Agent", "historyRange": "History Range", "inbox": { - "defaultMessage": "Hello, I'm your intelligent assistant. You can ask me any questions, and I will do my best to answer you. If you need a more professional or customized assistant, you can click on `+` to create a custom assistant.", - "desc": "Activate brain clusters and spark thinking. Your intelligent assistant is here to communicate with you about everything.", + "defaultMessage": "Hello, I'm your intelligent agent. You can ask me any questions, and I will do my best to answer you. If you need a more professional or customized agent, you can click on `+` to create a custom agent.", + "desc": "Activate brain clusters and spark thinking. Your intelligent agent is here to communicate with you about everything.", "title": "Chat Randomly" }, - "newAgent": "Create New Assistant", + "newAgent": "Create New Agent", "noDescription": "No description available", "regenerate": "Regenerate", "roleAndArchive": "Roles and Archives", - "searchAgentPlaceholder": "Search assistants and conversations...", + "searchAgentPlaceholder": "Search agents and conversations...", "send": "Send", "sendPlaceholder": "Enter chat content...", "shareModal": { @@ -29,7 +29,7 @@ "withBackground": "Include Background Image", "withFooter": "Include Footer", "withPluginInfo": "Include Plugin Information", - "withSystemRole": "Include Assistant Role Setting" + "withSystemRole": "Include Agent Role Setting" }, "stop": "Stop", "temp": "Temporary", @@ -50,6 +50,6 @@ "clear": "Clear Translation" }, "translateTo": "Translate", - "updateAgent": "Update Assistant Information", + "updateAgent": "Update Agent Information", "warp": "Line Break" } diff --git a/locales/en_US/setting.json b/locales/en_US/setting.json index 7c71e16cc4..04c340ba60 100644 --- a/locales/en_US/setting.json +++ b/locales/en_US/setting.json @@ -235,6 +235,13 @@ }, "title": "Theme Settings" }, + "submitAgentModal": { + "tooltips": "Share to Assistant Market", + "button": "Submit Assistant", + "identifier": "Identifier", + "metaMiss": "Please complete the assistant information before submitting. It should include name, description, and tags.", + "placeholder": "Please enter a unique identifier for the assistant, such as web-development." + }, "tab": { "agent": "Default Agent", "common": "Common Settings", diff --git a/locales/ja_JP/setting.json b/locales/ja_JP/setting.json index 98fe40d35d..ceca7990ab 100644 --- a/locales/ja_JP/setting.json +++ b/locales/ja_JP/setting.json @@ -222,6 +222,13 @@ }, "title": "テーマ設定" }, + "submitAgentModal": { + "tooltips": "アシスタントマーケットに共有する", + "button": "助手を提出する", + "identifier": "識別子 エージェントの識別子", + "metaMiss": "エージェント情報を入力してから提出してください。名前、説明、およびタグが必要です", + "placeholder": "エージェントの識別子を入力してください。一意である必要があります。例:web-development" + }, "tab": { "agent": "デフォルトのアシスタント", "common": "一般設定", diff --git a/locales/ko_KR/setting.json b/locales/ko_KR/setting.json index 9e1e145155..1e217133db 100644 --- a/locales/ko_KR/setting.json +++ b/locales/ko_KR/setting.json @@ -222,6 +222,13 @@ }, "title": "테마 설정" }, + "submitAgentModal": { + "tooltips": "도우미 마켓에 공유", + "button": "도우미 제출", + "identifier": "식별자 도우미 식별자", + "metaMiss": "도우미 정보를 입력한 후 제출하세요. 이름, 설명 및 태그를 포함해야 합니다.", + "placeholder": "도우미의 식별자를 입력하세요. 고유해야 하며, 예를 들어 web-development과 같은 형식이어야 합니다." + }, "tab": { "agent": "기본 도우미", "common": "일반 설정", diff --git a/locales/ru_RU/common.json b/locales/ru_RU/common.json index c843f5ee2a..d3f3a40b6e 100644 --- a/locales/ru_RU/common.json +++ b/locales/ru_RU/common.json @@ -1,7 +1,8 @@ { "about": "Наш Github", "advanceSettings": "Дополнительные настройки", - "agentDefaultMessage": "Здравствуйте, я **{{name}}**. Вы можете начать общаться со мной прямо сейчас или перейти на [Assistant Settings](/chat/settings#session={{id}}) для моей настройки.", + "agentDefaultMessage": "Здравствуйте, я **{{name}}**. Вы можете начать общаться со мной прямо сейчас или перейти на [Agent Settings](/chat/settings#session={{id}}) для моей настройки.", + "agentMaxToken": "Максимальная длина сессии", "agentModel": "Модель", "agentProfile": "Информация о помощнике", "appInitializing": "LobeChat запускается, пожалуйста, подождите...", diff --git a/locales/ru_RU/setting.json b/locales/ru_RU/setting.json index e73d8f9bdc..2d9dc2add1 100644 --- a/locales/ru_RU/setting.json +++ b/locales/ru_RU/setting.json @@ -235,6 +235,13 @@ }, "title": "Настройки темы" }, + "submitAgentModal": { + "tooltips": "Поделиться на рынке помощников", + "button": "Отправить агента", + "identifier": "Идентификатор агента", + "metaMiss": "Пожалуйста, заполните информацию об агенте перед отправкой. Необходимо указать имя, описание и метки", + "placeholder": "Введите идентификатор агента, который должен быть уникальным, например, web-development" + }, "tab": { "agent": "Помощник по умолчанию", "common": "Общие настройки", diff --git a/locales/zh_CN/setting.json b/locales/zh_CN/setting.json index 5a09e490bb..ff1d68155c 100644 --- a/locales/zh_CN/setting.json +++ b/locales/zh_CN/setting.json @@ -222,6 +222,13 @@ }, "title": "主题设置" }, + "submitAgentModal": { + "button": "提交助手", + "identifier": "identifier 助手标识符", + "metaMiss": "请补全助手信息后提交,需要包含名称、描述和标签", + "placeholder": "请输入助手的标识符,需要是唯一的,比如 web-development", + "tooltips": "分享到助手市场" + }, "tab": { "agent": "默认助手", "common": "通用设置", diff --git a/locales/zh_TW/setting.json b/locales/zh_TW/setting.json index e50c404757..fe30093188 100644 --- a/locales/zh_TW/setting.json +++ b/locales/zh_TW/setting.json @@ -235,6 +235,13 @@ }, "title": "主題設定" }, + "submitAgentModal": { + "tooltips": "分享到助手市場", + "button": "提交助手", + "identifier": "助手識別符", + "metaMiss": "請補全助手資訊後提交,需要包含名稱、描述和標籤", + "placeholder": "請輸入助手的識別符,需要是唯一的,例如 web-development" + }, "tab": { "agent": "預設助理", "common": "通用設定", diff --git a/package.json b/package.json index 2cca6f4660..c56ef17c00 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "@emoji-mart/data": "^1", "@emoji-mart/react": "^1", "@icons-pack/react-simple-icons": "^9", - "@lobehub/chat-plugin-sdk": "^1.17.8", + "@lobehub/chat-plugin-sdk": "latest", "@lobehub/chat-plugins-gateway": "latest", "@lobehub/ui": "latest", "@vercel/analytics": "^1", @@ -79,7 +79,7 @@ "antd-style": "^3.5", "brotli-wasm": "^1", "chroma-js": "^2", - "copy-to-clipboard": "^3.3.3", + "copy-to-clipboard": "^3", "dayjs": "^1", "emoji-mart": "^5", "fast-deep-equal": "^3", @@ -98,6 +98,7 @@ "openai": "^4.10.0", "polished": "^4", "posthog-js": "^1", + "query-string": "^8", "react": "^18", "react-dom": "^18", "react-hotkeys-hook": "^4", @@ -146,7 +147,7 @@ "eslint": "^8", "husky": "^8", "jsdom": "^22", - "lint-staged": "^15.0.0", + "lint-staged": "^15", "lodash": "^4", "next-pwa": "^5", "node-fetch": "^3", diff --git a/scripts/i18nWorkflow/utils.ts b/scripts/i18nWorkflow/utils.ts index feeca468a4..763c35de77 100644 --- a/scripts/i18nWorkflow/utils.ts +++ b/scripts/i18nWorkflow/utils.ts @@ -13,9 +13,12 @@ export const readJSON = (filePath: string) => { return JSON.parse(data); }; +export const replaceAssistantToAgent = (text: string) => + text.replaceAll('assistant', 'agent').replaceAll('Assistant', 'Agent'); + export const writeJSON = (filePath: string, data: any) => { const jsonStr = JSON.stringify(data, null, 2); - writeFileSync(filePath, jsonStr, 'utf8'); + writeFileSync(filePath, replaceAssistantToAgent(jsonStr), 'utf8'); }; export const genResourcesContent = (locales: string[]) => { diff --git a/src/app/chat/features/TopicListContent/SystemRole/index.tsx b/src/app/chat/features/TopicListContent/SystemRole/index.tsx index b96d89ef65..5f78df6011 100644 --- a/src/app/chat/features/TopicListContent/SystemRole/index.tsx +++ b/src/app/chat/features/TopicListContent/SystemRole/index.tsx @@ -5,6 +5,7 @@ import { memo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; +import AgentInfo from '@/features/AgentInfo'; import { useSessionChatInit, useSessionStore } from '@/store/session'; import { agentSelectors } from '@/store/session/selectors'; @@ -15,8 +16,9 @@ const SystemRole = memo(() => { const [openModal, setOpenModal] = useState(false); const [editing, setEditing] = useState(false); const { styles } = useStyles(); - const [systemRole, updateAgentConfig] = useSessionStore((s) => [ + const [systemRole, meta, updateAgentConfig] = useSessionStore((s) => [ agentSelectors.currentAgentSystemRole(s), + agentSelectors.currentAgentMeta(s), s.updateAgentConfig, ]); @@ -57,6 +59,7 @@ const SystemRole = memo(() => { }} onChange={(e) => { updateAgentConfig({ systemRole: e }); }} diff --git a/src/app/chat/settings/(desktop)/Header/index.tsx b/src/app/chat/settings/(desktop)/Header/index.tsx deleted file mode 100644 index 0aad6bba41..0000000000 --- a/src/app/chat/settings/(desktop)/Header/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { memo } from 'react'; - -import { HeaderContent } from '@/app/chat/settings/components/Header'; - -import Layout from './Desktop'; - -const Header = memo(() => ( - - - -)); - -export default Header; diff --git a/src/app/chat/settings/(desktop)/Header/Desktop.tsx b/src/app/chat/settings/(desktop)/features/Header.tsx similarity index 75% rename from src/app/chat/settings/(desktop)/Header/Desktop.tsx rename to src/app/chat/settings/(desktop)/features/Header.tsx index 8a725f8a8b..836ce80976 100644 --- a/src/app/chat/settings/(desktop)/Header/Desktop.tsx +++ b/src/app/chat/settings/(desktop)/features/Header.tsx @@ -1,11 +1,12 @@ import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui'; import { useRouter } from 'next/navigation'; -import { ReactNode, memo } from 'react'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; +import HeaderContent from '@/app/chat/settings/features/HeaderContent'; import { pathString } from '@/utils/url'; -const Header = memo<{ children: ReactNode }>(({ children }) => { +const Header = memo(() => { const { t } = useTranslation('setting'); const router = useRouter(); @@ -13,7 +14,7 @@ const Header = memo<{ children: ReactNode }>(({ children }) => { } onBackClick={() => router.push(pathString('/chat', { hash: location.hash }))} - right={children} + right={} showBackButton /> ); diff --git a/src/app/chat/settings/(desktop)/layout.desktop.tsx b/src/app/chat/settings/(desktop)/layout.desktop.tsx index e46f0847c7..146b885d66 100644 --- a/src/app/chat/settings/(desktop)/layout.desktop.tsx +++ b/src/app/chat/settings/(desktop)/layout.desktop.tsx @@ -5,7 +5,7 @@ import SafeSpacing from '@/components/SafeSpacing'; import { HEADER_HEIGHT } from '@/const/layoutTokens'; import Layout from '../../(desktop)/layout.desktop'; -import Header from './Header'; +import Header from './features/Header'; export default memo(({ children }: PropsWithChildren) => ( diff --git a/src/app/chat/settings/(mobile)/Header.tsx b/src/app/chat/settings/(mobile)/Header.tsx deleted file mode 100644 index 941847c030..0000000000 --- a/src/app/chat/settings/(mobile)/Header.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { memo } from 'react'; - -import { HeaderContent } from '@/app/chat/settings/components/Header'; -import Layout from '@/app/chat/settings/components/Header/Mobile'; - -const Header = memo(() => ( - - - -)); - -export default Header; diff --git a/src/app/chat/settings/components/Header/Mobile.tsx b/src/app/chat/settings/(mobile)/features/Header.tsx similarity index 76% rename from src/app/chat/settings/components/Header/Mobile.tsx rename to src/app/chat/settings/(mobile)/features/Header.tsx index b5cfd6e632..7a4db0fb1a 100644 --- a/src/app/chat/settings/components/Header/Mobile.tsx +++ b/src/app/chat/settings/(mobile)/features/Header.tsx @@ -1,11 +1,12 @@ import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui'; import { useRouter } from 'next/navigation'; -import { type ReactNode, memo } from 'react'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; +import HeaderContent from '@/app/chat/settings/features/HeaderContent'; import { pathString } from '@/utils/url'; -const Header = memo<{ children: ReactNode }>(({ children }) => { +const Header = memo(() => { const { t } = useTranslation('setting'); const router = useRouter(); @@ -13,7 +14,7 @@ const Header = memo<{ children: ReactNode }>(({ children }) => { } onBackClick={() => router.push(pathString('/chat/mobile', { hash: location.hash }))} - right={children} + right={} showBackButton /> ); diff --git a/src/app/chat/settings/(mobile)/layout.mobile.tsx b/src/app/chat/settings/(mobile)/layout.mobile.tsx index 58f9b15613..86923563c7 100644 --- a/src/app/chat/settings/(mobile)/layout.mobile.tsx +++ b/src/app/chat/settings/(mobile)/layout.mobile.tsx @@ -2,7 +2,7 @@ import { PropsWithChildren, memo } from 'react'; import AppLayoutMobile from '@/layout/AppLayout.mobile'; -import Header from './Header'; +import Header from './features/Header'; export default memo(({ children }: PropsWithChildren) => ( }>{children} diff --git a/src/app/chat/settings/components/Header/index.tsx b/src/app/chat/settings/features/HeaderContent.tsx similarity index 80% rename from src/app/chat/settings/components/Header/index.tsx rename to src/app/chat/settings/features/HeaderContent.tsx index a2564b6c81..bc7f9bce11 100644 --- a/src/app/chat/settings/components/Header/index.tsx +++ b/src/app/chat/settings/features/HeaderContent.tsx @@ -9,9 +9,12 @@ import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens'; import { exportSingleAgent, exportSingleSession } from '@/helpers/export'; import { useSessionStore } from '@/store/session'; +import SubmitAgentButton from './SubmitAgentButton'; + export const HeaderContent = memo<{ mobile?: boolean }>(() => { const { t } = useTranslation('setting'); const id = useSessionStore((s) => s.activeId); + const { mobile } = useResponsive(); const items = useMemo( @@ -41,8 +44,13 @@ export const HeaderContent = memo<{ mobile?: boolean }>(() => { const size = mobile ? MOBILE_HEADER_ICON_SIZE : { fontSize: 24 }; return ( - - - + <> + + + + + ); }); + +export default HeaderContent; diff --git a/src/app/chat/settings/features/SubmitAgentButton/Inner.tsx b/src/app/chat/settings/features/SubmitAgentButton/Inner.tsx new file mode 100644 index 0000000000..c5770a015e --- /dev/null +++ b/src/app/chat/settings/features/SubmitAgentButton/Inner.tsx @@ -0,0 +1,86 @@ +import { Alert, Button, Divider, Input } from 'antd'; +import { useTheme } from 'antd-style'; +import isEqual from 'fast-deep-equal'; +import { kebabCase } from 'lodash-es'; +import qs from 'query-string'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import MobilePadding from '@/components/MobilePadding'; +import { AGENTS_INDEX_GITHUB_ISSUE } from '@/const/url'; +import AgentInfo from '@/features/AgentInfo'; +import { useGlobalStore } from '@/store/global'; +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/slices/agentConfig'; + +const Inner = memo(() => { + const { t } = useTranslation('setting'); + const [identifier, setIdentifier] = useState(''); + const systemRole = useSessionStore(agentSelectors.currentAgentSystemRole); + const theme = useTheme(); + const meta = useSessionStore(agentSelectors.currentAgentMeta, isEqual); + const language = useGlobalStore((s) => s.settings.language); + + const isMetaPass = Boolean( + meta && meta.title && meta.description && (meta.tags as string[])?.length > 0 && meta.avatar, + ); + + const handleSubmit = () => { + const body = [ + '### systemRole', + systemRole, + '### identifier', + identifier, + '### avatar', + meta.avatar, + '### title', + meta.title, + '### description', + meta.description, + '### tags', + (meta.tags as string[]).join(', '), + '### locale', + language === 'auto' ? navigator.language : language, + ].join('\n\n'); + + const url = qs.stringifyUrl({ + query: { body, labels: '🤖 Agent PR', title: `[Agent] ${meta.title}` }, + url: AGENTS_INDEX_GITHUB_ISSUE, + }); + + window.open(url, '_blank'); + }; + + return ( + + + {!isMetaPass && ( + + )} + + + + * + {t('submitAgentModal.identifier')} + + setIdentifier(kebabCase(e.target.value))} + placeholder={t('submitAgentModal.placeholder')} + value={identifier} + /> + + + + ); +}); + +export default Inner; diff --git a/src/app/chat/settings/features/SubmitAgentButton/index.tsx b/src/app/chat/settings/features/SubmitAgentButton/index.tsx new file mode 100644 index 0000000000..7c0e4e49d1 --- /dev/null +++ b/src/app/chat/settings/features/SubmitAgentButton/index.tsx @@ -0,0 +1,37 @@ +import { ActionIcon, Modal } from '@lobehub/ui'; +import { useResponsive } from 'antd-style'; +import { Share2 } from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens'; + +import Inner from './Inner'; + +const SubmitAgentButton = memo(() => { + const { t } = useTranslation('setting'); + const { mobile } = useResponsive(); + const [isModalOpen, setIsModalOpen] = useState(false); + const size = mobile ? MOBILE_HEADER_ICON_SIZE : { fontSize: 24 }; + return ( + <> + setIsModalOpen(true)} + size={size} + title={t('submitAgentModal.tooltips')} + /> + setIsModalOpen(false)} + open={isModalOpen} + title={t('submitAgentModal.tooltips')} + > + + + + ); +}); + +export default SubmitAgentButton; diff --git a/src/app/chat/settings/features/SubmitAgentButton/style.ts b/src/app/chat/settings/features/SubmitAgentButton/style.ts new file mode 100644 index 0000000000..7264d5f6bf --- /dev/null +++ b/src/app/chat/settings/features/SubmitAgentButton/style.ts @@ -0,0 +1,46 @@ +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({ css, token, prefixCls }) => ({ + author: css` + font-size: 12px; + `, + + avatar: css` + flex: none; + `, + container: css` + position: relative; + padding: 16px 16px 24px; + border-bottom: 1px solid ${token.colorBorderSecondary}; + `, + date: css` + font-size: 12px; + color: ${token.colorTextDescription}; + `, + desc: css` + color: ${token.colorTextDescription}; + text-align: center; + `, + loading: css` + .${prefixCls}-skeleton-content { + display: flex; + flex-direction: column; + } + `, + nav: css` + padding-top: 4px; + + .${prefixCls}-tabs-tab { + margin: 4px !important; + + + .${prefixCls}-tabs-tab { + margin: 4px !important; + } + } + `, + title: css` + font-size: 20px; + font-weight: 600; + text-align: center; + `, +})); diff --git a/src/app/market/features/AgentSearchBar/index.tsx b/src/app/market/features/AgentSearchBar/index.tsx index 6c5199fe6c..a025ff7a40 100644 --- a/src/app/market/features/AgentSearchBar/index.tsx +++ b/src/app/market/features/AgentSearchBar/index.tsx @@ -1,6 +1,6 @@ import { SearchBar } from '@lobehub/ui'; import { useResponsive } from 'antd-style'; -import { memo } from 'react'; +import { memo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useMarketStore } from '@/store/market'; @@ -8,17 +8,20 @@ import { useMarketStore } from '@/store/market'; const AgentSearchBar = memo(() => { const { t } = useTranslation('market'); const keywords = useMarketStore((s) => s.searchKeywords); + const [value, setValue] = useState(keywords); const { mobile } = useResponsive(); return ( useMarketStore.setState({ searchKeywords: e.target.value })} + onChange={(e) => setValue(e.target.value)} + onPressEnter={() => useMarketStore.setState({ searchKeywords: value })} + onSubmit={() => useMarketStore.setState({ searchKeywords: value })} placeholder={t('search.placeholder')} shortKey={'k'} spotlight={!mobile} type={mobile ? 'block' : 'ghost'} - value={keywords} + value={value} /> ); }); diff --git a/src/chains/agent.ts b/src/chains/agent.ts index 1acd33aa38..1cf3e06318 100644 --- a/src/chains/agent.ts +++ b/src/chains/agent.ts @@ -4,29 +4,24 @@ import { OpenAIChatStreamPayload } from '@/types/openai/chat'; export const promptSummaryAgentName = (content: string): Partial => ({ messages: [ { - content: `你是一名擅长起名的起名大师,你需要将用户的描述总结为 20 个字以内的角色,格式要求如下: -输入: {文本作为JSON引用字符串} -输出: {角色名} -`, + content: `你是一名擅长起名的起名大师,名字需要有文学内涵,注重精炼和赋子意境,你需要将用户的描述总结为 20 个字以内的角色, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色名}`, role: 'system', }, { - content: `输入: {你是一名专业的前端开发者,擅长结合 vitest 和\`testing-library/react\` 书写单元测试。接下来用户会输入一串 ts 代码,你需要给出完善的单元测试。\n你需要注意,单元测试代码中,不应该使用 jest 。如果需要使用 \`jest.fn\`,请使用 \`vi.fn\` 替换}`, + content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`, role: 'user', }, - { content: '前端 vitest 测试专家', role: 'assistant' }, + { content: '创意命名师', role: 'assistant' }, { - content: `输入: {你是一名前端专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`, + content: `输入: {你是一名前端代码专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`, role: 'user', }, - { content: 'js 转 ts 专家', role: 'assistant' }, + { content: 'ts转换魔术师', role: 'assistant' }, { - content: `输入:{你是一名擅长比喻和隐喻的UX Writter。用户会输入文案,你需要给出3个优化后的结果,使用 markdown格式的文本。下面是一个例子: -输入:页面加载中 -输出:页面似乎在思考,一会儿才能准备好}`, + content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`, role: 'user', }, - { content: '文案比喻优化专家', role: 'assistant' }, + { content: '创业咨询专家', role: 'assistant' }, { content: `输入: {${content}}`, role: 'user' }, ], }); @@ -35,42 +30,76 @@ export const promptSummaryAgentName = (content: string): Partial => ({ messages: [ { - content: '你是一名非常懂设计与时尚的设计师,你需要从用户的描述中匹配一个合适的 emoji。', + content: + '你是一名擅长进行概念抽象的设计师与 Emoji 专家,你需要根据角色能力的描述抽象出一个表达物理实体的概念 Emoji 作为角色头像, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {一个Emoji}', role: 'system', }, { - content: `输入:你是一名精通体验设计的设计系统设计师,设计系统存在诸多类别的 token,比如品牌色、成功色等,你需要为各个类别的 token 提供说明文案。`, + content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`, role: 'user', }, + { content: '✒️', role: 'assistant' }, { - content: `💅`, - role: 'assistant', - }, - { - content: `输入:用户会输入一串 ts 代码,为了确保所有功能和分支的 100% 的覆盖率,你需要给出需要考虑哪些数据场景。`, + content: `输入: {你是一名代码巫师,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`, role: 'user', }, + { content: '🧙‍♂️', role: 'assistant' }, { - content: `🧪`, - role: 'assistant', - }, - { - content: `输入:${content}`, + content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`, role: 'user', }, + { content: '🚀', role: 'assistant' }, + { content: `输入: {${content}}`, role: 'user' }, ], }); export const promptSummaryDescription = (content: string): Partial => ({ messages: [ { - content: - '你是一名擅长会话的助理,你需要将用户的输入的内容总结为一个专家的简介,不超过 20 个字', + content: `你是一名擅长技能总结的助理,你需要将用户的输入的内容总结为一个角色技能简介,确保信息清晰、逻辑清晰,并有效地传达角色的技能和经验,不超过 20 个字, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色技能简介}`, role: 'system', }, { - content: `${content}`, + content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`, role: 'user', }, + { content: '擅长文创艺术作品起名', role: 'assistant' }, + { + content: `输入: {你是一名前端代码专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`, + role: 'user', + }, + { content: '擅长 ts 转换和补充类型声明', role: 'assistant' }, + { + content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`, + role: 'user', + }, + { content: '擅长创业计划撰写与咨询', role: 'assistant' }, + { content: `输入: {${content}}`, role: 'user' }, + ], +}); + +export const promptSummaryTags = (content: string): Partial => ({ + messages: [ + { + content: + '你是一名擅长会话标签总结的助理,你需要将用户的输入的内容提炼出分类标签,使用`,`分隔,不超过 5 个标签, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色名}', + role: 'system', + }, + { + content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`, + role: 'user', + }, + { content: '起名,写作,创意', role: 'assistant' }, + { + content: `输入: {你是一名前端专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`, + role: 'user', + }, + { content: '代码,软件开发,效率', role: 'assistant' }, + { + content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`, + role: 'user', + }, + { content: '创业,计划,咨询', role: 'assistant' }, + { content: `输入: {${content}}`, role: 'user' }, ], }); diff --git a/src/components/HotKeys/index.tsx b/src/components/HotKeys/index.tsx index d44523cb1d..e3aeebd95d 100644 --- a/src/components/HotKeys/index.tsx +++ b/src/components/HotKeys/index.tsx @@ -47,9 +47,9 @@ const HotKeys = memo(({ keys, desc }) => { if (!desc) return content; return ( - - {content} + {desc} + {content} ); }); diff --git a/src/components/ResponsiveIndex/index.tsx b/src/components/ResponsiveIndex/index.tsx index 544655b761..e425409a7b 100644 --- a/src/components/ResponsiveIndex/index.tsx +++ b/src/components/ResponsiveIndex/index.tsx @@ -14,10 +14,12 @@ const ResponsiveIndex = ({ children, Mobile }: ResponsiveIndexProps) => { const { t } = useTranslation(); const mobile = useIsMobile(); - return ( + return mobile ? ( }> - {mobile ? : children} + + ) : ( + children ); }; diff --git a/src/const/url.ts b/src/const/url.ts index 550fa2d375..4ea092e0f4 100644 --- a/src/const/url.ts +++ b/src/const/url.ts @@ -43,6 +43,7 @@ export const getAgentJSON = ( }; export const AGENTS_INDEX_GITHUB = 'https://github.com/lobehub/lobe-chat-agents'; +export const AGENTS_INDEX_GITHUB_ISSUE = urlJoin(AGENTS_INDEX_GITHUB, 'issues/new'); export const SESSION_CHAT_URL = (id: string = INBOX_SESSION_ID, mobile?: boolean) => mobile ? `/chat/mobile#session=${id}` : `/chat#session=${id}`; diff --git a/src/features/AgentInfo/index.tsx b/src/features/AgentInfo/index.tsx new file mode 100644 index 0000000000..ef35b9be0c --- /dev/null +++ b/src/features/AgentInfo/index.tsx @@ -0,0 +1,69 @@ +import { Avatar, Markdown, Tag } from '@lobehub/ui'; +import { Divider } from 'antd'; +import { createStyles } from 'antd-style'; +import { startCase } from 'lodash-es'; +import { CSSProperties, memo } from 'react'; +import { Center } from 'react-layout-kit'; + +import { MetaData } from '@/types/meta'; + +const useStyles = createStyles(({ css, token }) => ({ + avatar: css` + flex: none; + `, + desc: css` + color: ${token.colorTextDescription}; + text-align: center; + `, + + title: css` + font-size: 20px; + font-weight: 600; + text-align: center; + `, +})); + +export interface AgentInfoProps { + meta?: MetaData; + style?: CSSProperties; + systemRole?: string; +} + +const AgentInfo = memo(({ systemRole, style, meta }) => { + const { styles, theme } = useStyles(); + + if (!meta) return; + + return ( +
+ {meta.avatar && ( + + )} + {meta.title &&
{meta.title}
} + {(meta?.tags as string[])?.length > 0 && ( +
+ {(meta.tags as string[]).map((tag: string, index) => ( + + {startCase(tag).trim()} + + ))} +
+ )} + {meta.description &&
{meta.description}
} + {systemRole && ( + <> + + {systemRole} + + )} +
+ ); +}); + +export default AgentInfo; diff --git a/src/features/AgentSetting/AgentMeta/AutoGenerateSelect.tsx b/src/features/AgentSetting/AgentMeta/AutoGenerateSelect.tsx new file mode 100644 index 0000000000..980ffe9baf --- /dev/null +++ b/src/features/AgentSetting/AgentMeta/AutoGenerateSelect.tsx @@ -0,0 +1,48 @@ +import { ActionIcon } from '@lobehub/ui'; +import { Select, SelectProps } from 'antd'; +import { useTheme } from 'antd-style'; +import { isString } from 'lodash-es'; +import { Wand2 } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +export interface AutoGenerateInputProps extends SelectProps { + loading?: boolean; + onGenerate?: () => void; +} + +const AutoGenerateSelect = memo( + ({ loading, onGenerate, value, ...props }) => { + const { t } = useTranslation('common'); + const theme = useTheme(); + + return ( +