Compare commits

...

8 Commits

Author SHA1 Message Date
Coltea fe2d70bfa9
Merge pull request #1559 from KuaiYu95/fix/editor
修复了编辑器一些问题
2025-11-25 18:15:05 +08:00
yu.kuai c9f3a61e86 fix: 导出 markdown 错误
fix: 图片预览底部呈现工具栏
fix: 表格 100% 宽度出现滚动条的问题
2025-11-25 18:04:29 +08:00
Coltea 7b75f1bf55
Merge pull request #1558 from jiangwel/chore-mcp-placeholder
docs(设置页面): 更新MCP Tool输入框的默认值提示文本
2025-11-25 17:36:12 +08:00
jiangwel 07646f0823 chore: 设置默认的tool_name和tool_desc值
设置CardMCP组件中tool_name和tool_desc的默认值,确保功能正常运行
2025-11-25 16:26:52 +08:00
Coltea 63a8d8a743
Merge pull request #1557 from guanweiwang/feature/create_wiki_model
pref: 创建wiki站点,模型配置保存按钮合并到下一步按钮
2025-11-25 16:10:19 +08:00
Coltea 587c2842be
Merge pull request #1555 from coltea/feat-sitemap
feat: auto sitemap
2025-11-25 16:09:44 +08:00
coltea fd34bb4c55 feat: auto sitemap 2025-11-25 16:04:09 +08:00
Gavan 46afba778f pref: 创建wiki站点,模型配置保存按钮合并到下一步按钮 2025-11-25 11:38:55 +08:00
19 changed files with 132 additions and 106 deletions

View File

@ -4516,9 +4516,6 @@ const docTemplate = `{
}
]
},
"auto_sitemap": {
"type": "boolean"
},
"body_code": {
"type": "string"
},
@ -4806,9 +4803,6 @@ const docTemplate = `{
}
]
},
"auto_sitemap": {
"type": "boolean"
},
"body_code": {
"type": "string"
},

View File

@ -4509,9 +4509,6 @@
}
]
},
"auto_sitemap": {
"type": "boolean"
},
"body_code": {
"type": "string"
},
@ -4799,9 +4796,6 @@
}
]
},
"auto_sitemap": {
"type": "boolean"
},
"body_code": {
"type": "string"
},

View File

@ -420,8 +420,6 @@ definitions:
allOf:
- $ref: '#/definitions/domain.AIFeedbackSettings'
description: AI feedback
auto_sitemap:
type: boolean
body_code:
type: string
btns:
@ -601,8 +599,6 @@ definitions:
allOf:
- $ref: '#/definitions/domain.AIFeedbackSettings'
description: AI feedback
auto_sitemap:
type: boolean
body_code:
type: string
btns:

View File

@ -96,9 +96,8 @@ type AppSettings struct {
RecommendQuestions []string `json:"recommend_questions,omitempty"`
RecommendNodeIDs []string `json:"recommend_node_ids,omitempty"`
// seo
Desc string `json:"desc,omitempty"`
Keyword string `json:"keyword,omitempty"`
AutoSitemap bool `json:"auto_sitemap,omitempty"`
Desc string `json:"desc,omitempty"`
Keyword string `json:"keyword,omitempty"`
// inject code
HeadCode string `json:"head_code,omitempty"`
BodyCode string `json:"body_code,omitempty"`
@ -484,9 +483,8 @@ type AppSettingsResp struct {
RecommendQuestions []string `json:"recommend_questions,omitempty"`
RecommendNodeIDs []string `json:"recommend_node_ids,omitempty"`
// seo
Desc string `json:"desc,omitempty"`
Keyword string `json:"keyword,omitempty"`
AutoSitemap bool `json:"auto_sitemap,omitempty"`
Desc string `json:"desc,omitempty"`
Keyword string `json:"keyword,omitempty"`
// inject code
HeadCode string `json:"head_code,omitempty"`
BodyCode string `json:"body_code,omitempty"`

View File

@ -5,7 +5,6 @@ import (
"github.com/labstack/echo/v4"
"github.com/chaitin/panda-wiki/domain"
"github.com/chaitin/panda-wiki/handler"
"github.com/chaitin/panda-wiki/log"
"github.com/chaitin/panda-wiki/usecase"
@ -37,13 +36,6 @@ func (h *ShareSitemapHandler) GetSitemap(c echo.Context) error {
if kbID == "" {
return h.NewResponseWithError(c, "kb_id is required", nil)
}
appInfo, err := h.appUsecase.ShareGetWebAppInfo(c.Request().Context(), kbID, domain.GetAuthID(c))
if err != nil {
return h.NewResponseWithError(c, "web app not found", err)
}
if !appInfo.Settings.AutoSitemap {
return h.NewResponseWithError(c, "未开启自动生成站点地图功能", nil)
}
xml, err := h.sitemapUsecase.GetSitemap(c.Request().Context(), kbID)
if err != nil {

View File

@ -341,12 +341,11 @@ func (r *KnowledgeBaseRepository) CreateKnowledgeBase(ctx context.Context, maxKB
Name: kb.Name,
Type: domain.AppTypeWeb,
Settings: domain.AppSettings{
Title: kb.Name,
Desc: kb.Name,
Keyword: kb.Name,
AutoSitemap: true,
Icon: domain.DefaultPandaWikiIconB64,
WelcomeStr: fmt.Sprintf("欢迎使用%s", kb.Name),
Title: kb.Name,
Desc: kb.Name,
Keyword: kb.Name,
Icon: domain.DefaultPandaWikiIconB64,
WelcomeStr: fmt.Sprintf("欢迎使用%s", kb.Name),
Btns: []any{
AppBtn{
ID: uuid.New().String(),

View File

@ -462,7 +462,6 @@ func (u *AppUsecase) GetAppDetailByKBIDAndAppType(ctx context.Context, kbID stri
RecommendNodeIDs: app.Settings.RecommendNodeIDs,
Desc: app.Settings.Desc,
Keyword: app.Settings.Keyword,
AutoSitemap: app.Settings.AutoSitemap,
HeadCode: app.Settings.HeadCode,
BodyCode: app.Settings.BodyCode,
// DingTalkBot
@ -623,7 +622,6 @@ func (u *AppUsecase) ShareGetWebAppInfo(ctx context.Context, kbID string, authId
RecommendNodeIDs: app.Settings.RecommendNodeIDs,
Desc: app.Settings.Desc,
Keyword: app.Settings.Keyword,
AutoSitemap: app.Settings.AutoSitemap,
HeadCode: app.Settings.HeadCode,
BodyCode: app.Settings.BodyCode,
// theme

View File

@ -323,7 +323,6 @@ export type WelcomeSetting = {
export type SEOSetting = {
keyword: string;
desc: string;
auto_sitemap: boolean;
};
export type CustomCodeSetting = {

View File

@ -65,6 +65,7 @@ const Step1Model: React.FC<Step1ModelProps> = ({ ref }) => {
}, [modelList]);
const onSubmit = async () => {
await modelConfigRef.current?.onSubmit?.();
// 检查模型模式设置
try {
const modeSetting = await getApiV1ModelModeSetting();
@ -112,6 +113,7 @@ const Step1Model: React.FC<Step1ModelProps> = ({ ref }) => {
getModelList={getModelList}
hideDocumentationHint={true}
showTip={true}
showSaveBtn={false}
/>
</Box>
);

View File

@ -44,6 +44,7 @@ const ModelModal = lazy(() =>
export interface ModelConfigRef {
getAutoConfigFormData: () => { apiKey: string; selectedModel: string } | null;
handleClose: () => void;
onSubmit: () => Promise<void>;
}
interface ModelConfigProps {
@ -57,6 +58,7 @@ interface ModelConfigProps {
autoSwitchToAutoMode?: boolean;
hideDocumentationHint?: boolean;
showTip?: boolean;
showSaveBtn?: boolean;
}
const ModelConfig = forwardRef<ModelConfigRef, ModelConfigProps>(
@ -73,6 +75,7 @@ const ModelConfig = forwardRef<ModelConfigRef, ModelConfigProps>(
autoSwitchToAutoMode = false,
hideDocumentationHint = false,
showTip = false,
showSaveBtn = true,
} = props;
const [autoConfigMode, setAutoConfigMode] = useState(false);
@ -182,51 +185,58 @@ const ModelConfig = forwardRef<ModelConfigRef, ModelConfigProps>(
}
return null;
},
onSubmit: handleSave,
handleClose: handleCloseModal,
}));
const handleSave = async () => {
setIsSaving(true);
try {
const requestData: {
mode: 'auto' | 'manual';
auto_mode_api_key?: string;
chat_model?: string;
} = {
mode: tempMode,
};
if (tempMode !== savedMode || hasConfigChanged) {
setIsSaving(true);
try {
const requestData: {
mode: 'auto' | 'manual';
auto_mode_api_key?: string;
chat_model?: string;
} = {
mode: tempMode,
};
// 如果是自动模式,获取用户输入的 API Key 和 model
if (tempMode === 'auto' && autoConfigRef.current) {
const formData = autoConfigRef.current.getFormData();
if (formData) {
requestData.auto_mode_api_key = formData.apiKey;
requestData.chat_model = formData.selectedModel;
// 如果是自动模式,获取用户输入的 API Key 和 model
if (tempMode === 'auto' && autoConfigRef.current) {
const formData = autoConfigRef.current.getFormData();
if (formData) {
requestData.auto_mode_api_key = formData.apiKey;
requestData.chat_model = formData.selectedModel;
}
}
}
await postApiV1ModelSwitchMode(requestData);
setSavedMode(tempMode);
setAutoConfigMode(tempMode === 'auto');
setHasConfigChanged(false); // 重置变更标记
await postApiV1ModelSwitchMode(requestData);
setSavedMode(tempMode);
setAutoConfigMode(tempMode === 'auto');
setHasConfigChanged(false); // 重置变更标记
// 更新保存的初始值
if (tempMode === 'auto' && autoConfigRef.current) {
const formData = autoConfigRef.current.getFormData();
if (formData) {
setInitialApiKey(formData.apiKey);
setInitialChatModel(formData.selectedModel);
// 更新保存的初始值
if (tempMode === 'auto' && autoConfigRef.current) {
const formData = autoConfigRef.current.getFormData();
if (formData) {
setInitialApiKey(formData.apiKey);
setInitialChatModel(formData.selectedModel);
}
}
}
message.success(
tempMode === 'auto' ? '已切换为自动配置模式' : '已切换为手动配置模式',
);
getModelList(); // 刷新模型列表
} catch (err) {
console.error(err);
} finally {
setIsSaving(false);
if (showSaveBtn) {
message.success(
tempMode === 'auto'
? '已切换为自动配置模式'
: '已切换为手动配置模式',
);
}
getModelList(); // 刷新模型列表
} catch (err) {
console.error(err);
} finally {
setIsSaving(false);
}
}
};
@ -310,7 +320,7 @@ const ModelConfig = forwardRef<ModelConfigRef, ModelConfigProps>(
/>
</RadioGroup>
</Box>
{(tempMode !== savedMode || hasConfigChanged) && (
{(tempMode !== savedMode || hasConfigChanged) && showSaveBtn && (
<Button
variant='contained'
size='small'

View File

@ -202,23 +202,32 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
onAiWritingGetSuggestion: handleAiWritingGetSuggestion,
});
const exportFile = (value: string, type: string) => {
if (!value) return;
const content = completeIncompleteLinks(value);
const blob = new Blob([content], { type: `text/${type}` });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${nodeDetail?.name}.${type}`;
a.click();
URL.revokeObjectURL(url);
message.success('导出成功');
};
const handleExport = useCallback(
async (type: string) => {
if (editorRef) {
let value = nodeDetail?.content || '';
if (!isMarkdown) {
value = editorRef.getContent() || '';
if (type === 'html') {
const value = editorRef.getHTML() || '';
exportFile(value, type);
} else if (type === 'md') {
if (isMarkdown) {
let value = nodeDetail?.content || '';
exportFile(value, type);
} else if (editorRef) {
const value = editorRef.getMarkdown() || '';
exportFile(value, type);
}
if (!value) return;
const content = completeIncompleteLinks(value);
const blob = new Blob([content], { type: `text/${type}` });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${nodeDetail?.name}.${type}`;
a.click();
URL.revokeObjectURL(url);
message.success('导出成功');
}
},
[editorRef, nodeDetail?.content, nodeDetail?.name, isMarkdown],

View File

@ -34,8 +34,8 @@ const CardMCP = ({ kb }: CardMCPProps) => {
is_enabled: false,
access: 'open' as 'open' | 'auth',
token: '',
tool_name: '',
tool_desc: '',
tool_name: 'get_docs',
tool_desc: '为解决用户的问题从知识库中检索文档',
},
});

View File

@ -46,6 +46,7 @@ export enum ConstsSourceType {
SourceTypeDiscordBot = "discord_bot",
SourceTypeWechatOfficialAccount = "wechat_official_account",
SourceTypeOpenAIAPI = "openai_api",
SourceTypeMcpServer = "mcp_server",
}
/** @format int32 */
@ -591,7 +592,8 @@ export interface GetApiProV1AuthGetParams {
| "wechat_service_bot"
| "discord_bot"
| "wechat_official_account"
| "openai_api";
| "openai_api"
| "mcp_server";
}
export interface DeleteApiProV1AuthGroupDeleteParams {

View File

@ -78,6 +78,7 @@ export enum DomainAppType {
AppTypeOpenAIAPI = 9,
AppTypeWecomAIBot = 10,
AppTypeLarkBot = 11,
AppTypeMcpServer = 12,
}
export enum ConstsWatermarkSetting {
@ -132,6 +133,7 @@ export enum ConstsSourceType {
SourceTypeDiscordBot = "discord_bot",
SourceTypeWechatOfficialAccount = "wechat_official_account",
SourceTypeOpenAIAPI = "openai_api",
SourceTypeMcpServer = "mcp_server",
}
export enum ConstsNodeRagInfoStatus {
@ -298,7 +300,6 @@ export interface DomainAppInfoResp {
export interface DomainAppSettings {
/** AI feedback */
ai_feedback_settings?: DomainAIFeedbackSettings;
auto_sitemap?: boolean;
body_code?: string;
btns?: unknown[];
/** catalog settings */
@ -333,6 +334,8 @@ export interface DomainAppSettings {
keyword?: string;
/** LarkBot */
lark_bot_settings?: DomainLarkBotSettings;
/** MCP Server Settings */
mcp_server_settings?: DomainMCPServerSettings;
/** OpenAI API Bot settings */
openai_api_bot_settings?: DomainOpenAIAPIBotSettings;
recommend_node_ids?: string[];
@ -384,7 +387,6 @@ export interface DomainAppSettings {
export interface DomainAppSettingsResp {
/** AI feedback */
ai_feedback_settings?: DomainAIFeedbackSettings;
auto_sitemap?: boolean;
body_code?: string;
btns?: unknown[];
/** catalog settings */
@ -419,6 +421,8 @@ export interface DomainAppSettingsResp {
keyword?: string;
/** LarkBot */
lark_bot_settings?: DomainLarkBotSettings;
/** MCP Server Settings */
mcp_server_settings?: DomainMCPServerSettings;
/** OpenAI API settings */
openai_api_bot_settings?: DomainOpenAIAPIBotSettings;
recommend_node_ids?: string[];
@ -926,6 +930,17 @@ export interface DomainLink {
url?: string;
}
export interface DomainMCPServerSettings {
docs_tool_settings?: DomainMCPToolSettings;
is_enabled?: boolean;
sample_auth?: DomainSimpleAuth;
}
export interface DomainMCPToolSettings {
desc?: string;
name?: string;
}
export type DomainMessageContent = Record<string, any>;
export interface DomainMetricsConfig {
@ -1796,7 +1811,8 @@ export interface GetApiV1AuthGetParams {
| "wechat_service_bot"
| "discord_bot"
| "wechat_official_account"
| "openai_api";
| "openai_api"
| "mcp_server";
}
export interface GetApiV1CommentParams {

View File

@ -69,7 +69,6 @@ export interface KBDetail {
recommend_node_ids: string[];
desc: string;
keyword: string;
auto_sitemap: boolean;
head_code: string;
body_code: string;
theme_mode?: 'light' | 'dark';

View File

@ -46,6 +46,7 @@ export enum ConstsSourceType {
SourceTypeDiscordBot = "discord_bot",
SourceTypeWechatOfficialAccount = "wechat_official_account",
SourceTypeOpenAIAPI = "openai_api",
SourceTypeMcpServer = "mcp_server",
}
/** @format int32 */
@ -591,7 +592,8 @@ export interface GetApiProV1AuthGetParams {
| "wechat_service_bot"
| "discord_bot"
| "wechat_official_account"
| "openai_api";
| "openai_api"
| "mcp_server";
}
export interface DeleteApiProV1AuthGroupDeleteParams {

View File

@ -78,6 +78,7 @@ export enum DomainAppType {
AppTypeOpenAIAPI = 9,
AppTypeWecomAIBot = 10,
AppTypeLarkBot = 11,
AppTypeMcpServer = 12,
}
export enum ConstsWatermarkSetting {
@ -132,6 +133,7 @@ export enum ConstsSourceType {
SourceTypeDiscordBot = "discord_bot",
SourceTypeWechatOfficialAccount = "wechat_official_account",
SourceTypeOpenAIAPI = "openai_api",
SourceTypeMcpServer = "mcp_server",
}
export enum ConstsNodeRagInfoStatus {
@ -298,7 +300,6 @@ export interface DomainAppInfoResp {
export interface DomainAppSettings {
/** AI feedback */
ai_feedback_settings?: DomainAIFeedbackSettings;
auto_sitemap?: boolean;
body_code?: string;
btns?: unknown[];
/** catalog settings */
@ -333,6 +334,8 @@ export interface DomainAppSettings {
keyword?: string;
/** LarkBot */
lark_bot_settings?: DomainLarkBotSettings;
/** MCP Server Settings */
mcp_server_settings?: DomainMCPServerSettings;
/** OpenAI API Bot settings */
openai_api_bot_settings?: DomainOpenAIAPIBotSettings;
recommend_node_ids?: string[];
@ -384,7 +387,6 @@ export interface DomainAppSettings {
export interface DomainAppSettingsResp {
/** AI feedback */
ai_feedback_settings?: DomainAIFeedbackSettings;
auto_sitemap?: boolean;
body_code?: string;
btns?: unknown[];
/** catalog settings */
@ -419,6 +421,8 @@ export interface DomainAppSettingsResp {
keyword?: string;
/** LarkBot */
lark_bot_settings?: DomainLarkBotSettings;
/** MCP Server Settings */
mcp_server_settings?: DomainMCPServerSettings;
/** OpenAI API settings */
openai_api_bot_settings?: DomainOpenAIAPIBotSettings;
recommend_node_ids?: string[];
@ -926,6 +930,17 @@ export interface DomainLink {
url?: string;
}
export interface DomainMCPServerSettings {
docs_tool_settings?: DomainMCPToolSettings;
is_enabled?: boolean;
sample_auth?: DomainSimpleAuth;
}
export interface DomainMCPToolSettings {
desc?: string;
name?: string;
}
export type DomainMessageContent = Record<string, any>;
export interface DomainMetricsConfig {
@ -1796,7 +1811,8 @@ export interface GetApiV1AuthGetParams {
| "wechat_service_bot"
| "discord_bot"
| "wechat_official_account"
| "openai_api";
| "openai_api"
| "mcp_server";
}
export interface GetApiV1CommentParams {

View File

@ -18,7 +18,7 @@
"license": "ISC",
"packageManager": "pnpm@10.12.1",
"dependencies": {
"@ctzhian/tiptap": "^2.1.2",
"@ctzhian/tiptap": "^2.1.7",
"@ctzhian/ui": "^7.0.5",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",

View File

@ -9,8 +9,8 @@ importers:
.:
dependencies:
'@ctzhian/tiptap':
specifier: ^2.1.2
version: 2.1.2(474df993ec7b9e2d073b831f21aaac02)
specifier: ^2.1.7
version: 2.1.7(474df993ec7b9e2d073b831f21aaac02)
'@ctzhian/ui':
specifier: ^7.0.5
version: 7.0.5(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@mui/icons-material@7.3.4(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@mui/utils@7.3.3(@types/react@19.2.2)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@ -523,8 +523,8 @@ packages:
react: '>=16.9.0'
react-dom: '>=16.9.0'
'@ctzhian/tiptap@2.1.2':
resolution: {integrity: sha512-GXfJJV8ExkvTzmbOB20s2G3Hoy6SIecJlr79mDJd2Stw5LQjN0BAQBJTFnk13yCkspOTy+agHTzoWm2T+UtWOA==}
'@ctzhian/tiptap@2.1.7':
resolution: {integrity: sha512-qfZiG61W1wMK2CnC0dlVIiP5gVpjVBk8rcuE4h9KVpCvJ3PoSu9Xmu8wX5/X7LVhNamCKk9SgkQfGVh+z65iag==}
peerDependencies:
'@emotion/react': ^11
'@emotion/styled': ^11
@ -6156,7 +6156,7 @@ snapshots:
- react-native
- typescript
'@ctzhian/tiptap@2.1.2(474df993ec7b9e2d073b831f21aaac02)':
'@ctzhian/tiptap@2.1.7(474df993ec7b9e2d073b831f21aaac02)':
dependencies:
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@19.2.0)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0)