什么是Cursor
Cursor 是基于 VS Code 开发的一款编辑器,它在保留 VS Code 强大功能和熟悉操作体验的同时,专注于集成 AI 技术,帮助开发者更高效地编写代码。
主界面介绍
关于如何安装,注册,可参考各种视频进行下载学习,如下展示Cursor 界面的组成部分

AI 代码生成实践
背景
依据sping ai 文档,已经可以初步调用ai的api进行自定义,但是实际的输出很单调,而且每次都需要在地址框输入自己的message很繁琐,希望可以达到deepseek的方式,能够一直交互式的咨询,开发一个属于自己的gpt

上手cursor
话不多说,我们直接实战cursor进行适配,让ai帮我们写一个属于自己的ai“世界”:
首次对话
User
帮我生成一个ai界面,类似deepseek的界面,后端ai接口调用为@http://127.0.0.1:8899/ais 参数为message,message的值为我输入的文本
Cursor
我会帮您创建一个类似 Deepseek 的 AI 聊天界面。我们将使用 React 来构建前端,并创建一个美观的现代化界面。让我们一步步来实现这个项目。
首先,我需要检查项目结构。
看起来这是一个全新的项目。我们需要创建一个新的 React 项目。我将使用 Vite 来创建项目,因为它更快速和现代。
现在让我们安装必要的依赖:
现在我将创建必要的文件和组件。首先,让我们修改主应用文件:
import { ChakraProvider, Box, Container } from '@chakra-ui/react'
import Chat from './components/Chat'
function App() {
return (
<ChakraProvider>
<Box minH="100vh" bg="gray.50">
<Container maxW="container.lg" py={8}>
<Chat />
</Container>
</Box>
</ChakraProvider>
)
}
export default App
现在让我们创建聊天组件:
import { useState } from 'react'
import {
Box,
VStack,
Input,
Button,
HStack,
Text,
useToast,
Card,
CardBody,
} from '@chakra-ui/react'
import axios from 'axios'
interface Message {
role: 'user' | 'assistant'
content: string
}
const Chat = () => {
const [messages, setMessages] = useState<Message[]>([])
const [input, setInput] = useState('')
const [isLoading, setIsLoading] = useState(false)
const toast = useToast()
const handleSend = async () => {
if (!input.trim()) return
const userMessage: Message = {
role: 'user',
content: input,
}
setMessages((prev) => [...prev, userMessage])
setInput('')
setIsLoading(true)
try {
const response = await axios.post('http://127.0.0.1:8899/ais', {
message: input,
})
const assistantMessage: Message = {
role: 'assistant',
content: response.data,
}
setMessages((prev) => [...prev, assistantMessage])
} catch (error) {
toast({
title: '发送失败',
description: '无法连接到AI服务',
status: 'error',
duration: 3000,
isClosable: true,
})
} finally {
setIsLoading(false)
}
}
return (
<Box>
<VStack spacing={4} align="stretch" h="calc(100vh - 200px)">
<Box flex={1} overflowY="auto" p={4}>
{messages.map((message, index) => (
<Card
key={index}
mb={4}
bg={message.role === 'user' ? 'blue.50' : 'green.50'}
direction="row"
>
<CardBody>
<Text
fontSize="sm"
color="gray.500"
mb={1}
>
{message.role === 'user' ? '你' : 'AI'}
</Text>
<Text>{message.content}</Text>
</CardBody>
</Card>
))}
</Box>
<HStack spacing={2} p={4} bg="white" borderTop="1px" borderColor="gray.200">
<Input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="输入你的问题..."
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleSend()
}
}}
/>
<Button
colorScheme="blue"
onClick={handleSend}
isLoading={isLoading}
loadingText="发送中"
>
发送
</Button>
</HStack>
</VStack>
</Box>
)
}
export default Chat
让我们修复一些配置问题。首先,我们需要设置 ChakraProvider:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import { ChakraProvider } from '@chakra-ui/react'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ChakraProvider>
<App />
</ChakraProvider>
</React.StrictMode>,
)
让我们修复 App.tsx 中的问题:
import { Box, Container } from '@chakra-ui/react'
import Chat from './components/Chat'
function App() {
return (
<Box minH="100vh" bg="gray.50">
<Container maxW="container.lg" py={8}>
<Chat />
</Container>
</Box>
)
}
export default App
现在让我们启动开发服务器:
我已经创建了一个类似 Deepseek 的 AI 聊天界面。以下是主要功能和特点:
- 现代化的 UI 设计:
- 使用 Chakra UI 组件库实现清爽的界面
- 响应式布局,适配不同屏幕尺寸
- 消息气泡采用卡片式设计
- 交互功能:
- 支持文本输入和发送
- 回车键快捷发送
- 发送状态加载提示
- 错误提示(当 AI 服务不可用时)
- 消息显示:
- 用户消息和 AI 回复使用不同的背景色区分
- 消息区域支持滚动,可以查看历史对话
- 清晰的角色标识("你" 和 "AI")
- API 集成:
- 已配置连接到
http://127.0.0.1:8899/ais接口 - 使用 axios 发送 POST 请求
- 请求参数格式符合要求(使用 message 字段)
- 已配置连接到
现在您可以访问 http://localhost:5173 来查看和使用这个聊天界面。要使用它,您需要确保:
- AI 服务在
http://127.0.0.1:8899/ais正在运行 - 服务接受 POST 请求,并期望接收
message参数 - 服务返回文本响应
如果您需要对界面进行任何调整或者添加新功能,请随时告诉我。
首次总结
cursor帮我生成的界面是无法访问的,且我给的接口为get请求,将自己的需求持续反馈给cursor,等待代码的变更
二次对话
User
我是用的是get请求,请求的参数只有message,不是post请求,而且界面运行为空
Cursor 看起来是因为 Chakra UI 的组件导入和使用有一些问题,导致界面无法正常渲染。让我们修复这些问题:
import { useState } from 'react'
import {
Box,
Stack,
Input,
Button,
Text,
useToast as ChakraToast,
Card as ChakraCard,
CardBody as ChakraCardBody,
} from '@chakra-ui/react'
import axios from 'axios'
interface Message {
role: 'user' | 'assistant'
content: string
}
const Chat = () => {
const [messages, setMessages] = useState<Message[]>([])
const [input, setInput] = useState('')
const [isLoading, setIsLoading] = useState(false)
const toast = ChakraToast()
const handleSend = async () => {
if (!input.trim()) return
const userMessage: Message = {
role: 'user',
content: input,
}
setMessages((prev) => [...prev, userMessage])
setInput('')
setIsLoading(true)
try {
const response = await axios.get('http://127.0.0.1:8899/ais', {
params: {
message: input
}
})
const assistantMessage: Message = {
role: 'assistant',
content: response.data,
}
setMessages((prev) => [...prev, assistantMessage])
} catch (error) {
toast({
title: '发送失败',
description: '无法连接到AI服务',
status: 'error',
duration: 3000,
isClosable: true,
})
} finally {
setIsLoading(false)
}
}
return (
<Box>
<Stack direction="column" spacing={4} h="calc(100vh - 200px)">
<Box flex={1} overflowY="auto" p={4}>
{messages.map((message, index) => (
<ChakraCard
key={index}
mb={4}
bg={message.role === 'user' ? 'blue.50' : 'green.50'}
>
<ChakraCardBody>
<Text
fontSize="sm"
color="gray.500"
mb={1}
>
{message.role === 'user' ? '你' : 'AI'}
</Text>
<Text>{message.content}</Text>
</ChakraCardBody>
</ChakraCard>
))}
</Box>
<Stack direction="row" p={4} bg="white" borderTop="1px" borderColor="gray.200">
<Input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="输入你的问题..."
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleSend()
}
}}
/>
<Button
colorScheme="blue"
onClick={handleSend}
disabled={isLoading}
>
{isLoading ? '发送中...' : '发送'}
</Button>
</Stack>
</Stack>
</Box>
)
}
export default Chat
看来还需要安装一些额外的 Chakra UI 依赖。让我们安装必要的包:
让我们修改 main.tsx 文件来正确设置 Chakra UI:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import { ChakraProvider, extendTheme } from '@chakra-ui/react'
const theme = extendTheme({
styles: {
global: {
body: {
bg: 'gray.50',
},
},
},
})
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ChakraProvider theme={theme}>
<App />
</ChakraProvider>
</React.StrictMode>,
)
让我们重新安装并确保安装正确版本的 Chakra UI:
看来有版本兼容性问题,让我们使用 --legacy-peer-deps 来安装:
现在让我们更新 Chat 组件:
import { useState } from 'react'
import {
Box,
Flex,
Input,
Button,
Text,
useToast,
Container,
} from '@chakra-ui/react'
import axios from 'axios'
interface Message {
role: 'user' | 'assistant'
content: string
}
const Chat = () => {
const [messages, setMessages] = useState<Message[]>([])
const [input, setInput] = useState('')
const [isLoading, setIsLoading] = useState(false)
const toast = useToast()
const handleSend = async () => {
if (!input.trim()) return
const userMessage: Message = {
role: 'user',
content: input,
}
setMessages((prev) => [...prev, userMessage])
setInput('')
setIsLoading(true)
try {
const response = await axios.get('http://127.0.0.1:8899/ais', {
params: {
message: input
}
})
const assistantMessage: Message = {
role: 'assistant',
content: response.data,
}
setMessages((prev) => [...prev, assistantMessage])
} catch (error) {
toast({
title: '发送失败',
description: '无法连接到AI服务',
status: 'error',
duration: 3000,
isClosable: true,
})
} finally {
setIsLoading(false)
}
}
return (
<Flex direction="column" h="calc(100vh - 200px)">
<Box flex={1} overflowY="auto" p={4}>
{messages.map((message, index) => (
<Box
key={index}
mb={4}
bg={message.role === 'user' ? 'blue.50' : 'green.50'}
p={4}
borderRadius="lg"
>
<Text
fontSize="sm"
color="gray.500"
mb={1}
>
{message.role === 'user' ? '你' : 'AI'}
</Text>
<Text>{message.content}</Text>
</Box>
))}
</Box>
<Container maxW="container.xl" p={4} bg="white" borderTop="1px" borderColor="gray.200">
<Flex gap={2}>
<Input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="输入你的问题..."
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleSend()
}
}}
/>
<Button
colorScheme="blue"
onClick={handleSend}
isLoading={isLoading}
loadingText="发送中"
>
发送
</Button>
</Flex>
</Container>
</Flex>
)
}
export default Chat
让我们更新 main.tsx 文件:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import { ChakraProvider } from '@chakra-ui/react'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ChakraProvider>
<App />
</ChakraProvider>
</React.StrictMode>,
)
现在界面应该可以正常显示了。我做了以下改进:
- 简化了组件结构,使用更基础的 Chakra UI 组件
- 使用
Flex替代了Stack来实现更可靠的布局 - 使用
Box替代了Card组件来显示消息 - 修复了所有的类型错误和组件兼容性问题
- 保持了原有的功能:
- GET 请求到
http://127.0.0.1:8899/ais?message=xxx - 加载状态显示
- 错误提示
- 回车发送功能
- 消息历史记录
- GET 请求到
现在界面应该可以正常工作了。你可以:
- 在输入框中输入问题
- 按回车键或点击发送按钮
- 看到发送状态的加载动画
- 查看消息历史记录
- 如果发生错误会看到错误提示
如果你仍然看到任何问题,请告诉我。
二次总结
界面可以正常访问,报错ai服务器错误,实际查看请求状态为200

三次对话
User
我怀疑是跨域的问题,GET http://127.0.0.1:8899/ai?message=%E6%83%B3%E4%BD%A0%E4%BA%86 net::ERR_FAILED 200 (OK)
我服务器使用的springboot项目的java,且在启动类上添加了@CrossOrigin
Cursor
让我们修改一下前端代码,并建议您调整一下后端的 CORS 配置。首先修改前端代码:
import { useState } from 'react'
import {
Box,
Flex,
Input,
Button,
Text,
useToast,
Container,
} from '@chakra-ui/react'
import axios from 'axios'
interface Message {
role: 'user' | 'assistant'
content: string
}
// 创建axios实例
const api = axios.create({
baseURL: 'http://127.0.0.1:8899',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
}
})
const Chat = () => {
const [messages, setMessages] = useState<Message[]>([])
const [input, setInput] = useState('')
const [isLoading, setIsLoading] = useState(false)
const toast = useToast()
const handleSend = async () => {
if (!input.trim()) return
const userMessage: Message = {
role: 'user',
content: input,
}
setMessages((prev) => [...prev, userMessage])
setInput('')
setIsLoading(true)
try {
const response = await api.get('/ai', {
params: {
message: encodeURIComponent(input)
}
})
console.log('API Response:', response)
// 处理响应数据
let content = ''
if (response.data) {
content = typeof response.data === 'string' ? response.data : response.data.toString()
} else {
content = '抱歉,服务器返回了空响应'
}
const assistantMessage: Message = {
role: 'assistant',
content: content
}
setMessages((prev) => [...prev, assistantMessage])
} catch (error) {
console.error('API Error:', error)
if (axios.isAxiosError(error)) {
toast({
title: '请求失败',
description: error.response?.data?.message || '服务器连接失败,请检查网络',
status: 'error',
duration: 3000,
isClosable: true,
})
} else {
toast({
title: '发送失败',
description: '请求处理失败',
status: 'error',
duration: 3000,
isClosable: true,
})
}
} finally {
setIsLoading(false)
}
}
return (
<Flex direction="column" h="calc(100vh - 200px)">
<Box flex={1} overflowY="auto" p={4}>
{messages.map((message, index) => (
<Box
key={index}
mb={4}
bg={message.role === 'user' ? 'blue.50' : 'green.50'}
p={4}
borderRadius="lg"
>
<Text
fontSize="sm"
color="gray.500"
mb={1}
>
{message.role === 'user' ? '你' : 'AI'}
</Text>
<Text whiteSpace="pre-wrap">{message.content}</Text>
</Box>
))}
</Box>
<Container maxW="container.xl" p={4} bg="white" borderTop="1px" borderColor="gray.200">
<Flex gap={2}>
<Input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="输入你的问题..."
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleSend()
}
}}
/>
<Button
colorScheme="blue"
onClick={handleSend}
isLoading={isLoading}
loadingText="发送中"
>
发送
</Button>
</Flex>
</Container>
</Flex>
)
}
export default Chat
同时,我建议您在 Spring Boot 后端做如下修改。在启动类上使用 @CrossOrigin 可能不够完整,建议您创建一个专门的 CORS 配置类:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173") // 允许前端开发服务器的域名
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.maxAge(3600);
}
}
前端代码的主要改动:
- 简化了 axios 配置
- 添加了请求超时设置
- 对输入进行 URL 编码
- 改进了响应数据的处理方式
- 优化了错误提示信息
如果仍然遇到问题,请:
- 确保后端接口返回的是纯文本或 JSON 格式的数据
- 检查后端日志,看是否有异常信息
- 在浏览器控制台中查看具体的错误信息
您也可以在后端的接口方法上添加更具体的 CORS 配置:
@GetMapping("/ai")
@CrossOrigin(origins = "http://localhost:5173")
public String chat(@RequestParam String message) {
// 你的处理逻辑
}
如果还有问题,请告诉我:
- 后端接口的具体返回格式是什么?
- 浏览器控制台是否有具体的错误信息?
- 后端日志是否显示收到了请求?
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173") // 允许前端开发服务器的域名
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.maxAge(3600);
}
}
@GetMapping("/ai")
@CrossOrigin(origins = "http://localhost:5173")
public String chat(@RequestParam String message) {
// 你的处理逻辑
}
三次总结
按照上述变更,给程序添加了跨域的Configuration,随后功能正常,获取接口数据正常,映射正常

AI一天,人间一年
仅仅和Cursor进行了三次交互,就做出了属于自己的gpt,深感震撼ai的伟大,这也是为什么有AI一天,人间一年的说法


评论区
评论加载中...