长文本切割实现流式调用文本合成语音

长文本切割实现TTS文本合成语音HTTP流式输出

  • 下面是一个文本合成音频的接口文档

快速 TTS 音频构造接口文档

  • 请求地址:
http://52.83.113.111:13679/Say/api/ra
请求方式:
 post xml raw
请求参数:
字段名称字段作用数据格式(示例)
*****xml结构体string(32)<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"> <voice name="zh-CN-YunJianNeural"> <prosody rate="0%" pitch="0%"> 如果喜欢这个项目的话请点个 Star 吧。 </prosody > </voice > </speak >
format请求头标识stringaudio-24khz-48kbitrate-mono-mp3
DeviceNo请求头参数string319ee32b4715017e60b1ab5b6c0ea69f
参数备注:

可选vioce name:

{'中国大陆播音男口音1': 'zh-CN-YunjianNeural','中国大陆播音男口音3': 'zh-CN-YunyangNeural','中国大陆少女口音1': 'zh-CN-XiaoxiaoNeural','中国大陆少女口音2': 'zh-CN-XiaoyiNeural','中国大陆少女口音3': 'zh-CN-YunxiaNeural',}
返回参数:

二进制音频流

根据文档要求构建接口

// 向TTS API请求音频数据
func fetchAudioToTTS(text string, voicer string, format string) ([]byte, error) {url := "http://52.83.116.11:13679/Say/api/ra"payload := "<speak xmlns=\"http://www.w3.org/2001/10/synthesis\" " +"xmlns:mstts=\"http://www.w3.org/2001/mstts\" " +"xmlns:emo=\"http://www.w3.org/2009/10/emotionml\" " +"version=\"1.0\" " +"xml:lang=\"en-US\">" +"<voice name=\"" + voicer + "\">" +"<prosody rate=\"0%\" pitch=\"0%\">" +text +"</prosody>" +"</voice>" +"</speak>"fmt.Println(" ========================================== ")fmt.Println(" payload : =>", payload)// 设置请求头req, err := http.NewRequest("POST", url, strings.NewReader(payload))if err != nil {return nil, err}req.Header.Set("Content-Type", "application/xml")req.Header.Set("format", format)// 发送请求并获取响应client := &http.Client{}resp, err := client.Do(req)if err != nil {fmt.Println("fetchAudioToTTS err => ", err.Error())return nil, err}defer resp.Body.Close()// 读取音频流audioData, err := io.ReadAll(resp.Body)if err != nil {fmt.Println("读取音频流 err => ", err.Error())return nil, err}return audioData, nil
}

长文本切割,多协程合成音频,websocket流式输出音频流代码

package serviceimport ("bytes""fmt""github.com/gin-gonic/gin""github.com/gorilla/websocket""io""log""net/http""strings""sync""time"
)// 定义常用标点符号
var punctuationMarks = []string{".", ",", "。", "!", "?", ";", ":", "、", "·"}// 定义音频格式和TTS相关信息
//var voicer = "zh-CN-YunjianNeural"//var deviceNo = "319ee32b4715017e60b1ab5b6c0ea69f"
var format = "audio-24khz-48kbitrate-mono-mp3"//var audioServers = []string{
//	"http://server1.com/audio1.mp3",
//	"http://server2.com/audio2.mp3",
//	"http://server3.com/audio3.mp3",
//}var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {return true},
}const bufferSize = 1024 * 32 // 32KB// 创建一个带互斥锁的缓冲区结构体,用于存储音频数据
type AudioBuffer struct {buffer bytes.Buffermutex  sync.Mutex
}func (ab *AudioBuffer) Write(p []byte) (n int, err error) {ab.mutex.Lock()defer ab.mutex.Unlock()return ab.buffer.Write(p)
}func (ab *AudioBuffer) Read(p []byte) (n int, err error) {ab.mutex.Lock()defer ab.mutex.Unlock()return ab.buffer.Read(p)
}// 定义标点符号集合(可以根据实际需求扩展)
var PunctuationMarks = []string{",", ",", "。", "!", "!", "?", "?", "\n"}// computeLen 根据 UTF-8 编码,按照标点符号进行切割,确保每段不超过 15 个汉字
func computeLen(content string) (string, string) {Sr := ""      // 用于存储最终返回的已处理文本cp := content // 临时存储输入的文本内容// 获取文本中的汉字数量,按UTF-8编码切割for {// 如果剩余的文本为空或只剩最后一个字符,停止匹配切割if len(cp) == 0 {break}// 查找第一个符合的标点符号sAim := findFirstMatch(cp)// 如果剩余的文本长度较短或者已满足条件,直接添加到 Sr// 判断:如果当前已经处理的文本长度加上剩余文本长度 <= 15(即不超过15个汉字)if len(Sr)+len(cp) <= 15 {Sr += cp // 将剩余的文本直接添加到 Srcp = ""  // 剩余文本清空break    // 处理完成,退出循环}// 查找切割点,确保切割后的文本不超过 15 个汉字// 如果当前已经处理的文本长度小于15,并且找到一个符合条件的标点符号if len(Sr) < 15 && sAim != "" {fmt.Println("sAim => ", sAim)fmt.Println("len(Sr) => ", len(Sr))worldCount := 0 // 汉字计数器index := 0      // 字符串切割的索引位置// 遍历字符串,统计汉字数量(按字符数统计,处理UTF-8编码)for index = range cp {// 如果已处理的汉字数量大于等于15,则停止if worldCount >= 15 {fmt.Println("汉字数量大于等于15 cp => ", len(cp))break}// 增加汉字计数worldCount++}// 将符合条件的文本(从开始到切割点)添加到 SrSr += cp[:index]// 剩余的文本部分,更新 cpcp = cp[index:]// 处理完成,退出循环break}}// 返回切割后的结果:已处理的文本和剩余的文本return Sr, cp
}// computeLen 根据 UTF-8 编码,按照标点符号进行切割,确保每段不超过 30 个汉字
func computeLen22(content string) (string, string) {Sr := ""      // 用于存储最终返回的已处理文本cp := content // 临时存储输入的文本内容// 获取文本中的汉字数量,按UTF-8编码切割for {// 如果剩余的文本为空或只剩最后一个字符,停止匹配切割if len(cp) == 0 {break}// 查找第一个符合的标点符号sAim := findFirstMatch(cp)// 如果剩余的文本长度较短或者已满足条件,直接添加到 Sr// 判断:如果当前已经处理的文本长度加上剩余文本长度 <= 30(即不超过30个汉字)if len(Sr)+len(cp) <= 20 {Sr += cp // 将剩余的文本直接添加到 Srcp = ""  // 剩余文本清空break    // 处理完成,退出循环}// 查找切割点,确保切割后的文本不超过 30 个汉字// 如果当前已经处理的文本长度小于30,并且找到一个符合条件的标点符号if len(Sr) < 20 && sAim != "" {runeCount := 0 // 汉字计数器index := 0     // 字符串切割的索引位置// 遍历字符串,统计汉字数量(按字符数统计,处理UTF-8编码)for index = range cp {// 如果已处理的汉字数量大于等于30,则停止if runeCount >= 20 {break}// 增加汉字计数runeCount++}// 将符合条件的文本(从开始到切割点)添加到 SrSr += cp[:index]// 剩余的文本部分,更新 cpcp = cp[index:]// 处理完成,退出循环break}}// 返回切割后的结果:已处理的文本和剩余的文本return Sr, cp
}// 这个函数的作用是找到字符串中第一个符合标点符号的字符
func findFirstMatch(str string) string {// 遍历标点符号集合,检查当前文本中是否包含标点符号for _, match := range PunctuationMarks {// 如果找到符合的标点符号,则返回该符号if strings.Contains(str, match) {return match}}// 如果没有找到任何符合的标点符号,返回空字符串return ""
}// splitPlayText 函数用于将输入文本分割成当前播放文本和剩余文本
// 参数:input - 输入的字符串
// 返回值:(string, string) - 第一个返回值是本次播放的文本,第二个返回值是剩余文本
func splitPlayText(input string) (string, string) {// 将输入字符串转换为 rune 切片,以正确处理中文字符// 如果输入长度小于等于15个字符,直接返回整个字符串作为播放文本,无剩余文本if len([]rune(input)) <= 15 {return input, ""}// 定义可用的分隔符数组// 包含中文标点(。,!?)和英文标点(.,!?)以及换行符separators := []rune{'。', '.', ',', ',', '!', '!', '?', '?', '\n'}// 将输入字符串转换为 rune 切片,便于按字符处理runes := []rune(input)// 记录最后一个找到的分隔符位置// 初始化为-1表示还未找到分隔符lastSepPos := -1// 遍历字符串中的每个字符for i, r := range runes {// 标记当前字符是否为分隔符isSeparator := false// 检查当前字符是否是分隔符for _, sep := range separators {if r == sep {isSeparator = true// 更新最后一个分隔符的位置lastSepPos = ibreak}}// 处理超过25个字符的情况// 如果当前位置超过25且之前找到过分隔符,从最后一个分隔符处切割if i >= 25 && lastSepPos != -1 {// 返回分隔符之前的文本(包含分隔符)作为播放文本// 分隔符之后的文本作为剩余文本return string(runes[:lastSepPos+1]), string(runes[lastSepPos+1:])}// 处理超过15个字符的情况// 如果当前位置超过15且当前字符是分隔符,在当前位置切割if i >= 15 && isSeparator {// 返回当前分隔符之前的文本(包含分隔符)作为播放文本// 分隔符之后的文本作为剩余文本return string(runes[:i+1]), string(runes[i+1:])}}// 如果遍历完整个字符串都没有找到合适的切割点// 返回整个字符串作为播放文本,无剩余文本return string(runes), ""
}// 创建SSML内容
//func createSSML(text, voicer string) string {
//	return fmt.Sprintf("<speak><voice name=\"%s\">%s</voice></speak>", voicer, text)
//}// 向TTS API请求音频数据
func fetchAudioToTTS(text string, voicer string, format string) ([]byte, error) {url := "http://52.83.116.11:13679/Say/api/ra"payload := "<speak xmlns=\"http://www.w3.org/2001/10/synthesis\" " +"xmlns:mstts=\"http://www.w3.org/2001/mstts\" " +"xmlns:emo=\"http://www.w3.org/2009/10/emotionml\" " +"version=\"1.0\" " +"xml:lang=\"en-US\">" +"<voice name=\"" + voicer + "\">" +"<prosody rate=\"0%\" pitch=\"0%\">" +text +"</prosody>" +"</voice>" +"</speak>"fmt.Println(" ========================================== ")fmt.Println(" payload : =>", payload)// 设置请求头req, err := http.NewRequest("POST", url, strings.NewReader(payload))if err != nil {return nil, err}req.Header.Set("Content-Type", "application/xml")req.Header.Set("format", format)// 发送请求并获取响应client := &http.Client{}resp, err := client.Do(req)if err != nil {fmt.Println("fetchAudioToTTS err => ", err.Error())return nil, err}defer resp.Body.Close()// 读取音频流audioData, err := io.ReadAll(resp.Body)if err != nil {fmt.Println("读取音频流 err => ", err.Error())return nil, err}return audioData, nil
}// 处理文本分段,逐段请求TTS并通过channel返回音频数据
func processTextInChunks(content string, voicer string, ch chan<- []byte) {for len(content) > 0 {// 切割文本segment, remaining := splitPlayText(content)content = remaining// 如果 segment 为空,直接跳过if len(strings.TrimSpace(segment)) == 0 && len(strings.ReplaceAll(segment, "\n", "")) == 0 {//continuebreak}// 创建SSML//ssml := createSSML(segment, voicer)fmt.Println("segment : => ", segment, "content : ==>", content)// 请求TTS接口获取音频audioData, err := fetchAudioToTTS(segment, voicer, format)if err != nil {fmt.Println("Error generating audio:", err)continue}//fmt.Println("audioData : =>", audioData)// 将音频数据发送到channelch <- audioDataif len(content) == 0 {// 音频数据传输结束break}// 模拟逐段播放,每段等待一段时间time.Sleep(3 * time.Second)}// 关闭channelclose(ch)
}// WebSocket连接处理函数,流式传输音频数据
func HandleAudioStream(ws *websocket.Conn, msgContent string, voicer string) {//ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)//if err != nil {//	log.Printf("WebSocket upgrade error: %v", err)voicer//	return//}//defer ws.Close()// 创建一个带互斥锁的bufferaudioBuffer := &AudioBuffer{}// 创建用于通知新数据到达的channelnewDataChan := make(chan struct{}, 1)// 创建用于通知所有音频获取完成的channeldoneChan := make(chan struct{})// 创建一个channel,用于接收音频数据audioCh := make(chan []byte)// 测试文本//content := "这是一个测试文本,包含多个标点符号,看看如何处理。流式计算引擎Flink,是大数据领域非常常用的一个计算框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。"// 启动处理文本切割和请求TTS的goroutinego processTextInChunks(msgContent, voicer, audioCh)// 启动获取音频的goroutinego FetchAudioSequentially(audioCh, audioBuffer, newDataChan, doneChan)// 启动发送音频的goroutinego SendStreamAudio(ws, audioBuffer, newDataChan, doneChan)// 等待WebSocket连接关闭for {if _, _, err := ws.ReadMessage(); err != nil {log.Printf("WebSocket read error: %v", err)return}}
}// fetchAudioSequentially 负责按顺序获取音频数据
func FetchAudioSequentially(audioCh <-chan []byte, audioBuffer *AudioBuffer, newDataChan chan struct{}, doneChan chan struct{}) {defer close(doneChan)// 从audioCh获取音频数据for audioData := range audioCh {// 将获取到的音频数据写入音频缓冲区audioBuffer.Write(audioData)//fmt.Println("audioData : => ", audioData)// 通知有新数据可用select {case newDataChan <- struct{}{}:default:}// 模拟处理延时(实际场景可删除)time.Sleep(time.Second * 2)}
}// SendStreamAudio 负责将获取到的数据流式发送到客户端
func SendStreamAudio(ws *websocket.Conn, audioBuffer *AudioBuffer, newDataChan chan struct{}, doneChan chan struct{}) {buffer := make([]byte, bufferSize)//var offset int64 = 0for {select {case <-newDataChan:// 有新数据可用,尝试读取并发送for {n, err := audioBuffer.Read(buffer)if err == io.EOF {// 当前buffer读完,等待新数据//fmt.Println("err => ", err.Error())break}if err != nil {log.Printf("Error reading buffer: %v", err)return}// 发送数据//fmt.Println(" ws.WriteMessage 发送数据: ==> ", buffer[:n])err = ws.WriteMessage(websocket.BinaryMessage, buffer[:n])if err != nil {log.Printf("Error writing to websocket: %v", err)return}//offset += int64(n)}case <-doneChan:// 所有音频获取完成,确保发送完最后的数据for {n, err := audioBuffer.Read(buffer)if err == io.EOF {return}if err != nil {log.Printf("Error reading final buffer: %v", err)return}err = ws.WriteMessage(websocket.BinaryMessage, buffer[:n])if err != nil {log.Printf("Error writing final data to websocket: %v", err)return}}}}
}

HTTP_TTS流式输出音频流代码示例

package serviceimport ("PsycheEpic/src/models""fmt""github.com/gin-gonic/gin""log""net/http""strings""time"
)// 处理文本分段,逐段请求TTS并通过channel返回音频数据
func http_processTextInChunks(content string, voicer string, ch chan<- []byte) {for len(content) > 0 {// 切割文本segment, remaining := splitPlayText(content)content = remaining// 如果 segment 为空,直接跳过if len(strings.TrimSpace(segment)) == 0 && len(strings.ReplaceAll(segment, "\n", "")) == 0 {//continuebreak}// 创建SSML//ssml := createSSML(segment, voicer)fmt.Println("segment : => ", segment, "content : ==>", content)// 请求TTS接口获取音频audioData, err := fetchAudioToTTS(segment, voicer, format)if err != nil {fmt.Println("Error generating audio:", err)continue}//fmt.Println("audioData : =>", audioData)// 将音频数据发送到channelch <- audioDataif len(content) == 0 {// 音频数据传输结束ch <- nil // 使用nil来表示音频数据已经完成break}// 模拟逐段播放,每段等待一段时间time.Sleep(3 * time.Second)}// 关闭channelclose(ch)
}func HandleHTTPAudioStream(c *gin.Context) {// 设置响应头c.Writer.Header().Set("Content-Type", "audio/mp3")c.Writer.Header().Set("Transfer-Encoding", "chunked")// 获取 form-data 参数text := c.PostForm("text")voicer := c.PostForm("voicer")log.Printf("接收到TTS请求 - 文本: %s, 语音类型: %s", text, voicer)// 参数校验if text == "" || voicer == "" {c.JSON(http.StatusBadRequest, gin.H{"code": 0, "message": "参数 text 和 voicer 不能为空"})return}deviceNo := c.PostForm("deviceNo")if deviceNo == "" {c.JSON(http.StatusOK, gin.H{"code": 0, "message": "deviceNo参数不能为空"})return}DollInfo, err := models.GetDollUserRelationBySerialNumber(deviceNo)if err != nil {c.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询玩具设备信息出错"})return}if DollInfo == nil {c.JSON(http.StatusOK, gin.H{"code": 0, "message": "未查询到设备绑定的用户信息"})return}// 检查设备是否当前已经连接if _, exists := DollChatCache[deviceNo]; !exists {c.JSON(http.StatusOK, gin.H{"code": 0, "message": "设备未连接或已断开"})return}// 创建一个无缓冲的通道来协调goroutinedone := make(chan bool)// 初始化缓存区,开辟空间//buffer := make([]byte, bufferSize)// 使用CloseNotify来检测客户端连接是否关闭clientGone := c.Writer.CloseNotify()// 创建带互斥锁的音频缓冲区//audioBuffer := &AudioBuffer{}// 创建用于接收音频数据的 channelaudioCh := make(chan []byte)// **启动 Goroutine 处理文本分割和请求 TTS**// 启动后台处理go func() {log.Println("开始处理文本并获取音频数据")http_processTextInChunks(text, voicer, audioCh)}()// 发送数据go func() {for {select {// 检查客户端是否已断开连接case <-clientGone:fmt.Println("客户端已断开连接")done <- truereturndefault:// 继续处理// 从audioCh管道获取数据case audioData := <-audioCh://fmt.Println("有数据... ", string(audioData))// 从audioCh管道获取数据if audioData == nil {// 如果接收到 nil,表示音频数据已发送完毕fmt.Println("数据已发送完毕")done <- truereturn}// 直接写入音频数据到 HTTP 响应_, err := c.Writer.Write(audioData)if err != nil {log.Printf("写入 HTTP 音频流出错: %v", err)return}// 确保数据实时发送if flusher, ok := c.Writer.(http.Flusher); ok {flusher.Flush()}}}done <- true}()// 等待所有数据处理完成或客户端断开连接<-done}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/70829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始构建基于DeepSeek的智能客服系统

在当今的数字化时代,智能客服系统已经成为企业与客户沟通的重要桥梁。它不仅能够提升客户体验,还能大幅降低企业的运营成本。本文将带领你从零开始,使用PHP和DeepSeek技术构建一个功能强大的智能客服系统。我们将通过具体的案例和代码示例,深入探讨如何实现这一目标。 1. …

计算机网络:应用层 —— 电子邮件

文章目录 电子邮件的起源与发展电子邮件的组成电子邮件协议邮件发送和接收过程邮件发送协议SMTP协议多用途因特网邮件扩展MIME 电子邮件的信息格式 邮件读取协议邮局协议POP因特网邮件访问协议IMAP 基于万维网的电子邮件 电子邮件&#xff08;E-mail&#xff09;是因特网上最早…

CSS笔记一

一、语法 选择器{属性&#xff1a;属性值&#xff1b;属性&#xff1a;属性值} 二、书写分类 行内样式&#xff1a;直接通过style属性写在标签上 <p style"font-size80px">123456</p> 页内样式&#xff1a;在html页面创建style标签 外链样式&…

【PyTorch][chapter-33][transformer-5] MHA MQA GQA, KV-Cache

主要翻译外网&#xff1a; 解剖Deep Seek 系列&#xff0c;详细见参考部分。 目录&#xff1a; Multi-Head Attention &#xff08;MHA) KV-Cache KV-Cache 公式 Multi-Query Attention&#xff08;MQA) Grouped-Query Attention(GQA) Multi-Head Latent Attention …

Web刷题之PolarDN(中等)

1.到底给不给flag呢 代码审计 一道典型的php变量覆盖漏洞 相关知识 什么是变量覆盖漏洞 自定义的参数值替换原有变量值的情况称为变量覆盖漏洞 经常导致变量覆盖漏洞场景有&#xff1a;$$使用不当&#xff0c;extract()函数使用不当&#xff0c;parse_str()函数使用不当&…

如何看到 git 上打 tag 的时间

在 Git 中可以通过以下方法查看标签&#xff08;tag&#xff09;的创建时间&#xff1a; 使用 git show 命令&#xff1a; 运行以下命令可以查看某个特定标签的详细信息&#xff0c;包括创建时间&#xff1a; git show 输出中会包含 Tagger 的信息和 Date 字段&#xff0c;显示…

Nginx 源码编译安装

创建虚拟机&#xff0c;内存 4G 处理器 2 核&#xff0c;NAT 网络。 准备 Nginx 源码包&#xff0c;1.24 版本&#xff0c;用于实验。 一、下载 Nginx 源码包 Nginx 官网&#xff1a;www.nginx.org download 下载相关的版本&#xff0c;如下图&#xff1a; wget 下载 Nginx…

DPVS-5: 后端服务监控原理与测试

后端监控原理 被动监测 DPVS自带了被动监控&#xff0c;通过监控后端服务对外部请求的响应情况&#xff0c;判断服务器是否可用。 DPVS的被动监测&#xff0c;并不能获取后端服务器的详细情况&#xff0c;仅仅通过丢包/拒绝情况来发觉后端服务是否可用。 TCP session state…

【计算机网络协议01】应用层协议HTTP

应用层协议HTTP 引言 应用层协议是程序员自己制定的&#xff0c;但是良好的协议是保证网络通信的基础&#xff0c;前代的计算工程师已经帮助我们制定了一些很好用的应用层协议&#xff0c;http(hybertext transfer protocol)(超文本传输协议)就是其中之一。 http协议是客户端…

uniapp 系统学习,从入门到实战(四)—— 页面与路由管理

​ 全篇大概 2700 字(含代码)&#xff0c;建议阅读时间 20min 在跨平台开发中&#xff0c;高效的路由管理直接影响用户体验和开发效率。本文将深入探讨uniapp的页面创建、路由跳转、参数传递和生命周期管理&#xff0c;助您构建流畅的多端应用。 &#x1f4da; 目录 页面创建…

BOOST电路设计

目录 1电路模型 2器件选型 2.1设计需求 2.2参数计算 2.2.1电感L计算 2.2.2电容计算 2.2.3电阻计算 3仿真测试 4参数测试 4.1负载调整率 4.2电容测试 4.3电感测试 5实际应用 1电路模型 Boost升压电路,可以工作在电流断续工作模式(DCM)和电流连续工作模式(CCM)。CCM工…

springboot实现文件上传到华为云的obs

一、前言 有时在项目中需要使用一些存储系统来存储文件&#xff0c;那么当项目要接入obs作为存储系统时&#xff0c;就会利用obs来进行文件的上传下载&#xff0c;具体实现如下。 二、如何通过obs实现文件的上传下载&#xff1f; 1.添加相关的obs的maven依赖。 <dependency…

miqiu的分布式锁(二):实战——用JMeter验证JVM锁能否解决MySQL超卖问题

miqiu的分布式锁二&#xff1a;实战——用JMeter验证JVM锁能否解决MySQL超卖问题 实验背景 在秒杀场景中&#xff0c;超卖问题是典型的并发编程挑战。本文通过JMeter压测工具&#xff0c;验证基于JVM的两种锁机制&#xff08;synchronized/ReentrantLock&#xff09;对MySQL库…

《论企业集成平台的理解与应用》审题技巧 - 系统架构设计师

企业集成平台的理解与应用——论文写作框架 一、考点概述 本论题“企业集成平台的理解与应用”主要考察的是计算机软件测试工程师对于企业集成平台&#xff08;EIP&#xff09;的深入理解以及在实际项目中的应用能力。论题涵盖了以下几个核心内容&#xff1a; 首先&#xff…

初阶数据结构(C语言实现)——2算法的时间复杂度和空间复杂度

目录 本节目标1. 算法效率1.1 如何衡量一个算法的好坏1.2 算法的复杂度 2.时间复杂度2.1 时间复杂度的概念2.1.1 入门习题2.1.2 进阶习题 2.2 常见时间复杂度 3. 空间复杂度3.1 常见空间复杂度 本节目标 算法效率时间复杂度空间复杂度常见时间复杂度以及复杂度oj练习 1. 算法…

排序算法(3):

这是我们的最后一篇排序算法了&#xff0c;也是我们的初阶数据结构的最后一篇了。 我们来看&#xff0c;我们之前已经讲完了插入排序&#xff0c;选择排序&#xff0c;交换排序&#xff0c;我们还剩下最后一个归并排序&#xff0c;我们今天就讲解归并排序&#xff0c;另外我们还…

AI智能体与大语言模型:重塑SaaS系统的未来航向

在数字化转型的浪潮中&#xff0c;软件即服务&#xff08;SaaS&#xff09;系统一直是企业提升效率、优化业务流程的重要工具。随着AI智能体和大语言模型&#xff08;LLMs&#xff09;的迅速发展&#xff0c;SaaS系统正迎来前所未有的变革契机。本文将从AI智能体和大语言模型对…

AOP进阶-03.切入点表达式-execution

一.切入点表达式-execution 访问修饰符(public/private等)&#xff0c;包名.类名.&#xff0c;throws 异常都可以省略&#xff0c;但是建议包名.类名.不要省略&#xff0c;否则的话匹配范围太大影响程序执行效率。 *主要用来匹配单个参数&#xff0c;通配任意返回值、包名、类…

神经网络发展简史:从感知机到通用智能的进化之路

引言 神经网络作为人工智能的核心技术&#xff0c;其发展历程堪称一场人类对生物大脑的致敬与超越。本文将用"模型进化"的视角&#xff0c;梳理神经网络发展的五大关键阶段&#xff0c;结合具象化比喻和经典案例&#xff0c;为读者呈现一幅清晰的AI算法发展图谱。 一…

NLP09-加强1-对比SVM

支持向量机&#xff08;SVM&#xff09; &#xff08;一&#xff09;导入 SVM 相关库 &#xff08;二&#xff09; 修改模型初始化 &#xff08;三&#xff09; 比较 朴素贝叶斯分类器 SVM分类器 支持向量机&#xff08;SVM&#xff09; 代码修改基于NLP09-朴素贝叶斯问句…