Skip to content

Commit

Permalink
feat: 新增接入阿里云百炼模型 AI页面施工 (#68)
Browse files Browse the repository at this point in the history
* feat: Integrated Alibaba Cloud's BaiLian model (#67)

* fix upload pnpm lock file

* fix: 修复打包不成功的问题

* fix: 修复pnpm lock文件的样式问题

* fix: 修复pnpm lock文件的样式问题

---------

Co-authored-by: 周欣愉 <[email protected]>
  • Loading branch information
GavinZhou0125 and 周欣愉 authored Jul 18, 2024
1 parent 4a97823 commit 83a0bb9
Show file tree
Hide file tree
Showing 16 changed files with 428 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MODEL_API_BASE_URL=https://dashscope.aliyuncs.com/api/v1/apps/

QWEN_APP_ID=
QWEN_AUTH=
4 changes: 4 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MODEL_API_BASE_URL=https://dashscope.aliyuncs.com/api/v1/apps/

QWEN_APP_ID=
QWEN_AUTH=
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts

*storybook.log
*storybook.log
30 changes: 30 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,36 @@ const nextConfig = {
eslint: {
ignoreDuringBuilds: true,
},
compress: false, // 禁用gzip压缩
async rewrites() {
return [
{
source: '/ai/:path*',
destination: `${process.env.MODEL_API_BASE_URL}${process.env.QWEN_APP_ID}/:path*`, // 你想要代理的外部 API
},
];
},
async headers() {
return [
{
source: '/ai/:path*',
headers: [
{
key: 'Content-Type',
value: 'application/json',
},
{
key: 'Authorization',
value: `Bearer ${process.env.QWEN_AUTH}`,
},
{
key: 'Accept',
value: `text/event-stream`,
},
],
},
]
},
};

export default withNextDevtools(nextConfig);
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@giscus/react": "^3.0.0",
"@microsoft/fetch-event-source": "^2.0.1",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-avatar": "^1.1.0",
Expand Down
36 changes: 36 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added public/qwen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion src/app/edit/(main)/(router)/ai/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import React from 'react';

import { ChatLayout } from '@/components/ai/chat/chat-layout';

const AI = () => {
return <div>AI</div>;
return (
<div className="h-full pb-2">
<ChatLayout />
</div>
);
};

export default AI;
85 changes: 85 additions & 0 deletions src/components/ai/chat/chat-bottombar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { FileImage, Paperclip, Send } from 'lucide-react';
import React, { useRef, useState } from 'react';
import { AnimatePresence, motion } from 'framer-motion';

import { Message, loggedInUserData } from './data';
import { Textarea } from './textarea';

interface ChatBottombarProps {
sendMessage: (newMessage: Message) => void;
}

export const BottombarIcons = [{ icon: FileImage }, { icon: Paperclip }];

export default function ChatBottombar({ sendMessage }: ChatBottombarProps) {
const [message, setMessage] = useState('');
const inputRef = useRef<HTMLTextAreaElement>(null);

const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setMessage(event.target.value);
};

const handleSend = () => {
if (message.trim()) {
const newMessage: Message = {
id: Date.now(),
name: loggedInUserData.name,
avatar: loggedInUserData.avatar,
sessionId: loggedInUserData.sessionId,
message: message.trim(),
};
sendMessage(newMessage);
setMessage('');

if (inputRef.current) {
inputRef.current.focus();
}
}
};

const handleKeyPress = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
handleSend();
}

if (event.key === 'Enter' && event.shiftKey) {
event.preventDefault();
setMessage((prev) => prev + '\n');
}
};

return (
<div className="p-2 flex justify-between w-full items-center gap-2">
<AnimatePresence initial={false}>
<motion.div
key="input"
className="flex items-center justify-around gap-2 w-full relative"
layout
initial={{ opacity: 0, scale: 1 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 1 }}
transition={{
opacity: { duration: 0.05 },
layout: {
type: 'spring',
bounce: 0.15,
},
}}
>
<Textarea
autoComplete="off"
value={message}
ref={inputRef}
onKeyDown={handleKeyPress}
onChange={handleInputChange}
name="message"
placeholder="Aa"
className="w-full border rounded-full flex items-center h-9 resize-none overflow-hidden bg-background"
></Textarea>
<Send onClick={handleSend} />
</motion.div>
</AnimatePresence>
</div>
);
}
Loading

0 comments on commit 83a0bb9

Please sign in to comment.