diff --git a/.env.template b/.env.template index b2a0438d9..4efaa2ff8 100644 --- a/.env.template +++ b/.env.template @@ -1,21 +1,28 @@ - # Your openai api key. (required) OPENAI_API_KEY=sk-xxxx +# DeepSeek Api Key. (Optional) +DEEPSEEK_API_KEY= + # Access password, separated by comma. (optional) CODE=your-password -# You can start service behind a proxy +# You can start service behind a proxy. (optional) PROXY_URL=http://localhost:7890 +# Enable MCP functionality (optional) +# Default: Empty (disabled) +# Set to "true" to enable MCP functionality +ENABLE_MCP= + # (optional) # Default: Empty -# Googel Gemini Pro API key, set if you want to use Google Gemini Pro API. +# Google Gemini Pro API key, set if you want to use Google Gemini Pro API. GOOGLE_API_KEY= # (optional) # Default: https://generativelanguage.googleapis.com/ -# Googel Gemini Pro API url without pathname, set if you want to customize Google Gemini Pro API url. +# Google Gemini Pro API url without pathname, set if you want to customize Google Gemini Pro API url. GOOGLE_URL= # Override openai api request base url. (optional) @@ -47,6 +54,15 @@ ENABLE_BALANCE_QUERY= # If you want to disable parse settings from url, set this value to 1. DISABLE_FAST_LINK= +# (optional) +# Default: Empty +# To control custom models, use + to add a custom model, use - to hide a model, use name=displayName to customize model name, separated by comma. +CUSTOM_MODELS= + +# (optional) +# Default: Empty +# Change default model +DEFAULT_MODEL= # anthropic claude Api Key.(optional) ANTHROPIC_API_KEY= @@ -54,10 +70,14 @@ ANTHROPIC_API_KEY= ### anthropic claude Api version. (optional) ANTHROPIC_API_VERSION= - - ### anthropic claude Api url (optional) ANTHROPIC_URL= ### (optional) -WHITE_WEBDEV_ENDPOINTS= \ No newline at end of file +WHITE_WEBDAV_ENDPOINTS= + +### siliconflow Api key (optional) +SILICONFLOW_API_KEY= + +### siliconflow Api url (optional) +SILICONFLOW_URL= diff --git a/.eslintignore b/.eslintignore index 089752554..61e76e59a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ -public/serviceWorker.js \ No newline at end of file +public/serviceWorker.js +app/mcp/mcp_config.json +app/mcp/mcp_config.default.json \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index d229e86f2..5b5e88e67 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,4 +1,7 @@ { "extends": "next/core-web-vitals", - "plugins": ["prettier"] + "plugins": ["prettier", "unused-imports"], + "rules": { + "unused-imports/no-unused-imports": "warn" + } } diff --git a/.github/ISSUE_TEMPLATE/1_bug_report.yml b/.github/ISSUE_TEMPLATE/1_bug_report.yml new file mode 100644 index 000000000..b576629e3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_bug_report.yml @@ -0,0 +1,80 @@ +name: '🐛 Bug Report' +description: 'Report an bug' +title: '[Bug] ' +labels: ['bug'] +body: + - type: dropdown + attributes: + label: '📦 Deployment Method' + multiple: true + options: + - 'Official installation package' + - 'Vercel' + - 'Zeabur' + - 'Sealos' + - 'Netlify' + - 'Docker' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 Version' + validations: + required: true + + - type: dropdown + attributes: + label: '💻 Operating System' + multiple: true + options: + - 'Windows' + - 'macOS' + - 'Ubuntu' + - 'Other Linux' + - 'iOS' + - 'iPad OS' + - 'Android' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 System Version' + validations: + required: true + - type: dropdown + attributes: + label: '🌐 Browser' + multiple: true + options: + - 'Chrome' + - 'Edge' + - 'Safari' + - 'Firefox' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 Browser Version' + validations: + required: true + - type: textarea + attributes: + label: '🐛 Bug Description' + description: A clear and concise description of the bug, if the above option is `Other`, please also explain in detail. + validations: + required: true + - type: textarea + attributes: + label: '📷 Recurrence Steps' + description: A clear and concise description of how to recurrence. + - type: textarea + attributes: + label: '🚦 Expected Behavior' + description: A clear and concise description of what you expected to happen. + - type: textarea + attributes: + label: '📝 Additional Information' + description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/1_bug_report_cn.yml b/.github/ISSUE_TEMPLATE/1_bug_report_cn.yml new file mode 100644 index 000000000..1977237de --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_bug_report_cn.yml @@ -0,0 +1,80 @@ +name: '🐛 反馈缺陷' +description: '反馈一个问题/缺陷' +title: '[Bug] ' +labels: ['bug'] +body: + - type: dropdown + attributes: + label: '📦 部署方式' + multiple: true + options: + - '官方安装包' + - 'Vercel' + - 'Zeabur' + - 'Sealos' + - 'Netlify' + - 'Docker' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 软件版本' + validations: + required: true + + - type: dropdown + attributes: + label: '💻 系统环境' + multiple: true + options: + - 'Windows' + - 'macOS' + - 'Ubuntu' + - 'Other Linux' + - 'iOS' + - 'iPad OS' + - 'Android' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 系统版本' + validations: + required: true + - type: dropdown + attributes: + label: '🌐 浏览器' + multiple: true + options: + - 'Chrome' + - 'Edge' + - 'Safari' + - 'Firefox' + - 'Other' + validations: + required: true + - type: input + attributes: + label: '📌 浏览器版本' + validations: + required: true + - type: textarea + attributes: + label: '🐛 问题描述' + description: 请提供一个清晰且简洁的问题描述,若上述选项为`Other`,也请详细说明。 + validations: + required: true + - type: textarea + attributes: + label: '📷 复现步骤' + description: 请提供一个清晰且简洁的描述,说明如何复现问题。 + - type: textarea + attributes: + label: '🚦 期望结果' + description: 请提供一个清晰且简洁的描述,说明您期望发生什么。 + - type: textarea + attributes: + label: '📝 补充信息' + description: 如果您的问题需要进一步说明,或者您遇到的问题无法在一个简单的示例中复现,请在这里添加更多信息。 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2_feature_request.yml b/.github/ISSUE_TEMPLATE/2_feature_request.yml new file mode 100644 index 000000000..8576e8a83 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_feature_request.yml @@ -0,0 +1,21 @@ +name: '🌠 Feature Request' +description: 'Suggest an idea' +title: '[Feature Request] ' +labels: ['enhancement'] +body: + - type: textarea + attributes: + label: '🥰 Feature Description' + description: Please add a clear and concise description of the problem you are seeking to solve with this feature request. + validations: + required: true + - type: textarea + attributes: + label: '🧐 Proposed Solution' + description: Describe the solution you'd like in a clear and concise manner. + validations: + required: true + - type: textarea + attributes: + label: '📝 Additional Information' + description: Add any other context about the problem here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2_feature_request_cn.yml b/.github/ISSUE_TEMPLATE/2_feature_request_cn.yml new file mode 100644 index 000000000..c7a3cc370 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_feature_request_cn.yml @@ -0,0 +1,21 @@ +name: '🌠 功能需求' +description: '提出需求或建议' +title: '[Feature Request] ' +labels: ['enhancement'] +body: + - type: textarea + attributes: + label: '🥰 需求描述' + description: 请添加一个清晰且简洁的问题描述,阐述您希望通过这个功能需求解决的问题。 + validations: + required: true + - type: textarea + attributes: + label: '🧐 解决方案' + description: 请清晰且简洁地描述您想要的解决方案。 + validations: + required: true + - type: textarea + attributes: + label: '📝 补充信息' + description: 在这里添加关于问题的任何其他背景信息。 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index bdba257d2..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,146 +0,0 @@ -name: Bug report -description: Create a report to help us improve -title: "[Bug] " -labels: ["bug"] - -body: - - type: markdown - attributes: - value: "## Describe the bug" - - type: textarea - id: bug-description - attributes: - label: "Bug Description" - description: "A clear and concise description of what the bug is." - placeholder: "Explain the bug..." - validations: - required: true - - - type: markdown - attributes: - value: "## To Reproduce" - - type: textarea - id: steps-to-reproduce - attributes: - label: "Steps to Reproduce" - description: "Steps to reproduce the behavior:" - placeholder: | - 1. Go to '...' - 2. Click on '....' - 3. Scroll down to '....' - 4. See error - validations: - required: true - - - type: markdown - attributes: - value: "## Expected behavior" - - type: textarea - id: expected-behavior - attributes: - label: "Expected Behavior" - description: "A clear and concise description of what you expected to happen." - placeholder: "Describe what you expected to happen..." - validations: - required: true - - - type: markdown - attributes: - value: "## Screenshots" - - type: textarea - id: screenshots - attributes: - label: "Screenshots" - description: "If applicable, add screenshots to help explain your problem." - placeholder: "Paste your screenshots here or write 'N/A' if not applicable..." - validations: - required: false - - - type: markdown - attributes: - value: "## Deployment" - - type: checkboxes - id: deployment - attributes: - label: "Deployment Method" - description: "Please select the deployment method you are using." - options: - - label: "Docker" - - label: "Vercel" - - label: "Server" - - - type: markdown - attributes: - value: "## Desktop (please complete the following information):" - - type: input - id: desktop-os - attributes: - label: "Desktop OS" - description: "Your desktop operating system." - placeholder: "e.g., Windows 10" - validations: - required: false - - type: input - id: desktop-browser - attributes: - label: "Desktop Browser" - description: "Your desktop browser." - placeholder: "e.g., Chrome, Safari" - validations: - required: false - - type: input - id: desktop-version - attributes: - label: "Desktop Browser Version" - description: "Version of your desktop browser." - placeholder: "e.g., 89.0" - validations: - required: false - - - type: markdown - attributes: - value: "## Smartphone (please complete the following information):" - - type: input - id: smartphone-device - attributes: - label: "Smartphone Device" - description: "Your smartphone device." - placeholder: "e.g., iPhone X" - validations: - required: false - - type: input - id: smartphone-os - attributes: - label: "Smartphone OS" - description: "Your smartphone operating system." - placeholder: "e.g., iOS 14.4" - validations: - required: false - - type: input - id: smartphone-browser - attributes: - label: "Smartphone Browser" - description: "Your smartphone browser." - placeholder: "e.g., Safari" - validations: - required: false - - type: input - id: smartphone-version - attributes: - label: "Smartphone Browser Version" - description: "Version of your smartphone browser." - placeholder: "e.g., 14" - validations: - required: false - - - type: markdown - attributes: - value: "## Additional Logs" - - type: textarea - id: additional-logs - attributes: - label: "Additional Logs" - description: "Add any logs about the problem here." - placeholder: "Paste any relevant logs here..." - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 499781330..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Feature request -description: Suggest an idea for this project -title: "[Feature Request]: " -labels: ["enhancement"] - -body: - - type: markdown - attributes: - value: "## Is your feature request related to a problem? Please describe." - - type: textarea - id: problem-description - attributes: - label: Problem Description - description: "A clear and concise description of what the problem is. Example: I'm always frustrated when [...]" - placeholder: "Explain the problem you are facing..." - validations: - required: true - - - type: markdown - attributes: - value: "## Describe the solution you'd like" - - type: textarea - id: desired-solution - attributes: - label: Solution Description - description: A clear and concise description of what you want to happen. - placeholder: "Describe the solution you'd like..." - validations: - required: true - - - type: markdown - attributes: - value: "## Describe alternatives you've considered" - - type: textarea - id: alternatives-considered - attributes: - label: Alternatives Considered - description: A clear and concise description of any alternative solutions or features you've considered. - placeholder: "Describe any alternative solutions or features you've considered..." - validations: - required: false - - - type: markdown - attributes: - value: "## Additional context" - - type: textarea - id: additional-context - attributes: - label: Additional Context - description: Add any other context or screenshots about the feature request here. - placeholder: "Add any other context or screenshots about the feature request here..." - validations: - required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..3c4c90803 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,28 @@ +#### 💻 变更类型 | Change Type + + + +- [ ] feat +- [ ] fix +- [ ] refactor +- [ ] perf +- [ ] style +- [ ] test +- [ ] docs +- [ ] ci +- [ ] chore +- [ ] build + +#### 🔀 变更说明 | Description of Change + + + +#### 📝 补充信息 | Additional Information + + diff --git a/.github/workflows/deploy_preview.yml b/.github/workflows/deploy_preview.yml index bdbb78c27..b98845243 100644 --- a/.github/workflows/deploy_preview.yml +++ b/.github/workflows/deploy_preview.yml @@ -3,9 +3,7 @@ name: VercelPreviewDeployment on: pull_request_target: types: - - opened - - synchronize - - reopened + - review_requested env: VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} @@ -49,7 +47,7 @@ jobs: run: npm install --global vercel@latest - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 id: cache-npm with: path: ~/.npm diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..faf7205d9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,39 @@ +name: Run Tests + +on: + push: + branches: + - main + tags: + - "!*" + pull_request: + types: + - review_requested + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: "yarn" + + - name: Cache node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-node_modules- + + - name: Install dependencies + run: yarn install + + - name: Run Jest tests + run: yarn test:ci diff --git a/.gitignore b/.gitignore index b00b0e325..b1c2bfefa 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,9 @@ dev .env *.key -*.key.pub \ No newline at end of file +*.key.pub + +masks.json + +# mcp config +app/mcp/mcp_config.json diff --git a/Dockerfile b/Dockerfile index ae9a17cdd..d3e4193ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,12 +34,16 @@ ENV PROXY_URL="" ENV OPENAI_API_KEY="" ENV GOOGLE_API_KEY="" ENV CODE="" +ENV ENABLE_MCP="" COPY --from=builder /app/public ./public COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/.next/server ./.next/server +RUN mkdir -p /app/app/mcp && chmod 777 /app/app/mcp +COPY --from=builder /app/app/mcp/mcp_config.default.json /app/app/mcp/mcp_config.json + EXPOSE 3000 CMD if [ -n "$PROXY_URL" ]; then \ diff --git a/LICENSE b/LICENSE index 047f9431e..4864ab00d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023-2024 Zhang Yifei +Copyright (c) 2023-2025 NextChat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 499ba8588..cf9165512 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,32 @@
{
if (ref.current) {
- const code = ref.current.innerText;
- copyToClipboard(code);
+ copyToClipboard(
+ ref.current.querySelector("code")?.innerText ?? "",
+ );
}
}}
>
{props.children}
+ {mermaidCode.length > 0 && (
+
+ {props.children}
+
- return escapedText;
+ {renderShowMoreButton()}
+ >
+ );
}
function escapeBrackets(text: string) {
@@ -134,9 +246,30 @@ function escapeBrackets(text: string) {
);
}
+function tryWrapHtmlCode(text: string) {
+ // try add wrap html code (fixed: html codeblock include 2 newline)
+ // ignore embed codeblock
+ if (text.includes("```")) {
+ return text;
+ }
+ return text
+ .replace(
+ /([`]*?)(\w*?)([\n\r]*?)()/g,
+ (match, quoteStart, lang, newLine, doctype) => {
+ return !quoteStart ? "\n```html\n" + doctype : match;
+ },
+ )
+ .replace(
+ /(<\/body>)([\r\n\s]*?)(<\/html>)([\n\r]*)([`]*)([\n\r]*?)/g,
+ (match, bodyEnd, space, htmlEnd, newLine, quoteEnd) => {
+ return !quoteEnd ? bodyEnd + space + htmlEnd + "\n```\n" : match;
+ },
+ );
+}
+
function _MarkDownContent(props: { content: string }) {
const escapedContent = useMemo(() => {
- return escapeBrackets(escapeDollarNumber(props.content));
+ return tryWrapHtmlCode(escapeBrackets(props.content));
}, [props.content]);
return (
@@ -154,9 +287,24 @@ function _MarkDownContent(props: { content: string }) {
]}
components={{
pre: PreCode,
+ code: CustomCode,
p: (pProps) => ,
a: (aProps) => {
const href = aProps.href || "";
+ if (/\.(aac|mp3|opus|wav)$/.test(href)) {
+ return (
+
+
+
+
+
+ {Locale.Sd.Status.Name}: {s}
+
+ {item.status === "error" && (
+ {
+ showModal({
+ title: Locale.Sd.Detail,
+ children: (
+
+ {Locale.SdPanel.Prompt}:{" "}
+ {
+ showModal({
+ title: Locale.Sd.Detail,
+ children: (
+
+ {Locale.SdPanel.AIModel}: {item.model_name} +
+ {getSdTaskStatus(item)} +{item.created_at}
+