ai应用一篇通【react环境】

发布时间:2026/9/23 2:30:44

ai应用一篇通【react环境】
首先进行技术选型。1 Deepseek文本大模型其官方具备面向nodejs环境的openai调用模型的sdk。2 环境直接起一个react项目直接在前端项目中调用Deepseek仅学习用生产还是要起nodejs轻服务。一 流式多轮对话1.1 基础请求先发出一个简单的文本请求。下面的apiKey需要替换为自己的key在deepseek开发平台中获取。下面的代码包含了OpenAI的简单用法importOpenAIfromopenai;import{useState,useEffect}fromreact;constopenainewOpenAI({baseURL:https://api.deepseek.com,apiKey:xxxxxxxxxxxxxxxxxxxxx,dangerouslyAllowBrowser:true,});exportdefaultfunctionDeepseekPage(){const[chatList,setChatList]useState([])useEffect((){openai.chat.completions.create({messages:[{role:system,content:You are a helpful assistant.},{role:user,content:hello.},],model:deepseek-v4-flash,thinking:{type:disabled},stream:false,}).then(res{console.log(res.choices[0].message.content);});},[])return(div{chatList.map((msg,index)(div key{index}strong{msg.role}:/strong{msg.content}/div))}/div)}注意下面代码中打印了一个res.choices[0].message.content内容如下{role:assistant,content:Hi! How can I help you today?}其中content是内容role是角色。现在页面上已经展示了一行返回内容了。1.2 多轮对话多轮对话的核心是将第一轮中模型的输出添加到 messages 末尾。上面代码中第一次请求的参数是这样的[{role:system,content:You are a helpful assistant.},{role:user,content:hello.},]我们将返回体和用户的写入内容追加到后面使参数变为[{role:system,content:You are a helpful assistant.},{role:user,content:hello.},{role:assistant,content:Hi! How can I help you today?}{role:user,content:xxxxxx},]同时在用户点击发送后触发接口请求。现在我们要做两件事1 上面代码中的useEffect要重复触发触发条件是有新的用户信息产生时所以书写一个变量记录该信息列表chatList并将其加入到useEffect依赖项中。2 状态的触发需要入口所以添加input和submit入口。exportdefaultfunctionDeepseekPage(){const[chatList,setChatList]useState([{role:system,content:You are a helpful assistant.},{role:user,content:hello.},])const[input,setInput]useState()useEffect((){if(chatList[chatList.length-1].role!user)returnopenai.chat.completions.create({messages:chatList,model:deepseek-v4-flash,thinking:{type:disabled},stream:false,}).then(res{console.log(res.choices[0].message.content);setChatList([...chatList,res.choices[0].message])});},[chatList])return(div{chatList.map((msg,index)(div key{index}strong{msg.role}:/strong{msg.content}/div))}Space vertical sizemediumSpace.Compact style{{width:100%}}Input defaultValueCombine input and buttonvalue{input}onChange{(e)setInput(e.target.value)}/Button typeprimaryonClick{(){setChatList([...chatList,{role:user,content:input}])}}Submit/Button/Space.Compact/Space/div)}现在输入文字点击按钮就可以实现多轮对话了。1.3 流式传输现在ai返回的语句是一次性全部返回的等待时候较长。我们使用ai对话的时候可以让它陆续返回实现打字机效果就是流式传输了。首先将stream设置为true让其开启流式传输。其次要在js中补充承接逻辑。1.3.1 fetch如果使用fetch来处理返回值会返回两个重要的数据value和doneReading。doneReading是流式数据是否已全部返回。value是返回的内容使用new TextDecoder().decode(value)进行解析读取。返回的内容解析后可能出现的情况示例如下第一轮返回data:{choices:[{delta:{content:你第二轮返回}}]}\n\n可以看到解析的时候一个有效json会分成多次返回一个有效json由data开启由\n结束。整个代码逻辑如下1 判断是否已经全部返回否则循环获取数据。2 将本次数据与上次数据相结合形成本次校验是否形成有效json?数据chunkValue。3 将有效数据以’data: ‘为开头’\n’为结尾取出4 解析json串后赋值1.3.2 openai我们这里使用openai来处理。首先将openai.chat.completions.create中的stream设置为true让其开启流式传输。先把useEffect中的代码提取出来成为方法使用。因为这个方法是独立性比较强的所以不需要封装为hook。const getCharDateasync(dataList, callback, streamfalse){letresawait openai.chat.completions.create({messages: dataList, model:deepseek-v4-flash, thinking:{type:disabled}, stream: stream,})callback([...dataList, res.choices[0].message])}现在添加流式处理逻辑。openai已对其做了封装实现流式就比较容易。其会返回异步迭代器Async Iterator直接使用 for await…of 循环来逐块获取数据即可。forawait(const chunk of res){console.log(chunk)}上面打印出的chunk示例如下{id:5a3ce01f-1353-47ed-b355-0337dc890ff6, // 对话id 多组流式对话时靠它拼接object:chat.completion.chunk,created:1784792183,model:deepseek-v4-flash,system_fingerprint:fp_8b330d02d0_prod0820_fp8_kvcache_20260402,choices:[{index:0,delta:{role:assistant,content:// 数据放在这里},logprobs:null,finish_reason:null}]}现在根据chunk内容list有值则拼接无值则添加对话项将id记录在项中用来寻找对应项。forawait(constchunkofres){callback(prevList{constchartIndexItemprevList.findIndex(item{returnitem.charIdchunk.id})if(chartIndexItem-1){return[...prevList,{...chunk.choices[0].delta,charId:chunk.id}]}else{returnprevList.map(item{if(item.charIdchunk.id){return{...item,content:item.contentchunk.choices[0].delta.content}}else{returnitem}})}})}如此就实现了流式效果。1.3.3 设置node中间层上面是在前端项目中直接请求的openai接口实际项目中需要使用node中间层做中转以保护key。中转层在操作时需要注意一下几点:1 发出请求时注意请求头的正确性{Content-Type:text/event-stream,Cache-Control:no-cache,Connection:keep-alive,}返回数据时使用res.write陆续返回。数据返回结束后使用res.end();结束接口。其他逻辑和前端项目中的内容等同都是通过openai获取chund后对数据进行处理。前端可以使用fetch读取流式数据axios不支持。fetch读取流式数据的方式上面有介绍。使用response.body.getReader().read()读取内容new TextDecoder().decode(value)进行解码。response.body.getReader().read()反复读取直到返回的done为true时break。这里也可以使用EventSource但是EventSource仅支持get接口不支持太长的上下文传递。const eventSourcenew EventSource(url);eventSource.addEventListener(message, function(e: any){content.valuee.data;});eventSource.addEventListener(end,(){eventSource.close();});个人更推荐仍然使用openai来在前端读取只是不写秘钥把url改成node中间层的地址。二 图像生成我们仍然选用国内场景大模型可灵ai来做示范。可灵ai需要比文本请求多做一件事通过jsonwebtoken包换取token。当然这一步在生产上肯定是后端做的这里我们就放在前端了。npm i jsonwebtoken安装依赖。2.1 发布任务可灵ai首页左侧有开发者平台按钮开发者平台右上角能进入控制台买个试用资源包然后创建key。和文本一样在header中写Authorization “Bearer XXX”其中 XXX 填写第一步获取的 API Key。现在页面中准备好相关的内容。divstyle{{margin:10px}}Imagewidth{200}srchttps://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png//divSpace verticalsizemediumSpace.Compactstyle{{width:100%}}InputdefaultValueCombine input and buttonvalue{pInput}onChange{(e)setPInput(e.target.value)}/ButtontypeprimaryonClick{()getImage(pInput)}图片生成/Button/Space.Compact/Space然后在getImage事件中根据pInput的值获取图片把图片url给image组件即可。api调用文档https://klingai.com/document-api/api/image/2-1/image-generationconst getImageasync(imageInput){const endPointhttps://api-beijing.klingai.com/v1/images/generationsletresfetch(endPoint,{headers:{Content-Type:application/json,Authorization:Bearer xxxx,}, method:POST, body: JSON.stringify({prompt: imageInput, aspect_ratio:1:1,})})if(res.status400){throw new Error(Non-200 response: ${await res.text()});}const resJsonawait res.json();constidresJson.data.task_id;const resultUrl${endpoint}/${id};console.log(id, resultUrl)// while(true){// 循环获取图片内容直到生成成功 // 返回task_status标志位为succeed即成功 // 成功后task_result中有生成图片的url //}}可灵ai是不支持跨域的所以咋package.json中配置proxy来进行跨域。在文本框中输入文字后点击图片生成id。909536646579253261/v1/images/generations/909536646579253261根据这个id就可以来获取图片内容了。2.2 获取图片现在将while中的内容补全。while(true){// console.log(resJson,id)// 循环获取图片内容直到生成成功// 返回task_status标志位为succeed即成功// 成功后task_result中有生成图片的urlawaitnewPromise((resolve)setTimeout(resolve,100));// 预防堵塞 让出主线程constresultawaitfetch(resultUrl,{headers:{Content-Type:application/json,Authorization:Bearer xxxx,}});constresultJsonawaitresult.json();console.log(resultJson)consttaskStatusresultJson.data.task_status;if(taskStatussucceed){console.log(resultJson.data?.task_result.images[0].url)setImageUrl(resultJson.data?.task_result.images[0].url)returnresultJson.data?.task_result.images[0].url}else{continue}}setImageUrl是这个方法的第二个参数用来赋值图片地址。现在点击生成图片页面上就出现了图片。三 AI应用智能体-------------------------------------------------------------------------------------------------------------未完待续 持续更新

相关新闻

TFLite Micro农业场景声音分类部署实战:鸟鸣、虫鸣与机械噪音的多类别端侧识别系统

TFLite Micro农业场景声音分类部署实战:鸟鸣、虫鸣与机械噪音的多类别端侧识别系统

2026/9/8 19:49:21

TFLite Micro农业场景声音分类部署实战:鸟鸣、虫鸣与机械噪音的多类别端侧识别系统 一、引言:音频分类在智慧农业中的独特价值 农田环境中的声音信息承载着丰富的生态和机械状态信号。鸟类的鸣叫频度可以作为生物多样性的指示指标,而特定害…

装闭 RenoPit 源码解析(05):FastAPI与Celery如何执行AI装修分析

装闭 RenoPit 源码解析(05):FastAPI与Celery如何执行AI装修分析

2026/8/23 12:57:04

AI 装修闭坑分析可能包含多张图片、多份合同以及多次大模型调用,不适合让 FastAPI 请求一直阻塞。装闭 RenoPit 在 fthux/RenoPit 中使用 Celery 和 Redis 编排这条长任务链,本篇分析任务从入队到结束的全过程。 一、FastAPI 只负责启动任务 用户点击“…

百度网盘下载速度突然很慢怎么回事?2026还有解除限制的方法吗

百度网盘下载速度突然很慢怎么回事?2026还有解除限制的方法吗

2026/8/23 12:57:05

不少人可能会遇到这样的困扰:在日常日常使用网络存储服务时,原本几兆甚至几十兆每秒的传输速度,忽然降到了几十KB,或者出现速度忽高忽低、频繁波动的状况。这种现象通常由多重因素共同作用产生,下面梳理了常见的原因及…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/21 18:38:46

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/21 18:41:09

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/21 18:36:40

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/21 18:37:26

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/21 18:40:29

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/21 18:36:17

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/22 0:19:28

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/21 23:38:13

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/22 0:48:53

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…