当前位置: 首页 > article >正文

Phi-3-mini-128k-instruct开发实战:Vue3前端调用大模型API全流程

Phi-3-mini-128k-instruct开发实战Vue3前端调用大模型API全流程最近在捣鼓一个智能对话的小项目后端用上了微软新出的Phi-3-mini-128k-instruct模型推理速度挺快效果也不错。但前端这块儿怎么在Vue3里优雅地调用这个API特别是处理流式响应和管理对话历史着实让我琢磨了一阵子。今天就把这套从零到一的前端集成方案分享给你包含请求封装、流式处理、状态管理这些核心环节最后还会给你一个开箱即用的聊天组件代码。如果你也在Vue3项目里对接过大模型API或者正打算这么做这篇应该能帮你省下不少踩坑的时间。1. 项目准备与环境搭建在开始写代码之前咱们先把基础环境搭好。这个过程不复杂跟着步骤走就行。1.1 创建Vue3项目如果你还没有现成的项目可以用Vite快速创建一个。打开终端执行下面这行命令npm create vuelatest my-phi3-project创建过程中它会问你几个问题像是否要加TypeScript、路由、状态管理这些。对于咱们这个项目我建议把TypeScript和Pinia状态管理选上其他的按需选择就行。选完以后进入项目目录安装依赖cd my-phi3-project npm install1.2 安装必要的依赖咱们这个方案需要用到几个关键的库。在项目根目录下运行npm install axiosaxios: 用来发HTTP请求比原生的fetch用起来更方便拦截器、错误处理这些功能都很成熟。如果你的项目里打算用图标可以再装个lucide-vue-next它提供了一套挺好看的图标集。安装完以后可以先运行npm run dev看看项目能不能正常启动。没问题的话咱们就进入正题。2. 核心工具层API请求封装直接在每个组件里写axios.post太零散了也不好统一管理。咱们把跟大模型API相关的操作都封装到单独的工具模块里。2.1 创建API客户端在src目录下新建一个utils文件夹然后在里面创建apiClient.js文件。// src/utils/apiClient.js import axios from axios; // 创建一个配置好的axios实例方便统一管理基地址、超时时间等 const apiClient axios.create({ // 这里填你后端服务的地址。本地开发通常是 localhost:8000 或类似 baseURL: import.meta.env.VITE_API_BASE_URL || http://localhost:8000, timeout: 60000, // 超时时间设长一点大模型响应可能比较慢 headers: { Content-Type: application/json, }, }); // 请求拦截器可以在发送请求前做些事情比如统一加token apiClient.interceptors.request.use( (config) { // 假设你的后端需要认证可以从localStorage或Pinia store里取token // const token localStorage.getItem(auth_token); // if (token) { // config.headers.Authorization Bearer ${token}; // } return config; }, (error) { return Promise.reject(error); } ); // 响应拦截器统一处理错误比如网络问题、服务器错误 apiClient.interceptors.response.use( (response) { // 请求成功直接返回数据部分 return response.data; }, (error) { // 请求失败这里可以根据HTTP状态码做统一的错误提示 console.error(API请求错误:, error); let message 请求失败请稍后重试; if (error.response) { // 服务器返回了错误状态码 (4xx, 5xx) switch (error.response.status) { case 401: message 未授权请登录; break; case 403: message 拒绝访问; break; case 404: message 请求地址出错: ${error.response.config.url}; break; case 500: message 服务器内部错误; break; default: message 网络错误: ${error.response.status}; } } else if (error.request) { // 请求发了但没收到响应可能是网络断了 message 网络异常请检查网络连接; } // 这里可以触发一个全局的错误提示比如用Element Plus的Message // ElMessage.error(message); return Promise.reject(new Error(message)); } ); export default apiClient;这个客户端把axios包了一层加上了基地址、超时设置和全局的错误处理逻辑。注意那个VITE_API_BASE_URL它是从环境变量里读的这样区分开发环境和生产环境就很方便。在项目根目录创建.env.development和.env.production文件来分别配置。2.2 封装大模型服务接下来创建专门调用Phi-3模型的服务。在src/utils下再建一个phi3Service.js。// src/utils/phi3Service.js import apiClient from ./apiClient; /** * 发送普通对话请求非流式 * param {string} message - 用户输入的消息 * param {Array} history - 对话历史数组格式 [{role: user, content: xxx}, {role: assistant, content: yyy}] * returns {Promisestring} - 模型返回的完整回复 */ export const sendChatRequest async (message, history []) { try { const response await apiClient.post(/v1/chat/completions, { model: phi-3-mini-128k-instruct, // 根据你后端实际的模型名调整 messages: [ ...history, { role: user, content: message } ], stream: false, // 非流式 max_tokens: 1024, temperature: 0.7, }); // 假设后端返回格式遵循OpenAI API回复在 choices[0].message.content return response.choices[0].message.content; } catch (error) { console.error(发送聊天请求失败:, error); throw error; // 把错误抛出去让调用方处理 } }; /** * 发送流式对话请求Server-Sent Events * 这是一个生成器函数调用后返回一个异步迭代器可以逐块获取回复 * param {string} message - 用户输入的消息 * param {Array} history - 对话历史 * returns {AsyncGeneratorstring, void, unknown} - 每次yield一个回复片段 */ export async function* sendStreamChatRequest(message, history []) { // 注意流式请求我们通常直接用fetch因为axios对SSE的支持不如fetch原生 const baseURL import.meta.env.VITE_API_BASE_URL || http://localhost:8000; const payload { model: phi-3-mini-128k-instruct, messages: [ ...history, { role: user, content: message } ], stream: true, // 关键开启流式 max_tokens: 1024, temperature: 0.7, }; try { const response await fetch(${baseURL}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, // 如果需要认证在这里加Authorization头 }, body: JSON.stringify(payload), }); if (!response.ok) { const errorText await response.text(); throw new Error(HTTP ${response.status}: ${errorText}); } const reader response.body?.getReader(); if (!reader) { throw new Error(响应体不可读); } const decoder new TextDecoder(utf-8); let buffer ; try { while (true) { const { done, value } await reader.read(); if (done) break; buffer decoder.decode(value, { stream: true }); const lines buffer.split(\n); buffer lines.pop(); // 最后一行可能不完整放回buffer for (const line of lines) { if (line.trim() ) continue; if (line.startsWith(data: )) { const data line.slice(6); // 去掉data: 前缀 if (data [DONE]) { return; // 流结束 } try { const parsed JSON.parse(data); const chunk parsed.choices[0]?.delta?.content || ; if (chunk) { yield chunk; // 产出每一个文本片段 } } catch (e) { console.warn(解析SSE数据失败:, e, 原始数据:, data); } } } } } finally { reader.releaseLock(); } } catch (error) { console.error(流式请求失败:, error); throw error; } }这里封装了两个核心方法。sendChatRequest是普通的阻塞式请求等模型全部生成完才返回结果。sendStreamChatRequest是重点它用fetch发起一个流式请求然后通过yield把模型生成的内容一块一块地“吐”出来前端就能实现打字机效果了。3. 状态与UI层构建聊天组件工具层准备好了现在来构建用户能看到和交互的部分。我们会用一个Vue组件来承载聊天界面并用Pinia来管理对话状态。3.1 创建对话状态管理Pinia Store在src/stores目录下如果没有就创建一个新建chatStore.js。// src/stores/chatStore.js import { defineStore } from pinia; import { ref, computed } from vue; export const useChatStore defineStore(chat, () { // 状态 const messageList ref([]); // 对话消息列表 const currentInput ref(); // 用户当前输入 const isLoading ref(false); // 是否正在加载用于非流式 const isStreaming ref(false); // 是否正在流式输出用于流式 // 计算属性 const chatHistory computed(() { // 将消息列表格式化成API需要的 {role, content} 格式只保留最近N轮 return messageList.value .filter(msg msg.role ! error) .map(msg ({ role: msg.role, content: msg.content })) .slice(-10); // 只保留最近10轮对话防止上下文过长 }); // 动作 const addMessage (role, content) { messageList.value.push({ id: Date.now() Math.random(), role, // user 或 assistant content, timestamp: new Date(), }); }; const addErrorMessage (content) { messageList.value.push({ id: Date.now() Math.random(), role: error, content, timestamp: new Date(), }); }; const clearMessages () { messageList.value []; }; const updateLastMessage (newContent) { // 用于流式输出时不断更新最后一条助手消息的内容 const lastMsg messageList.value[messageList.value.length - 1]; if (lastMsg lastMsg.role assistant) { lastMsg.content newContent; } }; return { // 状态 messageList, currentInput, isLoading, isStreaming, // 计算属性 chatHistory, // 动作 addMessage, addErrorMessage, clearMessages, updateLastMessage, }; });这个Store把聊天相关的数据和方法都集中管理起来了。messageList存所有消息chatHistory会自动把它转换成API需要的格式并且只截取最近10轮这是个实用的小技巧避免上下文太长导致模型性能下降或API费用增加。3.2 实现聊天组件最后我们来创建核心的聊天界面组件。在src/components目录下创建Phi3Chat.vue。!-- src/components/Phi3Chat.vue -- template div classchat-container !-- 消息展示区域 -- div classmessages-area refmessagesEndRef div v-formsg in messageList :keymsg.id :class[message-bubble, msg.role] div classmessage-avatar span v-ifmsg.role user/span span v-else-ifmsg.role assistant/span span v-else⚠️/span /div div classmessage-content !-- 用户和错误消息直接显示 -- template v-ifmsg.role ! assistant {{ msg.content }} /template !-- 助手消息如果是流式输出中的最后一条用v-html渲染包含可能的光标 -- template v-else div v-ifisStreaming msg.id streamingMessageId v-htmlformatStreamingContent(msg.content)/div div v-else{{ msg.content }}/div /template /div /div !-- 加载指示器非流式时显示 -- div v-ifisLoading !isStreaming classloading-indicator div classloading-dots span/spanspan/spanspan/span /div 思考中... /div /div !-- 输入区域 -- div classinput-area textarea v-modelcurrentInput keydown.enter.exact.preventhandleSend placeholder输入你的问题...按Enter发送ShiftEnter换行 :disabledisLoading || isStreaming rows3 /textarea div classinput-actions button clickhandleSend :disabled!canSend classsend-button 发送 /button button clickhandleClear classclear-button 清空对话 /button label classstream-toggle input typecheckbox v-modeluseStreaming / 启用流式输出 /label /div /div /div /template script setup import { ref, computed, nextTick, watch } from vue; import { useChatStore } from /stores/chatStore; import { sendChatRequest, sendStreamChatRequest } from /utils/phi3Service; const chatStore useChatStore(); const { messageList, currentInput, isLoading, isStreaming, addMessage, addErrorMessage, clearMessages, updateLastMessage } chatStore; // 本地状态 const useStreaming ref(true); // 是否使用流式输出 const streamingMessageId ref(null); // 当前正在流式输出的消息ID const messagesEndRef ref(null); // 用于滚动到底部的DOM引用 // 计算属性是否可以发送消息 const canSend computed(() { return currentInput.value.trim() ! !isLoading.value !isStreaming.value; }); // 方法滚动到消息底部 const scrollToBottom () { nextTick(() { if (messagesEndRef.value) { messagesEndRef.value.scrollTop messagesEndRef.value.scrollHeight; } }); }; // 方法格式化流式内容可以在这里加光标动画 const formatStreamingContent (content) { // 简单处理可以在这里加一个闪烁的光标 return content span classblinking-cursor|/span; }; // 方法处理发送消息非流式 const handleSendNormal async () { const userMessage currentInput.value.trim(); if (!userMessage) return; // 1. 清空输入框添加用户消息到列表 currentInput.value ; addMessage(user, userMessage); scrollToBottom(); // 2. 设置加载状态 isLoading.value true; addMessage(assistant, ); // 先添加一条空消息占位 scrollToBottom(); try { // 3. 调用API const history chatStore.chatHistory.slice(0, -1); // 获取发送前的历史 const fullResponse await sendChatRequest(userMessage, history); // 4. 更新最后一条助手消息 updateLastMessage(fullResponse); } catch (error) { // 5. 出错处理 console.error(对话出错:, error); // 移除刚才添加的占位助手消息 messageList.value.pop(); // 添加错误消息 addErrorMessage(请求失败: ${error.message}); } finally { // 6. 重置状态 isLoading.value false; scrollToBottom(); } }; // 方法处理发送消息流式 const handleSendStream async () { const userMessage currentInput.value.trim(); if (!userMessage) return; currentInput.value ; addMessage(user, userMessage); scrollToBottom(); // 添加一条初始为空的助手消息并记录其ID addMessage(assistant, ); streamingMessageId.value messageList.value[messageList.value.length - 1].id; isStreaming.value true; scrollToBottom(); try { const history chatStore.chatHistory.slice(0, -1); const streamGenerator sendStreamChatRequest(userMessage, history); let fullResponse ; for await (const chunk of streamGenerator) { fullResponse chunk; updateLastMessage(fullResponse); scrollToBottom(); // 每收到一块都滚动一下 } } catch (error) { console.error(流式对话出错:, error); messageList.value.pop(); // 移除占位消息 addErrorMessage(流式请求失败: ${error.message}); } finally { isStreaming.value false; streamingMessageId.value null; scrollToBottom(); } }; // 方法统一的发送处理 const handleSend () { if (!canSend.value) return; if (useStreaming.value) { handleSendStream(); } else { handleSendNormal(); } }; // 方法清空对话 const handleClear () { if (isLoading.value || isStreaming.value) { if (!confirm(正在生成回复确定要清空吗)) return; } clearMessages(); }; // 监听消息列表变化自动滚动到底部 watch(messageList, () { scrollToBottom(); }, { deep: true }); /script style scoped .chat-container { display: flex; flex-direction: column; height: 600px; max-width: 800px; margin: 0 auto; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; background-color: #fafafa; } .messages-area { flex: 1; padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 16px; } .message-bubble { display: flex; gap: 12px; max-width: 85%; } .message-bubble.user { align-self: flex-end; flex-direction: row-reverse; } .message-bubble.assistant { align-self: flex-start; } .message-bubble.error { align-self: center; max-width: 95%; background-color: #fff2f0; border: 1px solid #ffccc7; border-radius: 8px; padding: 10px 16px; } .message-avatar { width: 36px; height: 36px; border-radius: 50%; background-color: #f0f0f0; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; } .message-bubble.user .message-avatar { background-color: #1890ff; color: white; } .message-bubble.assistant .message-avatar { background-color: #52c41a; color: white; } .message-content { padding: 12px 16px; border-radius: 18px; background-color: white; box-shadow: 0 1px 3px rgba(0,0,0,0.1); line-height: 1.5; word-break: break-word; } .message-bubble.user .message-content { background-color: #1890ff; color: white; border-bottom-right-radius: 4px; } .message-bubble.assistant .message-content { border-bottom-left-radius: 4px; } .input-area { border-top: 1px solid #e0e0e0; padding: 16px; background-color: white; } .input-area textarea { width: 100%; padding: 12px; border: 1px solid #d9d9d9; border-radius: 8px; resize: none; font-family: inherit; font-size: 14px; box-sizing: border-box; margin-bottom: 12px; } .input-area textarea:focus { outline: none; border-color: #1890ff; } .input-actions { display: flex; justify-content: space-between; align-items: center; } .send-button, .clear-button { padding: 8px 20px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: background-color 0.2s; } .send-button { background-color: #1890ff; color: white; } .send-button:hover:not(:disabled) { background-color: #40a9ff; } .send-button:disabled { background-color: #bae7ff; cursor: not-allowed; } .clear-button { background-color: #f5f5f5; color: #666; } .clear-button:hover { background-color: #e8e8e8; } .stream-toggle { display: flex; align-items: center; gap: 6px; font-size: 14px; color: #666; } .loading-indicator { display: flex; align-items: center; gap: 10px; color: #999; font-size: 14px; padding: 10px 0; align-self: center; } .loading-dots { display: inline-flex; gap: 4px; } .loading-dots span { width: 8px; height: 8px; border-radius: 50%; background-color: #1890ff; animation: bounce 1.4s infinite ease-in-out both; } .loading-dots span:nth-child(1) { animation-delay: -0.32s; } .loading-dots span:nth-child(2) { animation-delay: -0.16s; } keyframes bounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1.0); } } .blinking-cursor { animation: blink 1s infinite; color: #999; } keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } } /style这个组件把前面封装的工具和状态都用起来了。界面分成了消息展示区和输入区。消息区能区分用户、助手和错误消息并且支持流式输出的打字机效果。输入区有文本框、发送按钮、清空按钮和一个切换流式/非流式模式的复选框。关键逻辑在handleSendStream函数里它用for await...of循环来消费我们之前封装的那个流式生成器每收到一个文本块就实时更新界面上的消息内容体验就很流畅。4. 集成与使用组件写好了最后一步就是把它用起来。假设你有一个App.vue或者某个页面组件可以这么引入!-- 例如在 src/App.vue 中 -- template div idapp header h1Phi-3 Mini 智能对话/h1 p基于 Phi-3-mini-128k-instruct 模型构建的对话演示/p /header main Phi3Chat / /main /div /template script setup import Phi3Chat from ./components/Phi3Chat.vue; /script style /* 一些全局样式 */ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, sans-serif; background-color: #f5f5f5; } #app { padding: 20px; } header { text-align: center; margin-bottom: 30px; } /style记得确保你的后端服务已经启动并且API地址VITE_API_BASE_URL配置正确。然后运行npm run dev一个功能完整的AI对话前端就跑起来了。5. 总结与扩展思路走完这一套流程你应该能在Vue3项目里比较顺畅地集成大模型API了。这套方案把网络请求、状态管理和UI组件分得比较清楚后续维护或者加新功能都方便。实际用下来流式输出的体验确实比等全部生成完再显示要好得多用户感知到的响应速度更快。对话历史管理那个截取最近N轮的小技巧也挺实用能平衡效果和性能。如果你还想进一步扩展有几个方向可以考虑一个是加个消息持久化把对话记录存到localStorage或者IndexedDB里关掉页面再打开还能看到。另一个是优化UI比如支持消息复制、代码高亮、或者引用消息。如果对话场景复杂可能还需要实现函数调用Function Calling的支持那就在服务层和组件里相应增加处理逻辑。总的来说前端调用大模型API的核心就是处理好异步通信和状态同步。把基础打牢后面的扩展就是水到渠成的事了。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

相关文章:

Phi-3-mini-128k-instruct开发实战:Vue3前端调用大模型API全流程

Phi-3-mini-128k-instruct开发实战:Vue3前端调用大模型API全流程 最近在捣鼓一个智能对话的小项目,后端用上了微软新出的Phi-3-mini-128k-instruct模型,推理速度挺快,效果也不错。但前端这块儿,怎么在Vue3里优雅地调用…...

Docker-compose实战:MySQL主从集群的自动化部署与网络配置

1. 为什么需要MySQL主从集群? 作为开发者,我们经常会遇到数据库性能瓶颈的问题。想象一下,当你的应用用户量突然激增,所有查询请求都压在一台数据库服务器上,那场景就像节假日的高速公路收费站——所有车辆挤在唯一开…...

简单理解:嵌入式 USB 基础通信代码

完整 USB 虚拟串口代码(带超详细注释)// 包含单片机寄存器定义头文件(根据你的芯片型号修改,比如stm32f10x.h) #include "stm32f10x.h"// 包含USB驱动库文件(标准USB设备库) #include…...

思维重构跨设备交互:Scrcpy-iOS如何重新定义手机远程控制体验

思维重构跨设备交互:Scrcpy-iOS如何重新定义手机远程控制体验 【免费下载链接】scrcpy-ios Scrcpy-iOS.app is a remote control tool for Android Phones based on [https://github.com/Genymobile/scrcpy]. 项目地址: https://gitcode.com/gh_mirrors/sc/scrcpy…...

张雪机车 Logo 陷抄袭争议,设计方正式回应

随着张雪机车在赛场夺冠出圈,其品牌 LOGO 一夜之间陷入抄袭争议,4 月 14 日,负责该设计的巴顿品牌设计终于公开回应,把这场持续多日的舆论风波推向了新节点。①事情起因很简单:张雪机车凭借赛事成绩走红后,…...

用Video2X自主掌控视频增强:AI超分辨率与帧插值实战指南

用Video2X自主掌控视频增强:AI超分辨率与帧插值实战指南 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_Trending/vi/vid…...

基于STM32标准库SPI+DMA驱动ST7789:从阻塞刷新到流畅显示的优化实践

1. 从卡顿到流畅:为什么需要SPIDMA驱动ST7789 第一次用STM32的SPI接口驱动ST7789屏幕时,我遇到了一个尴尬的问题:明明已经将SPI时钟调到了最高频率18MHz,全屏刷新时却像幻灯片一样卡顿,实测只有每秒3帧左右。这种性能连…...

“擅自加班” 3 小时后猝死!公司不服工伤认定,反复上诉。网友:这也太狗了吧

①4 月 14 日,一则“员工下班居家工作后猝死,公司拒绝认定工伤”的案件终审判决公布,迅速冲上热搜,引发无数打工人共鸣。2023 年 3 月李某入职郑州某科技公司。2023 年 4 月 17 日下班后续工作:当日 17:00(…...

H3C交换机远程端口镜像配置详解:反射端口方式与VLAN设置

H3C交换机远程端口镜像实战指南:反射端口与VLAN的深度配置解析 在企业网络运维中,流量监控是故障排查和安全审计的重要手段。H3C交换机的远程端口镜像功能,特别是反射端口方式,为跨设备流量监控提供了灵活高效的解决方案。本文将带…...

通过IP地址查询判断网络风险,有哪些具体指标和判断方法?

在风控系统中,IP地址是最基础的判断特征之一。攻击者通过代理池、秒拨IP、云主机等方式绕过规则,如果只依赖简单的地理位置或黑名单,很容易被绕过。本文将结合实际工程经验,梳理IP风险判断的核心指标与可落地的判断方法&#xff0…...

别再乱装PyTorch了!手把手教你用conda搞定Linux下CUDA驱动、Toolkit和PyTorch的版本匹配

深度学习环境搭建避坑指南:用conda精准管理PyTorch与CUDA版本 刚拿到新显卡的兴奋,往往会被环境配置的噩梦浇灭——驱动版本不匹配、CUDA报错、PyTorch无法调用GPU...这些坑我全都踩过。今天我们就用conda这把瑞士军刀,彻底解决这个让无数开发…...

Triton实战手册---Python后端与配置精解(二)

1. Python后端开发实战 Python后端是Triton中最灵活的后端类型,特别适合需要自定义预处理/后处理逻辑的场景。与TensorRT、ONNX等静态模型不同,Python后端允许开发者完全控制推理流程。 先看一个典型的图像处理案例。假设我们需要实现一个图像分类服务&a…...

TimesFM vs 传统时间序列模型:为什么谷歌基础模型正在重塑预测范式

TimesFM vs 传统时间序列模型:为什么谷歌基础模型正在重塑预测范式 【免费下载链接】timesfm TimesFM (Time Series Foundation Model) is a pretrained time-series foundation model developed by Google Research for time-series forecasting. 项目地址: http…...

金融APP如何过等保?一份满足监管与业务安全的加固方案实战教程

对于金融APP而言,安全不仅仅是技术问题,更是生存底线和监管红线。从《个人信息保护法》到等保2.0,每一道监管要求都像悬在头上的剑。在找APK加固方案服务商时,技术负责人最怕的就是:花了大价钱做了加固,结果…...

iOS 15-16设备激活锁绕过:applera1n工具的完整技术解析与实践指南

iOS 15-16设备激活锁绕过:applera1n工具的完整技术解析与实践指南 【免费下载链接】applera1n icloud bypass for ios 15-16 项目地址: https://gitcode.com/gh_mirrors/ap/applera1n 在iOS设备安全研究领域,applera1n作为一款专门针对iOS 15-16.…...

持续交付流水线:从代码提交到生产发布的自动化

持续交付流水线:从代码提交到生产发布的自动化 在当今快节奏的软件开发环境中,企业需要快速、高效地将新功能交付给用户,同时确保质量和稳定性。持续交付流水线(Continuous Delivery Pipeline)正是实现这一目标的核心…...

3分钟掌握卡牌批量生成器:从零到百张的专业设计指南

3分钟掌握卡牌批量生成器:从零到百张的专业设计指南 【免费下载链接】CardEditor 一款专为桌游设计师开发的批处理数值填入卡牌生成器/A card batch generator specially developed for board game designers 项目地址: https://gitcode.com/gh_mirrors/ca/CardEd…...

怎样3分钟找回遗忘的QQ账号:手机号查询工具实战手册

怎样3分钟找回遗忘的QQ账号:手机号查询工具实战手册 【免费下载链接】phone2qq 项目地址: https://gitcode.com/gh_mirrors/ph/phone2qq 你是否曾经因为忘记QQ号而无法登录重要账号?手机号查询QQ号工具为你提供了一种高效、便捷的解决方案。这个…...

告别手动搬运:飞书文档批量导出工具的降维打击

告别手动搬运:飞书文档批量导出工具的降维打击 【免费下载链接】feishu-doc-export 飞书文档导出服务 项目地址: https://gitcode.com/gh_mirrors/fe/feishu-doc-export 还记得那些深夜加班,一个个手动复制粘贴飞书文档的日子吗?当团队…...

跨端通信实战:解锁uniapp中webview与H5/APP的高效数据交互

1. 为什么需要跨端通信? 在混合应用开发中,我们经常会遇到这样的场景:用户在内嵌的H5页面完成登录后,需要将登录状态同步到原生APP中。这时候就需要H5页面和原生APP之间进行数据交互。我遇到过不少开发者在这个环节卡壳&#xff0…...

SAP最快掌握 SAP 组织 核算要素【核心方法论】

口诀记忆(一秒分层)1 大集团 → 2 套核算 → 5 大层级 → 单向归属 → 自动集成流转对外FI 法定:做账、报税、出财报对内CO 管理:算成本、算利润、绩效考核物流业务层:管库存、生产、物料计价预算FM 基金层&#xff1a…...

如何高效使用XUnity.AutoTranslator:终极Unity游戏翻译指南

如何高效使用XUnity.AutoTranslator:终极Unity游戏翻译指南 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 还在为日文或韩文Unity游戏而苦恼吗?XUnity.AutoTranslator是一款专为U…...

CheatEngine找基址实战:从‘更改数值’到理解‘偏移’的完整思路

CheatEngine找基址实战:从数值追踪到指针解析的逆向思维 当你在游戏里发现金币数值从100变成120时,CheatEngine的扫描结果可能会显示十几个内存地址。这时候新手常犯的错误是随便选一个地址修改——结果重启游戏就失效。真正稳定的修改需要找到基址偏移…...

基于 SelectDB 实现 Hive 数据湖统一分析:洋钱罐全球一体化探索分析平台升级实践

在技术领域,我们常常被那些闪耀的、可见的成果所吸引。今天,这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力,让我们得以一窥未来的轮廓。然而,作为在企业一线构建、部署和维护复杂系统的实践者,我们深知…...

CREST终极指南:3分钟掌握分子构象搜索与化学空间探索

CREST终极指南:3分钟掌握分子构象搜索与化学空间探索 【免费下载链接】crest CREST - A program for the automated exploration of low-energy molecular chemical space. 项目地址: https://gitcode.com/gh_mirrors/crest/crest 你是否曾经为寻找分子的最佳…...

如何永久解锁Cursor Pro功能:3个核心技巧让你免费使用AI编程助手

如何永久解锁Cursor Pro功能:3个核心技巧让你免费使用AI编程助手 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reache…...

UE5动画新手上路:用ControlRig+Sequencer 10分钟搞定你的第一个角色点头动画

UE5动画新手指南:10分钟用Control Rig制作角色点头动画 第一次打开Unreal Engine 5的动画系统时,我完全被那些复杂的骨骼和参数吓到了。直到发现Control Rig这个神奇的工具,才意识到原来制作一个简单的角色动画可以如此直观。本文将带你从零开…...

LLM系列:1.python入门:7.字典型对象(dict)

字典型对象(dict) 一. 字典基础 字典(dict)是Python中无序的可变容器。它由一个个键值对(Key-Value)构成。字典也被称作关联数组或者哈希表。 1. 字典的创建 外侧使用大括号 {} 圈定,内部是由冒号 : 连接的键值对,不同键值对之间用…...

给STM32F7加把安全锁:用CubeMX、FreeRTOS和WolfSSL 4.4.0实现HTTPS客户端(附完整工程)

STM32F7安全通信实战:基于CubeMX与WolfSSL的HTTPS客户端深度优化 在物联网设备爆发式增长的今天,数据安全传输已成为嵌入式开发者的必修课。当你的智能家居设备向云端发送温度数据,或是工业传感器传输产线状态时,如何防止敏感信息…...

Intv_AI_MK11运维自动化实践:智能监控告警与故障自愈方案

Intv_AI_MK11运维自动化实践:智能监控告警与故障自愈方案 1. 运维自动化的新纪元 凌晨3点,某电商平台的数据库突然出现性能抖动。传统运维模式下,值班工程师需要手动检查十几项指标、翻阅数百条日志才能定位问题。而采用Intv_AI_MK11的智能…...