Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@types/react-copy-to-clipboard": "^5.0.7",
"@types/react-scroll": "^1.8.10",
"@types/remark-heading-id": "^1.0.0",
"axios": "^1.11.0",
"cheerio": "^1.0.0",
"fast-glob": "^3.3.3",
"gray-matter": "^4.0.3",
Expand All @@ -44,9 +45,11 @@
"react": "^19.0.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^19.0.0",
"react-markdown": "^9.0.1",
"react-scroll": "^1.9.3",
"react-slick": "^0.30.3",
"react-stickynode": "^5.0.2",
"react-syntax-highlighter": "^15.5.0",
"read-yaml-file": "^2.1.0",
"rehype-highlight": "^7.0.2",
"rehype-highlight-code-lines": "^1.1.3",
Expand All @@ -72,6 +75,7 @@
"@types/react-dom": "^19",
"@types/react-slick": "^0.23.13",
"@types/react-stickynode": "^4.0.3",
"@types/react-syntax-highlighter": "^15.5.13",
"eslint": "^9",
"eslint-config-next": "^15.4.5",
"eslint-config-prettier": "^10.1.8",
Expand Down
2 changes: 2 additions & 0 deletions src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AIChatBox from '@/components/AIChatBox';
import I18nProvider from '@/components/I18nProvider';
import MessageBox from '@/components/MessageBox';
import { MuiThemeProvider } from '@/components/MuiThemeProvider';
Expand Down Expand Up @@ -47,6 +48,7 @@ export default async function RootLayout({
<Toolbar />
<Box component="main">{children}</Box>
<ScrollTop />
<AIChatBox />
</MuiThemeProvider>
</NextThemeProvider>
</AppRouterCacheProvider>
Expand Down
105 changes: 105 additions & 0 deletions src/app/api/chat/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import axios from 'axios';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
try {
const { message } = await request.json();

if (!message) {
return NextResponse.json(
{ error: 'Message is required' },
{ status: 400 },
);
}

// 检查必要的环境变量
const apiKey = process.env.DASHSCOPE_API_KEY;
const appId = process.env.DASHSCOPE_APP_ID;
const pipelineIds = process.env.DASHSCOPE_PIPELINE_IDS?.split(',') || [];

if (!apiKey) {
console.error('DASHSCOPE_API_KEY not configured');
return NextResponse.json(
{ error: 'AI service not configured' },
{ status: 500 },
);
}

if (!appId) {
console.error('DASHSCOPE_APP_ID not configured');
return NextResponse.json(
{ error: 'AI service not configured' },
{ status: 500 },
);
}

const url = `https://dashscope.aliyuncs.com/api/v1/apps/${appId}/completion`;

const data = {
input: {
prompt: message,
},
parameters: {
rag_options: {
pipeline_ids: pipelineIds.length > 0 ? pipelineIds : undefined,
},
},
debug: {},
};

const response = await axios.post(url, data, {
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
timeout: 30000, // 30 seconds timeout
});

if (response.status === 200) {
const aiResponse =
response.data.output?.text || 'Sorry, I cannot answer this question.';
return NextResponse.json({ response: aiResponse });
} else {
console.error('DashScope API error:', {
status: response.status,
data: response.data,
requestId: response.headers['request_id'],
});
return NextResponse.json(
{ error: 'AI service temporarily unavailable' },
{ status: 500 },
);
}
} catch (error: any) {
console.error('Error calling DashScope API:', error.message);

if (error.response) {
console.error('Response status:', error.response.status);
console.error('Response data:', error.response.data);
}

// Return different responses based on error type
if (error.code === 'ECONNABORTED') {
return NextResponse.json({ error: 'Request timeout' }, { status: 408 });
}

if (error.response?.status === 401) {
return NextResponse.json(
{ error: 'API authentication failed' },
{ status: 401 },
);
}

if (error.response?.status === 429) {
return NextResponse.json(
{ error: 'Rate limit exceeded' },
{ status: 429 },
);
}

return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 },
);
}
}
2 changes: 1 addition & 1 deletion src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
);

// ignore some category
if(["release_notes"].includes(category)) {
if (['release_notes'].includes(category)) {
return;
}

Expand Down
Loading