作者:微信小助手
<h2 data-id="heading-0">一、前言</h2> <p>今天在开发H5的时候,遇到了一个bug,就是在ios环境,在某些情况下执行<code>window.open</code>不生效,所以正好趁此机会研究了一下<code>window.open</code>。</p> <h2 data-id="heading-1">二、window.open介绍</h2> <p>从<code>open</code>方法的调用方式可以看出,<code>open</code>方法是定义在<code>Window</code>接口上,正因为如此它有三个参数:</p> <pre> window.open</span>(url, target, windowFeatures) </pre> <ol> <li><strong>url</strong>:「可选参数」,表示你要加载的资源URL或路径,如果不传,则打开一个<code>url</code>地址为<code>about:blank</code>的空白页。</li> </ol> <p><img src="https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/407176f422144262821ebcc0dfda45fb~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg56iL5bqP5ZGY5bCP5a-S:q75.awebp?rk3s=f64ab15b&x-expires=1737810058&x-signature=5FeWeJbgf9hC0r3goIz88LAnyOc%3D" alt="" loading="lazy" class="medium-zoom-image"></p> <p>顺便介绍一下,<code>about:blank</code>是<code>chrome浏览器</code>的一个命令,该指令会打开浏览器的一个内建空白页面,而不是从网络上下载,类似的命令还有<code>about:downloads</code>、<code>about:extensions</code>、<code>about:history</code>等等,具体<code>chrom浏览器</code>提供了哪些命令,你可以通过在浏览器地址栏输入<code>about:about</code>查看。</p> <ol start="2"> <li><strong>target</strong>:「可选参数」,它可以给以下两种值。 <ul> <li>第一种是<strong>target关键字</strong> <ul> <li><code>_self</code>:当前标签页加载;</li> <li><code>_blank(默认值)</code>:新标签页打开;</li> <li><code>_parent</code>:作为当前浏览环境的父级浏览上下文打开,没有父级浏览上下文,效果与<code>_self</code>相同;</li> <li><code>_top</code>:作为最顶级的浏览上下文打开,没有顶级浏览上下文,效果与<code>_self</code>相同。</li> </ul> </li> <li>第二种是一个<strong>字符串</strong>:表示加载资源的浏览上下文的<strong>名称</strong>,也就是<strong>标签页的名称</strong>,如果这个名称在现有的标签页中不存在,则会开启一个新的标签页,如果存在,会跳转到这个标签页。</li> </ul> </li> </ol> <p>这里顺便提一下,我在平时开发中曾经写出这样的代码:</p> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-keyword">const</span> <span class="hljs-title function_">handleClick</span> = (<span class="hljs-params"></span>) => {</span> <span class="code-block-extension-codeLine" data-line-num="2"> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">open</span>(url, <span class="hljs-string">'blank'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="3">}</span> </code></pre> <p>这个方法是绑定在一个点击按钮上面的,结果我的同事在点击多次这个按钮时,第一次会打开一个新窗口,而后续的点击都跳转到第一次点击打开的那个窗口,于是我去排查了一下,发现自己把<code>_blank</code>写成了<code>blank</code>,于是浏览器把它解析成了<strong>标签页的名字</strong>,而不是<strong>target关键词</strong>,我那时候感觉挺有意思,第一次详细去了解了这个<code>target</code>。</p> <ol start="3"> <li><strong>windowFeatures</strong>:「可选参数」,它是一个字符串,用来描述窗口的特性,其格式是<code>"key1=value1, key2=value2"</code>,即将<code>key</code>和<code>value</code>以<code>=</code>号连接拼接成字符串,多个<code>key value</code>以<strong>逗号</strong>隔开,比如我们要打开一个宽为500,高为600的窗口可以这么写:</li> </ol> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-variable language_">window</span>.<span class="hljs-title function_">open</span>(url, <span class="hljs-string">'new-window'</span>, <span class="hljs-string">'width=500,height=600'</span>);</span> </code></pre> <p>它可以描述如下窗口特性:</p> <ol> <li><code>width</code>:内容区域宽度,最小值为100,</li> <li><code>height</code>:内容区域高度,最小值100,</li> <li><code>left</code>:距离<strong>用户操作系统</strong>工作区左侧的距离,</li> <li><code>top</code>:距离<strong>用户操作系统</strong>工作区顶部的距离。</li> <li>...</li> </ol> <p>这四个应该是最常用的,其它的不太常用我这里就不列举了。</p> <p>至于这个<code>windowFeatures</code>的作用呢,平常开发中用的不太多,我能想到的场景就是比如你要通过url打开一个预览页面,让用户看里面的一些内容,就可以用这个试试。</p> <h2 data-id="heading-2">三、bug复现</h2> <p>先写一个能复现问题的demo:</p> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">jump</span>(<span class="hljs-params"></span>) {</span> <span class="code-block-extension-codeLine" data-line-num="2"> <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/xxx'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="3"> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">open</span>(<span class="hljs-string">'https://www.xxx.cn'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="4">}</span> </code></pre> <p>正常情况下执行<code>window.open</code>是能正常新标签页打开传入的url的,但是一旦前面用<code>await</code>做了异步操作后,再执行<code>window.open</code>,就不生效了。</p> <p>然后我又尝试了<code>a标签</code>,发现效果也是一样的,无法打开新标签页。</p> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">jump</span>(<span class="hljs-params"></span>) {</span> <span class="code-block-extension-codeLine" data-line-num="2"> <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/xxx'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="3"> <span class="hljs-keyword">let</span> a = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">'a'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="4"> a.<span class="hljs-title function_">setAttribute</span>(<span class="hljs-string">'target'</span>, <span class="hljs-string">'blank'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="5"> a.<span class="hljs-property">href</span> = <span class="hljs-string">'https://www.xxx.cn'</span>;</span> <span class="code-block-extension-codeLine" data-line-num="6"> a.<span class="hljs-title function_">click</span>()</span> <span class="code-block-extension-codeLine" data-line-num="7"> a = <span class="hljs-literal">null</span>;</span> <span class="code-block-extension-codeLine" data-line-num="8">}</span> </code></pre> <h2 data-id="heading-3">四、原因分析</h2> <ol> <li><strong>安全机制拦截</strong>:IOS的Safari浏览器为了防止恶意网站通过<code>window.open/a标签</code>打开其他网站,于是对它们的调用有所限制,如果不是由用户直接交互触发的,而是由程序自动触发的,Safari会拦截这个操作。</li> <li><strong>异步操作</strong>:在AJAX回调中执行<code>window.open/a标签跳转</code>,被浏览器认为是非用户交互行为,所以被拦截。</li> </ol> <h2 data-id="heading-4">五、解决方案</h2> <h3 data-id="heading-5">方案1:改用location.href</h3> <p>既然<code>window.open</code>和<code>a标签跳转</code>不行,那就换成<code>location.href</code>就好了,因为safari不会拦截<code>location.href</code>。</p> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">jump</span>(<span class="hljs-params"></span>) {</span> <span class="code-block-extension-codeLine" data-line-num="2"> <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/xxx'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="3"> location.<span class="hljs-property">href</span> = <span class="hljs-string">'https://www.xxx.cn'</span>;</span> <span class="code-block-extension-codeLine" data-line-num="4">}</span> </code></pre> <p>当然并不是所有场景下都适合用<code>location.href</code>,因为<code>location.href</code>会刷新页面,所以需要根据具体场景来选择。</p> <h3 data-id="heading-6">方案2:先打开一个空标签页</h3> <p>通过<code>window.open("", "_blank")</code>先打开一个空标签页,然后等待请求完成后,修改这个新标签页的url。</p> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">jump</span>(<span class="hljs-params"></span>) {</span> <span class="code-block-extension-codeLine" data-line-num="2"> <span class="hljs-keyword">const</span> newWin = <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">open</span>(<span class="hljs-string">""</span>, <span class="hljs-string">"_blank"</span>); <span class="hljs-comment">// 提前打开一个窗口</span></span> <span class="code-block-extension-codeLine" data-line-num="3"> <span class="hljs-keyword">const</span> { jumpUrl } = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/xxx'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="4"> <span class="hljs-keyword">if</span> (jumpUrl) {</span> <span class="code-block-extension-codeLine" data-line-num="5"> newWin.<span class="hljs-property">location</span> = jumpUrl;</span> <span class="code-block-extension-codeLine" data-line-num="6"> } <span class="hljs-keyword">else</span> {</span> <span class="code-block-extension-codeLine" data-line-num="7"> newWin.<span class="hljs-title function_">close</span>();</span> <span class="code-block-extension-codeLine" data-line-num="8"> <span class="hljs-comment">// ... </span></span> <span class="code-block-extension-codeLine" data-line-num="9"> }</span> <span class="code-block-extension-codeLine" data-line-num="10">}</span> </code></pre> <p>但这里有个体验问题,我这里根据有没有<code>jumpUrl</code>进行跳转,如果没有<code>jumpUrl</code>,我需要调用<code>close</code>方法关闭刚才提前打开的那个窗口,而这样用户就会体验到的流程就是,先出来一个新窗口,随后被秒关闭,这样用户体验很差。</p> <h3 data-id="heading-7">方案3:setTimeout/requestAnimationFrame</h3> <p>在我的业务场景中,是必须要用window.open的,所以只能另寻他法,最终找到了一个解决方案,就是在<code>window.open</code>之前加一个<code>setTimeout</code>,在回调中执行<code>window.open</code>,这样就能避免被safari拦截。</p> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">jump</span>(<span class="hljs-params"></span>) {</span> <span class="code-block-extension-codeLine" data-line-num="2"> <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/xxx'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="3"> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {</span> <span class="code-block-extension-codeLine" data-line-num="4"> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">open</span>(<span class="hljs-string">'https://www.xxx.cn'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="5"> }, <span class="hljs-number">0</span>)</span> <span class="code-block-extension-codeLine" data-line-num="6">}</span> </code></pre> <p>后面测试了一下,发现<code>requestAnimationFrame</code>也可以。</p> <pre><code class="hljs language-js code-block-extension-codeShowNum" lang="js"><span class="code-block-extension-codeLine" data-line-num="1"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">jump</span>(<span class="hljs-params"></span>) {</span> <span class="code-block-extension-codeLine" data-line-num="2"> <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/xxx'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="3"> <span class="hljs-title function_">requestAnimationFrame</span>(<span class="hljs-function">() =></span> {</span> <span class="code-block-extension-codeLine" data-line-num="4"> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">open</span>(<span class="hljs-string">'https://www.xxx.cn'</span>);</span> <span class="code-block-extension-codeLine" data-line-num="5"> })</span> <span class="code-block-extension-codeLine" data-line-num="6">}</span> </code></pre> <h2 data-id="heading-8">六、最终我采取的方案</h2> <p>我最终是通过<strong>方案3</strong>的<code>setTimeout</code>解决了问题,如果<code>setTimeout</code>不生效,可以尝试加点延时看看,比如100毫秒,我这边实测的ios机型都能生效,所以就没加延时。</p> <h2 data-id="heading-9">七、小结</h2> <p>本文主要介绍了<code>window.open</code>的用法,以及我自己在平时开发中踩的坑,希望对大家平常开发有帮助!</p> <p>如果针对上面的问题,更好的解决方案,欢迎在下方留言评论!一起学习。</p></div>
作者:微信小助手
<p> 在软件使用上,用户体验是一个重要的考虑因素,所以为了提高用户的体验,很多的应用系统中都会有自动登录功能,如下所示的自动登录的图:<span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;"></span></p> <p style="text-align: left;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001833" data-ratio="0.5897435897435898" data-s="300,640" src="/upload/90cd2965c51fd55c4a91bfcbc5c779a4.png" data-type="png" data-w="429" style=""></p> <p style="text-align: left;"> 自动登录其实是在用户第一次成功登录后,应用系统将用户的登录状态持久化,等用户下次再访问时实现自动登录,这样就不需用户再次输入用户名和密码。那么自动登录如何实现呢,下面介绍通过Cookie+Token的方式实现自动登录的功能。</p> <p style="text-align: left;"><strong>1、<span style="letter-spacing: 0.578px;text-align: left;">Cookie+T</span><span style="letter-spacing: 0.578px;text-align: left;">oken实现方案</span></strong><span style="letter-spacing: 0.578px;text-align: left;"></span></p> <p> 用户勾选“自动登录”选项后进行登录时,服务端验证用户信息通过之后生成一个Token,然后服务端将Token写到Cookie上并存留一段时间,用户下次重新打开浏览器,浏览器会<span style="letter-spacing: 0.578px;">自动登录,如下<span style="letter-spacing: 0.578px;">自动登录的流程图:</span></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001840" data-ratio="0.5714285714285714" data-s="300,640" src="/upload/daad82af7529000086bfb54469e60554.png" data-type="png" data-w="700" style=""></p> <article> <p>(1)当用户第一次登录系统的时候,用户输入用户名和密码进行登录,验证账号与密码通过之后,服务端<span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">生成Token,如下图所示:</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001838" data-ratio="0.4452449567723343" data-s="300,640" src="/upload/52083366df7fdd72a191423b8715fc46.png" data-type="png" data-w="694" style=""></p> <p><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;"></span></p> <p> 服务端将生成的Token缓存一份到Redis上,然后将Token和用户信息更新到数据库中;最后服务端<span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">将Token存入用户的Cookie中,以便后续请求使用。</span></p> <p><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">(2)</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">用户下次再访问服务的时候,请求中携带有Token的Cookie访问服务端,服务端要</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">从请求的Cookie中获取Token的信息,流程图如下所示:</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001839" data-ratio="0.6369747899159663" data-s="300,640" src="/upload/b58c138dafaba83661584ba4e8471ec9.png" data-type="png" data-w="595" style=""></p> <p><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;"></span></p> <p> Redis中与数据库中都验证<span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">Token通过之后,</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">系统直接将用户设置成登录状态。</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">至此就完成了</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">用户的自动登录</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">。</span></p> </article> <p style="text-align: left;"><strong>2、方案实现的核心代码</strong><br></p> <p style="text-align: left;">(1)用户的登录的核心代码<br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"> <span class="code-snippet__meta">@PostMapping(<span class="code-snippet__meta-string">"/login"</span>)</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">public</span> String login(<span class="code-snippet__meta">@RequestBody</span> User loginUser, HttpServletResponse response) {</span></code><code><span class="code-snippet_outer"> User user = userService.queryUserByName(loginUser.getUsername());</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 用户验证通过</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (user != <span class="code-snippet__literal">null</span> && user.getPassword().equals(loginUser.getPassword())) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//生成token 并保存用户的token</span></span></code><code><span class="code-snippet_outer"> String token = JWTUtils.generateToken(user);</span></code><code><span class="code-snippet_outer"> user.setToken(token);</span></code><code><span class="code-snippet_outer"> userService.save(user);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//保存到redis中</span></span></code><code><span class="code-snippet_outer"> stringRedisTemplate.opsForValue().<span class="code-snippet__keyword">set</span>(<span class="code-snippet__string">"login_token_"</span> + token, user.getId().toString(), <span class="code-snippet__number">7</span> * <span class="code-snippet__number">24</span> * <span class="code-snippet__number">60</span> * <span class="code-snippet__number">60</span>, TimeUnit.SECONDS);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//设置cookie</span></span></code><code><span class="code-snippet_outer"> Cookie cookie = new Cookie(<span class="code-snippet__string">"token"</span>, token);</span></code><code><span class="code-snippet_outer"> cookie.setPath(<span class="code-snippet__string">"/"</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//Cookie有效的时间存储为一周</span></span></code><code><span class="code-snippet_outer"> cookie.setMaxAge(<span class="code-snippet__number">7</span> * <span class="code-snippet__number">24</span> * <span class="code-snippet__number">60</span> * <span class="code-snippet__number">60</span>);</span></code><code><span class="code-snippet_outer"> response.addCookie(cookie);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__string">"登录成功"</span>;</span></code><code><span class="code-snippet_outer"> } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__string">"用户名或密码错误"</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code></pre> </section> <p style="text-align: left;">(2)用户自动登录的核心代码实现</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__meta">@GetMapping(<span class="code-snippet__meta-string">"/autoLogin"</span>)</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">public</span> String autoLogin(HttpServletRequest request) {</span></code><code><span class="code-snippet_outer"> Cookie[] cookies = request.getCookies();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//无cookie</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (Objects.isNull(cookies)) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__string">"自动登录失败"</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//解析cookie中的token</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (Cookie cookie : cookies) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__string">"token"</span>.equals(cookie.getName())) {</span></code><code><span class="code-snippet_outer"> String token = cookie.getValue();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//判断redis中是否存在token的记录信息,如果不存在就返回</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span>(stringRedisTemplate.opsForValue().<span class="code-snippet__keyword">get</span>(<span class="code-snippet__string">"login_token_"</span> + token) == <span class="code-snippet__literal">null</span>){</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__string">"自动登录失败"</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//解析token</span></span></code><code><span class="code-snippet_outer"> String userIdStr = JWTUtils.parseToken(token);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//通过token获取用户的信息</span></span></code><code><span class="code-snippet_outer"> User user = userService.queryByToken(token);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (Objects.nonNull(user) && user.getId().toString().equals(userIdStr)) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__string">"自动登录成功了"</span>;</span></code><code><span class="code-snippet_outer"> } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__string">"自动登录失败"</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__string">"自动登录失败"</span>;</span></code><code><span class="code-snippet_outer"> }</span></code></pre> </section> <p style="text-align: left;">总结:</p> <p style="text-align: left;"> <span style="letter-spacing: 0.578px;text-align: left;">通过使用Token和Cookie的方式</span>已实现了用户自动登录功能。原理是用户第一次登录成功之后将Token保存到Cookie中,然后用户再次登录时检测Token是否有效,从而实现自动登录的功能。</p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section powered-by="xiumi.us" style="margin-bottom: 0px;" data-mpa-powered-by="yiban.io"> <section> <img class="rich_pages wxw-img" data-backh="96" data-backw="578" data-galleryid="" data-imgfileid="100178701" data-ratio="0.16666666666666666" data-s="300,640" src="/upload/c8f924541c2de425a10733d3ee1e36a7.png" data-type="png" data-w="900" style="text-align: center;width: 100%;height: auto;"><br> </section> </section> <section powered-by="xiumi.us" style="margin-bottom: 0px;"> <p><span style="font-size: 15px;color: rgb(51, 51, 51);">工程名称:EDA-Robot机器狗</span></p> <p><span style="font-size: 15px;color: rgb(51, 51, 51);">工程作者:<span style="color: rgb(51, 51, 51);font-size: 15px;letter-spacing: 0.578px;">立创EDA课程案例推荐</span></span></p> </section> <p style="margin: 0px;padding: 0px;clear: both;min-height: 1em;"><br style="margin: 0px;padding: 0px;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, microsoft yahei, arial, sans-serif;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;></p> <section data-role="outer" label="edit by 135editor"> <h2 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="letter-spacing: 1px;"></span></h2> <section data-tools="135编辑器" data-id="us-4489579"> <section style="margin: 10px auto;"> <section> <section style="display: flex;justify-content: flex-start;"> <section> <section style="display: flex;justify-content: flex-start;margin-bottom: -10px;margin-left: 6px;z-index: 9;"> <section style="width: 20px;"> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 43.9 35.15" style="display: block;"> <g data-name="图层 2"> <g data-name="图层 1"> <path style="fill:none;" d="M11.73,11.17A78.33,78.33,0,0,1,15.58,3H10a88,88,0,0,0-5.29,8.2A18,18,0,0,0,4,14.86V30.15H19.29V14.86H11.58A17.42,17.42,0,0,1,11.73,11.17Z"></path> <path style="fill:none;" d="M32.34,11.17A78.33,78.33,0,0,1,36.19,3H30.61a88,88,0,0,0-5.29,8.2,18,18,0,0,0-.71,3.66V30.15H39.9V14.86H32.19A17.42,17.42,0,0,1,32.34,11.17Z"></path> <path style="fill:#dfdfdf;" d="M39.9,13.86H35.27a76.22,76.22,0,0,1,3.57-7.45L41.19,2H29.07l-.9,1.25a86.61,86.61,0,0,0-5.57,8.68A8.52,8.52,0,0,0,22,13.86H14.66a78.6,78.6,0,0,1,3.57-7.45L20.58,2H8.46l-.9,1.25c-.45.63-5.41,6.2-6.57,8.68a17.17,17.17,0,0,0-1,4.62l0,.16V35.15H43.9V13.86ZM19.29,32.15H4V16.86a18,18,0,0,1,.71-3.66A88,88,0,0,1,10,5h5.58a78.33,78.33,0,0,0-3.85,8.17,17.42,17.42,0,0,0-.15,3.69h7.71Zm20.61,0H24.61V16.86a18,18,0,0,1,.71-3.66A88,88,0,0,1,30.61,5h5.58a78.33,78.33,0,0,0-3.85,8.17,17.42,17.42,0,0,0-.15,3.69H39.9Z"></path> <path style="fill:#ffffff;" d="M39.9,11.86H35.27a76.22,76.22,0,0,1,3.57-7.45L41.19,0H29.07l-.9,1.25A86.61,86.61,0,0,0,22.6,9.93,8.52,8.52,0,0,0,22,11.86H14.66a78.6,78.6,0,0,1,3.57-7.45L20.58,0H8.46l-.9,1.25A86.61,86.61,0,0,0,2,9.93a17.17,17.17,0,0,0-1,4.62l0,.16V33.15H42.9V11.86ZM19.29,30.15H4V14.86a18,18,0,0,1,.71-3.66A88,88,0,0,1,10,3h5.58a78.33,78.33,0,0,0-3.85,8.17,17.42,17.42,0,0,0-.15,3.69h7.71Zm20.61,0H24.61V14.86a18,18,0,0,1,.71-3.66A88,88,0,0,1,30.61,3h5.58a78.33,78.33,0,0,0-3.85,8.17,17.42,17.42,0,0,0-.15,3.69H39.9Z"></path> <path style="fill:#3d89ff;" d="M11.73,11.17A78.33,78.33,0,0,1,15.58,3H10a88,88,0,0,0-5.29,8.2A18,18,0,0,0,4,14.86V30.15H19.29V14.86H11.58A17.42,17.42,0,0,1,11.73,11.17Z"></path> <path style="fill:#3d89ff;" d="M32.34,11.17A78.33,78.33,0,0,1,36.19,3H30.61a88,88,0,0,0-5.29,8.2,18,18,0,0,0-.71,3.66V30.15H39.9V14.86H32.19A17.42,17.42,0,0,1,32.34,11.17Z"></path> </g> </g> </svg> </section> </section> <section style="display: flex;align-items: flex-end;background-color: #edf5ff;"> <section style="font-size: 16px;color: rgb(61, 137, 255);text-align: center;padding: 9px 15px 9px 30px;"> <span style="font-size: 24px;"><strong data-brushtype="text">前言</strong></span> </section> <section style="width: 22px;"> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 51 65" style="display: block;"> <g data-name="图层 2"> <path style="fill:#abcdff;fill-rule:evenodd;" d="M51,0,0,50s20.49-.93,16,15Z"></path> <g data-name="图层 1"> <path style="fill:#fff;fill-rule:evenodd;" d="M16,65,51,0V65Z"></path> </g> </g> </svg> </section> </section> </section> </section> </section> </section> </section> <p style="text-align:justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><span style="letter-spacing: 1px;">花</span><span style="letter-spacing: 1px;font-size: 20px;"><strong>30元</strong></span><span style="letter-spacing: 1px;">,做了一只超可爱的机器狗!</span></p> <p style="text-align:justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><img class="rich_pages wxw-img" data-backh="325" data-backw="578" data-imgfileid="100178705" data-ratio="0.5625" src="/upload/1d0c9b7fc5cf4b73abb3d5e6e7f3f138.png" data-type="gif" data-w="640" style="cursor: pointer;vertical-align: inherit;width: 100%;max-inline-size: 100%;height: auto;border-radius: 9px;"></p> <h2 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="letter-spacing: 1px;">目前,项目已</span><span style="letter-spacing: 1px;font-size: 20px;"><strong>全开源</strong></span><span style="letter-spacing: 1px;">!</span></h2> <section style="line-height: 2em;"> <span style="letter-spacing: 1px;">它有哪些<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">功能</span></strong></span><span style="color: rgb(178, 178, 178);letter-spacing: 1px;font-size: 14px;"><em>(第1章)</em></span><span style="font-size: 20px;"><strong><em><span style="letter-spacing: 1px;">?</span></em></strong></span><strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">软硬件</span></strong><span style="letter-spacing: 1px;">怎么设计</span><span style="letter-spacing: 1px;font-size: 14px;"><em><span style="letter-spacing: 1px;color: rgb(178, 178, 178);">(2-3章)</span></em></span><span style="font-size: 20px;"><em><strong><span style="letter-spacing: 1px;">?</span></strong></em></span><span style="letter-spacing: 1px;">如何<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">校准舵机</span></strong></span><span style="letter-spacing: 1px;font-size: 14px;"><em><span style="letter-spacing: 1px;color: rgb(178, 178, 178);">(4章)</span></em></span><span style="font-size: 20px;"><strong><em><span style="letter-spacing: 1px;">?</span></em></strong></span><span style="letter-spacing: 1px;">开源资料入口</span><span style="color: rgb(178, 178, 178);letter-spacing: 1px;font-size: 14px;"><em>(6章)</em></span><em><strong><span style="letter-spacing: 1px;font-size: 20px;">?</span></strong></em><span style="letter-spacing: 1px;">下文咱们一一了解~</span> </section> <p style="line-height: 2em;margin-top: 40px;margin-bottom: 40px;"><br></p> <section data-role="title" data-tools="135编辑器" data-id="us-4502227"> <section style="margin: 10px auto;display: flex;justify-content: center;"> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 40px;letter-spacing: 1.5px;color: transparent;-webkit-text-stroke: 1px #3d89ff;line-height: 1em;"> <em><strong>0</strong><strong data-original-title="" title="">1</strong></em> </section> </section> <section style="display: flex;"> <section style="font-size: 16px;color: rgb(61, 137, 255);text-align: center;padding-right: 7px;padding-left: 7px;"> <span style="font-size: 20px;"><strong data-brushtype="text">功能&亮点</strong></span> </section> <section style="color: #466df1;transform: translateY(5px);-webkit-transform: translateY(5px);-moz-transform: translateY(5px);-o-transform: translateY(5px);"> <strong><span style="font-size: 25px;line-height: 0;font-family:ArialMT, Arial;">”</span></strong> </section> </section> <section style="flex-shrink: 0;margin-left: -10px;"> <section style="width: 30px;height: 30px;border-radius: 100%;background-color: rgb(237, 245, 255);"> <br> </section> </section> </section> </section> </section> <section data-tools="135编辑器" data-id="125425"> <section style="margin: 10px auto;"> <section style="background-color: rgb(247, 252, 255);padding-top: 15px;padding-right: 10px;padding-bottom: 30px;"> <section style="display: flex;justify-content: space-between;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">1</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><span style="letter-spacing: 1px;">支持</span><strong><span style="letter-spacing: 1px;">手机遥控</span></strong></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">2</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><span style="letter-spacing: 1px;">支持</span><strong><span style="letter-spacing: 1px;">表情、每日天气、时间</span></strong><span style="letter-spacing: 1px;">显示</span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">3</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><span style="letter-spacing: 1px;">电路大部分使用插件封装,成本低廉且易于新手焊接,适用于教学</span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">4</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><span style="letter-spacing: 1px;">本项目不含电池,成本大致为</span><span style="color:#2e8cff;"><strong><span style="letter-spacing: 1px;">30元</span></strong></span><span style="letter-spacing: 1px;">,主要费用在于舵机12元,屏幕4.5元,主控4元</span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">5</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height: 2em;margin-bottom: 15px;"><strong><span style="letter-spacing: 1px;"><span style="color: rgb(255, 0, 0);">支持功能拓展</span></span></strong><span style="letter-spacing: 1px;"><span style="color: rgb(255, 0, 0);"></span>,代码已完全开源,可以根据现有代码逻辑框架,添加更多好玩有趣的功能</span></p> <p style="line-height: 1em;"><span style="font-size: 13px;color: #a5a5a5;"><em><span style="letter-spacing: 1px;">当然你也可以完全重构,使用更好性能的主控</span></em></span></p> <p style="line-height: 1em;"><span style="font-size: 13px;color: #a5a5a5;"><em><span style="letter-spacing: 1px;">在软件上可以添加<span style="color: rgb(63, 63, 63);">语音交互,大模型对话</span>等等</span></em></span></p> <p style="line-height: 1em;"><span style="font-size: 13px;color: #a5a5a5;"><em><span style="letter-spacing: 1px;">在硬件上也可以添加<span style="color: rgb(63, 63, 63);">避障,测温,搭载炮台</span>等等</span></em></span></p> </section> </section> </section> </section> </section> </section> </section> </section> <section style="text-align: center;line-height: 2em;margin-bottom: 16px;margin-top: 16px;"> <span style="font-size: 20px;"><strong>表情显示▼</strong></span> </section> <section style="text-align: center;margin-bottom: 16px;margin-top: 16px;"> <strong><img class="rich_pages wxw-img js_insertlocalimg" data-backh="325" data-backw="578" data-imgfileid="100178702" data-ratio="0.5625" data-s="300,640" src="/upload/18334d11b9a9612d6a27bcfcf4d590e2.png" data-type="gif" data-w="640" style="width: 100%;height: auto;border-radius: 9px;"></strong> </section> <section style="text-align: justify;line-height: 2em;margin-bottom: 40px;margin-top: 40px;"> <br> </section> <section> <section> <h2 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="letter-spacing: 1px;"></span></h2> <section data-role="title" data-tools="135编辑器" data-id="us-4502227"> <section style="margin: 10px auto;display: flex;justify-content: center;"> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 40px;letter-spacing: 1.5px;color: transparent;-webkit-text-stroke: 1px #3d89ff;line-height: 1em;"> <em><strong>0</strong><strong data-original-title="" title="" data-num="2">2</strong></em> </section> </section> <section style="display: flex;"> <section style="font-size: 16px;color: rgb(61, 137, 255);text-align: center;padding-right: 7px;padding-left: 7px;"> <span style="font-size: 20px;"><strong data-brushtype="text">硬件设计</strong></span> </section> <section style="color: #466df1;transform: translateY(5px);-webkit-transform: translateY(5px);-moz-transform: translateY(5px);-o-transform: translateY(5px);"> <strong><span style="font-size: 25px;line-height: 0;font-family:ArialMT, Arial;">”</span></strong> </section> </section> <section style="flex-shrink: 0;margin-left: -10px;"> <section style="width: 30px;height: 30px;border-radius: 100%;background-color: rgb(237, 245, 255);"> <br> </section> </section> </section> </section> </section> <section data-role="paragraph"> <p style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing:1px;">电路由以下部分组成——电源部分、ESP8266主控、外部接口。</span></p> </section> <h2 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="letter-spacing: 1px;"></span></h2> <p style="text-align:center;line-height: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100178703" data-ratio="0.7111111111111111" src="/upload/20696b88bfe9b4ae00bd5de9812344e1.png" data-type="png" data-w="1080" style="vertical-align: inherit;width: 100%;"></p> <p style="text-align:center;line-height: 2em;"><span style="font-size: 16px;color: rgb(165, 165, 165);letter-spacing: 1px;">EDA-Robot插件版原理图</span></p> <p style="text-align:center;line-height: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100178704" data-ratio="0.5064814814814815" src="/upload/e343adc0eb1118aeb879ed84175693a5.png" data-type="png" data-w="1080" style="vertical-align: inherit;width: 100%;"></p> <p style="text-align:center;line-height: 2em;"><span style="font-size: 16px;color: rgb(165, 165, 165);letter-spacing: 1px;">EDA-Robot插件版PCB图</span></p> <p style="text-align:center;line-height: 2em;"><br></p> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>01 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">硬件参数</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section> <section data-role="list"> <section style="margin: 10px auto;"> <section style="background-color: rgb(247, 252, 255);padding-top: 15px;padding-right: 10px;padding-bottom: 30px;"> <section style="display: flex;justify-content: space-between;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">1</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><strong><span style="letter-spacing: 1px;"><span style="caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;">主控</span></span></strong><span style="letter-spacing: 1px;"><span style="caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"></span><span style="caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;">:</span>ESP8266</span></p> <p style="line-height:2em;"><span style="color:#a5a5a5;"><em><span style="letter-spacing: 1px;">内置WIFI功能,通过AP模式遥控</span></em></span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">2</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><strong><span style="letter-spacing: 1px;caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;">OLED显示屏</span></strong><span style="letter-spacing: 1px;caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;">:</span><span style="letter-spacing: 1px;">0.96寸</span></p> <p style="line-height:2em;"><span style="color:#a5a5a5;"><em><span style="letter-spacing: 1px;">可显示表情、时钟、天气等信息</span></em></span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">3</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><strong><span style="letter-spacing: 1px;"><span style="caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;">L</span></span><span style="letter-spacing: 1px;"><span style="caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;">DO线性稳压器</span></span></strong><span style="letter-spacing: 1px;"><span style="caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"></span><span style="caret-color: rgb(255, 0, 0);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;">:</span>AMS1117 </span></p> <p style="line-height:2em;"><span style="color:#a5a5a5;"><em><span style="letter-spacing: 1px;">负责将8.4V和5V电压分别转换成5V和3.3V,为舵机及主控提供电源</span></em></span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">4</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><strong><span style="letter-spacing: 1px;">舵机</span></strong><span style="letter-spacing: 1px;">:SG-90/MG90,支持180度/360度版本</span></p> <p style="line-height:2em;"><span style="color:#a5a5a5;"><em><span style="letter-spacing: 1px;">本文以360度版本为主</span></em></span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">5</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><strong><span style="letter-spacing: 1px;">供电:</span></strong><span style="letter-spacing: 1px;">14500双节电池组</span></p> <p style="line-height:2em;"><span style="color:#a5a5a5;"><em><span style="letter-spacing: 1px;">通过LDO降压稳压器供电</span></em></span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">6</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <section data-autoskip="1"> <p style="line-height:2em;"><span style="letter-spacing: 1px;"><span style="color: rgb(51, 51, 51);font-size: 16px;letter-spacing: 1px;background-color: rgb(255, 255, 255);">OL</span><span style="color: rgb(51, 51, 51);font-size: 16px;letter-spacing: 1px;background-color: rgb(255, 255, 255);">E</span><span style="color: rgb(51, 51, 51);font-size: 16px;letter-spacing: 1px;background-color: rgb(255, 255, 255);">D</span><span style="color: rgb(51, 51, 51);font-size: 16px;letter-spacing: 1px;background-color: rgb(255, 255, 255);">显示屏</span>支持<strong>SSD1315,SSD1306</strong>驱动</span><strong><span style="letter-spacing: 1px;"></span></strong></p> <p style="line-height:2em;"><span style="color:#a5a5a5;"><em><span style="letter-spacing: 1px;">该模块自带屏幕驱动电路,仅需接口接入即可。</span></em></span></p> </section> </section> </section> </section> </section> <section style="display: flex;justify-content: space-between;margin-top: 15px;"> <section style="flex-shrink: 0;padding-top: 25px;padding-right: 8px;padding-left: 8px;"> <section style="font-size: 16px;letter-spacing: 1.5px;color: rgb(255, 255, 255);background-color: rgb(46, 140, 255);width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 100%;"> <span data-original-title="" title="">6</span> </section> </section> <section style="width: 100%;" data-width="100%"> <section style="background-color: rgb(255, 255, 255);padding: 15px 10px;border-radius: 6px;"> <section style="line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(51, 51, 51);background: transparent;"> <p style="line-height:2em;"><span style="letter-spacing: 1px;">电路设计软件:嘉立创EDA</span></p> </section> </section> </section> </section> </section> </section> </section> <h3 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="letter-spacing: 1px;"></span></h3> <h3 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="font-size: 20px;text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;"><strong><span style="line-height: 1.7em;"></span></strong></span></h3> <section data-role="paragraph"> <p><br></p> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>02 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">原理解析</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <h3 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;font-size: 18px;"><strong>①ADC电量检测电路</strong></span></h3> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">修改分压器适配 8.4V 到 1V</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="color:#ff0000;"><strong><span style="letter-spacing: 1px;">现在需要适配新的输入电压范围</span></strong></span><span style="letter-spacing: 1px;">(最大 8.4V)到 ESP8266 的 1.0V ADC 输入。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><strong><span style="letter-spacing: 1px;">分压比计算如下:</span></strong></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"> <semantics> <mrow> <mtext> <span style="letter-spacing: 1px;">分压比</span> </mtext> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mfrac> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">1</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">V</span> </mi> </mrow> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">8.4</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">V</span> </mi> </mrow> </mfrac> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mfrac> <mn> <span style="letter-spacing: 1px;font-size: 17px;">1</span> </mn> <mn> <span style="letter-spacing: 1px;font-size: 17px;">8.4</span> </mn> </mfrac> <mo> <span style="letter-spacing: 1px;">≈</span> </mo> <mn> <span style="letter-spacing: 1px;">0.119</span> </mn> </mrow> </semantics><span style="letter-spacing: 1px;">分压比=8.4V1V=8.41≈0.119</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><strong><span style="letter-spacing: 1px;">根据分压公式:</span></strong></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"> <semantics> <mrow> <mfrac> <msub> <mi> <span style="letter-spacing: 1px;font-size: 17px;">R</span> </mi> <mn> <span style="letter-spacing: 1px;font-size: 17px;">2</span> </mn> </msub> <mrow> <msub> <mi> <span style="letter-spacing: 1px;font-size: 17px;">R</span> </mi> <mn> <span style="letter-spacing: 1px;font-size: 17px;">1</span> </mn> </msub> <mo> <span style="letter-spacing: 1px;font-size: 17px;">+</span> </mo> <msub> <mi> <span style="letter-spacing: 1px;font-size: 17px;">R</span> </mi> <mn> <span style="letter-spacing: 1px;font-size: 17px;">2</span> </mn> </msub> </mrow> </mfrac> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mn> <span style="letter-spacing: 1px;">0.119</span> </mn> </mrow> </semantics><span style="letter-spacing: 1px;">R1+R2R2=0.119</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><strong><span style="letter-spacing: 1px;">假设保持100k ,计算 :</span></strong></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"> <semantics> <mrow> <mfrac> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> </mrow> <mrow> <msub> <mi> <span style="letter-spacing: 1px;font-size: 17px;">R</span> </mi> <mn> <span style="letter-spacing: 1px;font-size: 17px;">1</span> </mn> </msub> <mo> <span style="letter-spacing: 1px;font-size: 17px;">+</span> </mo> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> </mrow> </mfrac> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mn> <span style="letter-spacing: 1px;">0.119</span> </mn> </mrow> </semantics><span style="letter-spacing: 1px;">R1+100k100k=0.119</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"> <semantics> <mrow> <msub> <mi> <span style="letter-spacing: 1px;">R</span> </mi> <mn> <span style="letter-spacing: 1px;font-size: 17px;">1</span> </mn> </msub> <mo> <span style="letter-spacing: 1px;">+</span> </mo> <mn> <span style="letter-spacing: 1px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;">k</span> </mi> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mfrac> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> </mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">0.119</span> </mn> </mfrac> <mo> <span style="letter-spacing: 1px;">≈</span> </mo> <mn> <span style="letter-spacing: 1px;">840</span> </mn> <mi> <span style="letter-spacing: 1px;">k</span> </mi> </mrow> </semantics><span style="letter-spacing: 1px;">R1+100k=0.119100k≈840k</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"> <semantics> <mrow> <msub> <mi> <span style="letter-spacing: 1px;">R</span> </mi> <mn> <span style="letter-spacing: 1px;font-size: 17px;">1</span> </mn> </msub> <mo> <span style="letter-spacing: 1px;">≈</span> </mo> <mn> <span style="letter-spacing: 1px;">740</span> </mn> <mi> <span style="letter-spacing: 1px;">k</span> </mi> <mi mathvariant="normal"> <span style="letter-spacing: 1px;">Ω</span> </mi> </mrow> </semantics><span style="letter-spacing: 1px;">R1≈740kΩ</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><strong><span style="letter-spacing: 1px;">对于 ,输出电压:</span></strong></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"> <semantics> <mrow> <msub> <mi> <span style="letter-spacing: 1px;">V</span> </mi> <mtext> <span style="letter-spacing: 1px;font-size: 17px;">out</span> </mtext> </msub> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mn> <span style="letter-spacing: 1px;">8.4</span> </mn> <mo> <span style="letter-spacing: 1px;">×</span> </mo> <mfrac> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> </mrow> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">740</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> <mo> <span style="letter-spacing: 1px;font-size: 17px;">+</span> </mo> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> </mrow> </mfrac> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mn> <span style="letter-spacing: 1px;">8.4</span> </mn> <mo> <span style="letter-spacing: 1px;">×</span> </mo> <mfrac> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mn> <span style="letter-spacing: 1px;font-size: 17px;">840</span> </mn> </mfrac> <mo> <span style="letter-spacing: 1px;">≈</span> </mo> <mn> <span style="letter-spacing: 1px;">1.0</span> </mn> <mi> <span style="letter-spacing: 1px;">V</span> </mi> </mrow> </semantics><span style="letter-spacing: 1px;">Vout=8.4×740k+100k100k=8.4×840100≈1.0V</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><strong><span style="letter-spacing: 1px;">对于电压较低时(如 4.2V),输出电压为:</span></strong></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"> <semantics> <mrow> <msub> <mi> <span style="letter-spacing: 1px;">V</span> </mi> <mtext> <span style="letter-spacing: 1px;font-size: 17px;">out</span> </mtext> </msub> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mn> <span style="letter-spacing: 1px;">4.2</span> </mn> <mo> <span style="letter-spacing: 1px;">×</span> </mo> <mfrac> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> </mrow> <mrow> <mn> <span style="letter-spacing: 1px;font-size: 17px;">740</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> <mo> <span style="letter-spacing: 1px;font-size: 17px;">+</span> </mo> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mi> <span style="letter-spacing: 1px;font-size: 17px;">k</span> </mi> </mrow> </mfrac> <mo> <span style="letter-spacing: 1px;">=</span> </mo> <mn> <span style="letter-spacing: 1px;">4.2</span> </mn> <mo> <span style="letter-spacing: 1px;">×</span> </mo> <mfrac> <mn> <span style="letter-spacing: 1px;font-size: 17px;">100</span> </mn> <mn> <span style="letter-spacing: 1px;font-size: 17px;">840</span> </mn> </mfrac> <mo> <span style="letter-spacing: 1px;">≈</span> </mo> <mn> <span style="letter-spacing: 1px;">0.5</span> </mn> <mi> <span style="letter-spacing: 1px;">V</span> </mi> </mrow> </semantics><span style="letter-spacing: 1px;">Vout=4.2×740k+100k100k=4.2×840100≈0.5V</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><em><strong><span style="letter-spacing: 1px;">分压电路成功将8.4V的输入电压,压缩到0-1V范围内</span></strong></em></p> <p style="text-align:justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><span style="text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;font-size: 18px;"><strong>②外部接口电路</strong></span></p> <p style="text-align:justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><strong><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">串口:</span></strong><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">为方便下载,</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;text-decoration: underline;">单独引出了IO0及GND接口</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;text-decoration: underline;">作为跳帽</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">插入接口,当插入跳帽时,IO0被拉低,进入下载模式。反之被主控部分电路拉高,进入工作模式。<br style="max-inline-size: 100%;"></span></p> <p style="text-align:justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><strong><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">电池:</span></strong><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">引出了外部充电拓展接口,</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">VIN与VBAT是</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;text-decoration: underline;">开关接口</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">,VIN与GND接口是外部充电模块接口。充电模块选择</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;text-decoration: underline;">满电电压大概在8.4V</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">的2串锂电池充电模块。<br style="max-inline-size: 100%;"></span></p> <p style="text-align:justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><strong><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">按键:</span></strong><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;text-decoration: underline;">使用IO2和IO15引脚</span><span style="max-inline-size: 100%;cursor: text;letter-spacing: 1px;">,IO2按键按下时拉低,空闲时被拉高。但由于IO15必须接下拉电阻,所以这里开关逻辑与IO2相反,按键按下时拉高,空闲时被拉低。</span></p> <p style="text-align: justify;line-height: 2em;margin-top: 40px;margin-bottom: 40px;"><br></p> <section data-role="title" data-tools="135编辑器" data-id="us-4502227"> <section style="margin: 10px auto;display: flex;justify-content: center;"> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 40px;letter-spacing: 1.5px;color: transparent;-webkit-text-stroke: 1px #3d89ff;line-height: 1em;"> <em><strong>0</strong><strong data-original-title="" title="" data-num="3">3</strong></em> </section> </section> <section style="display: flex;"> <section style="font-size: 16px;color: rgb(61, 137, 255);text-align: center;padding-right: 7px;padding-left: 7px;"> <span style="font-size: 20px;"><strong data-brushtype="text">软件代码</strong></span> </section> <section style="color: #466df1;transform: translateY(5px);-webkit-transform: translateY(5px);-moz-transform: translateY(5px);-o-transform: translateY(5px);"> <strong><span style="font-size: 25px;line-height: 0;font-family:ArialMT, Arial;">”</span></strong> </section> </section> <section style="flex-shrink: 0;margin-left: -10px;"> <section style="width: 30px;height: 30px;border-radius: 100%;background-color: rgb(237, 245, 255);"> <br> </section> </section> </section> </section> </section> <p style="text-align: justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><span style="letter-spacing: 1px;color: rgba(0, 0, 0, 0.9);font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: var(--articlefontsize);>完整的项目源码已放在附件</span><span style="letter-spacing: 1px;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: var(--articlefontsize);color: rgb(178, 178, 178);><em>(参考第6章指引前往原工程获取)</em></span></p> <p style="text-align:center;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;"><strong><img class="rich_pages wxw-img" data-imgfileid="100178708" data-ratio="0.8005952380952381" src="/upload/12cb832365e3c1d4d1004ea5b51a64b2.png" data-type="png" data-w="336" style="vertical-align:inherit;"></strong><br></span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">本章节只介绍部分比较重要的关键代码。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;"><em style="color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;letter-spacing: 0.578px;caret-color: rgb(255, 0, 0);"><span style="text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;font-size: 18px;"><strong>如何通过手机【控制】机器狗?</strong></span></em></span></p> <p style="text-align: justify;line-height: 2em;margin-top: 24px;margin-bottom: 24px;"><span style="line-height: 1.7em;text-decoration: none;font-size: 17px;letter-spacing: 1px;font-size: 17px;font-size: 17px;">为了控制机器狗,我写了一个网页,你可以直接使用,也可以参考下方了逻辑,自己写一个,并在此基础上进行拓展。</span></p> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>01 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">控制页面CSS样式表</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="css"><code><span class="code-snippet_outer"> <span class="code-snippet__selector-tag">body</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">margin</span>: <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">padding</span>: <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">font-family</span>: Arial, sans-serif;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-class">.container</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">max-width</span>: <span class="code-snippet__number">800px</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">margin</span>: <span class="code-snippet__number">0</span> auto;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">padding</span>: <span class="code-snippet__number">20px</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">text-align</span>: center;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-tag">h1</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">text-align</span>: center;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-tag">button</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">display</span>: inline-block;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">height</span>: auto;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">width</span>: auto;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">margin-top</span>: <span class="code-snippet__number">20px</span>;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">padding</span>: <span class="code-snippet__number">10px</span> <span class="code-snippet__number">20px</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">background-color</span>: deepskyblue;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">color</span>: <span class="code-snippet__number">#fff</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">border</span>: none;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">border-radius</span>: <span class="code-snippet__number">20px</span>; <span class="code-snippet__comment">/* 添加圆角 */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">text-decoration</span>: none;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">line-height</span>: <span class="code-snippet__number">2</span>; <span class="code-snippet__comment">/* 通过调整line-height的值来调整文字的垂直位置 */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">text-align</span>: center; <span class="code-snippet__comment">/* 文字居中 */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">box-shadow</span>: <span class="code-snippet__number">2px</span> <span class="code-snippet__number">2px</span> <span class="code-snippet__number">5px</span> <span class="code-snippet__built_in">rgba</span>(0, 0, 0, 0.2); <span class="code-snippet__comment">/* 添加立体感 */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">transition</span>: all <span class="code-snippet__number">0.3s</span> ease; <span class="code-snippet__comment">/* 添加过渡效果 */</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-tag">button</span><span class="code-snippet__selector-pseudo">:hover</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">background-color</span>: skyblue; <span class="code-snippet__comment">/* 鼠标悬停时的背景颜色 */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">transform</span>: <span class="code-snippet__built_in">translateY</span>(2px); <span class="code-snippet__comment">/* 点击效果 */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">box-shadow</span>: <span class="code-snippet__number">2px</span> <span class="code-snippet__number">2px</span> <span class="code-snippet__number">8px</span> <span class="code-snippet__built_in">rgba</span>(0, 0, 0, 0.3); <span class="code-snippet__comment">/* 添加更多立体感 */</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-class">.button-grid3</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">display</span>: grid;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">grid-template-columns</span>: <span class="code-snippet__built_in">repeat</span>(3, 1fr);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">gap</span>: <span class="code-snippet__number">10px</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">justify-content</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">align-content</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">text-align</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">margin</span>: <span class="code-snippet__number">20px</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-class">.button-grid2</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">display</span>: grid;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">grid-template-columns</span>: <span class="code-snippet__built_in">repeat</span>(2, 1fr);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">gap</span>: <span class="code-snippet__number">10px</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">justify-content</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">align-content</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">text-align</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">margin</span>: <span class="code-snippet__number">20px</span>;</span></code><code><span class="code-snippet_outer"> } <span class="code-snippet__selector-class">.button-grid1</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">display</span>: grid;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">border-radius</span>: <span class="code-snippet__number">20px</span>; <span class="code-snippet__comment">/* 添加圆角 */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">grid-template-columns</span>: <span class="code-snippet__built_in">repeat</span>(1, 1fr);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">justify-content</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">align-content</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">text-align</span>: center;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attribute">margin</span>: <span class="code-snippet__number">10px</span>;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> }</span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <p><br></p> <p><br></p> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>02 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">控制页面JavaScript代码</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <span style="background-color: rgb(240, 240, 240);color: inherit;font-size: var(--articleFontsize);letter-spacing: 0.034em;"></span> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 简化 AJAX 请求函数</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">function</span> <span class="code-snippet__title">sendCommand</span>(<span class="code-snippet__params">action</span>) </span>{</span></code><code><span class="code-snippet_outer"> fetch(<span class="code-snippet__string">`/<span class="code-snippet__subst">${action}</span>`</span>)</span></code><code><span class="code-snippet_outer"> .then(<span class="code-snippet__function"><span class="code-snippet__params">response</span> =></span> response.text())</span></code><code><span class="code-snippet_outer"> .catch(<span class="code-snippet__function"><span class="code-snippet__params">()</span> =></span> alert(<span class="code-snippet__string">'发送失败,请检查设备连接'</span>));</span></code><code><span class="code-snippet_outer"> } </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">function</span> <span class="code-snippet__title">refreshState</span>(<span class="code-snippet__params">url, displayElementId</span>) </span>{</span></code><code><span class="code-snippet_outer"> fetch(url)</span></code><code><span class="code-snippet_outer"> .then(<span class="code-snippet__function"><span class="code-snippet__params">response</span> =></span> response.text())</span></code><code><span class="code-snippet_outer"> .then(<span class="code-snippet__function"><span class="code-snippet__params">data</span> =></span> { <span class="code-snippet__built_in">document</span>.getElementById(displayElementId).innerText = data;</span></code><code><span class="code-snippet_outer"> });</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">function</span> <span class="code-snippet__title">setRefreshInterval</span>(<span class="code-snippet__params">url, displayElementId</span>) </span>{</span></code><code><span class="code-snippet_outer"> setInterval(<span class="code-snippet__function"><span class="code-snippet__params">()</span> =></span> refreshState(url, displayElementId), <span class="code-snippet__number">1000</span>);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">const</span> states = [</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/batteryVoltage'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'batteryVoltageDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/batteryPercentage'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'batteryPercentageDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine1offsetleftpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine1offsetleftpwmDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine1offsetrightpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine1offsetrightpwmDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine2offsetleftpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine2offsetleftpwmDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine2offsetrightpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine2offsetrightpwmDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine3offsetleftpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine3offsetleftpwmDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine3offsetrightpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine3offsetrightpwmDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine4offsetleftpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine4offsetleftpwmDisplay'</span> },</span></code><code><span class="code-snippet_outer"> { <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">'/engine4offsetrightpwm'</span>, <span class="code-snippet__attr">displayId</span>: <span class="code-snippet__string">'engine4offsetrightpwmDisplay'</span> }</span></code><code><span class="code-snippet_outer"> ];</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> states.forEach(<span class="code-snippet__function"><span class="code-snippet__params">state</span> =></span> setRefreshInterval(state.url, state.displayId));</span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <p><br></p> <p><br></p> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>03 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">控制页面HTML代码</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">h1</span>></span>EDA-Robot遥控台<span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->h1</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">p</span>></span>本项目基于ESP8266主控开发<span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->p</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">style</span>=<span class="code-snippet__string">"display:flex;justify-content:center"</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">p</span>></span>电压:<span class="code-snippet__tag"><<span class="code-snippet__name">span</span> <span class="code-snippet__attr">id</span>=<span class="code-snippet__string">"batteryVoltageDisplay"</span>></span>0<span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->span</span>></span><span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->p</span>></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">p</span>></span>电量:<span class="code-snippet__tag"><<span class="code-snippet__name">span</span> <span class="code-snippet__attr">id</span>=<span class="code-snippet__string">"batteryPercentageDisplay"</span>></span>0<span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->span</span>></span><span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->p</span>></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">style</span>=<span class="code-snippet__string">"background-color:papayawhip"</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">h3</span>></span>运动控制<span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->h3</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">style</span>=<span class="code-snippet__string">"display:flex;justify-content:center"</span>></span></span></code><code><span class="code-snippet_outer"> ↑</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">style</span>=<span class="code-snippet__string">"display:flex;justify-content:center"</span>></span></span></code><code><span class="code-snippet_outer"> ←</span></code><code><span class="code-snippet_outer"> →</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">style</span>=<span class="code-snippet__string">"display:flex;justify-content:center"</span>></span></span></code><code><span class="code-snippet_outer"> ↓</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span>></span></span></code><code><span class="code-snippet_outer"> 抬左手</span></code><code><span class="code-snippet_outer"> 抬右手</span></code><code><span class="code-snippet_outer"> 坐下</span></code><code><span class="code-snippet_outer"> 趴下</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> 自由模式开</span></code><code><span class="code-snippet_outer"> 自由模式关</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">style</span>=<span class="code-snippet__string">"background-color:limegreen"</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">h3</span>></span>表情控制<span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->h3</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span>></span></span></code><code><span class="code-snippet_outer"> 开心</span></code><code><span class="code-snippet_outer"> 生气</span></code><code><span class="code-snippet_outer"> 难受</span></code><code><span class="code-snippet_outer"> 好奇</span></code><code><span class="code-snippet_outer"> 喜欢</span></code><code><span class="code-snippet_outer"> 错误</span></code><code><span class="code-snippet_outer"> 晕</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">style</span>=<span class="code-snippet__string">"background-color:orange"</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">h3</span>></span>联网功能<span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->h3</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span>></span></span></code><code><span class="code-snippet_outer"> 时间</span></code><code><span class="code-snippet_outer"> 天气</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><!--/<span class="code-snippet__name"-->div</span>></span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">控制页面的代码是存放在FS文件系统中的,这里主要看AJAX请求函数,</span><span style="letter-spacing: 1px;text-decoration: underline;">这部分的请求与下一小节的页面路由监听代码相对应</span><span style="letter-spacing: 1px;">,我们通过<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">点击页面按钮触发请求</span></strong>。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="color: rgb(178, 178, 178);"><em><span style="letter-spacing: 1px;">这里进行了一些简化操作,避免html过长过大导致html加载和响应缓慢,这可能导致esp8266无法正确显示页面。</span></em></span><span style="letter-spacing: 1px;"></span></p> <section data-role="paragraph"> <section style="line-height: 2em;"> <em style="color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;letter-spacing: 0.578px;caret-color: rgb(255, 0, 0);"><span style="text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;font-size: 18px;"><strong>如何让机器狗【<em style="letter-spacing: 0.578px;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;caret-color: rgb(255, 0, 0);"><span style="text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;font-size: 18px;"><strong>运行起来</strong></span></em>】?</strong></span></em><strong><span style="font-size: var(--articleFontsize);letter-spacing: 1px;color: rgb(217, 33, 66);">给它注入点赛博灵魂~~</span></strong> </section> <p><br></p> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>04 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">页面路由监听</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="php"><code><span class="code-snippet_outer"> void handleWiFiConfig()</span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 启动服务器</span></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/left90"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">10</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/right90"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">11</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/front"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">1</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/back"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">4</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/left"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">2</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/right"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">3</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/toplefthand"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">5</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/toprighthand"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">6</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/sitdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">8</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/lie"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">7</span>; </span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// server.on("/dance", HTTP_GET, [](AsyncWebServerRequest *request)</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// {</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// actionstate = 7; // 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// request->send(200, "text/plain", "Front function started"); });</span></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/free"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> freestate=<span class="code-snippet__keyword">true</span>;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/offfree"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> freestate=<span class="code-snippet__keyword">false</span>;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/histate"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">0</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/angrystate"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">1</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/errorstate"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">2</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine1offsetleftpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine1offsetleftpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine2offsetleftpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine2offsetleftpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine3offsetleftpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine3offsetleftpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine4offsetleftpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine4offsetleftpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine1offsetrightpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine1offsetrightpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine2offsetrightpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine2offsetrightpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine3offsetrightpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine3offsetrightpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine4offsetrightpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine4offsetrightpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine4offsetrightpwm"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(engine4offsetrightpwm)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/batteryVoltage"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(batteryVoltage)); }); </span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/batteryPercentage"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(batteryPercentage)); }); </span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/speed"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> { request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, String(speed)); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/speedup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> speed++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/speeddown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> speed--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine1offsetrightpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine1offsetrightpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine1offsetrightpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine1offsetrightpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine1offsetleftpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine1offsetleftpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine1offsetleftpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine1offsetleftpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine2offsetrightpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine2offsetrightpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine2offsetrightpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine2offsetrightpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine2offsetleftpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine2offsetleftpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine2offsetleftpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine2offsetleftpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine3offsetrightpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine3offsetrightpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine3offsetrightpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine3offsetrightpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine3offsetleftpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine3offsetleftpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine3offsetleftpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine3offsetleftpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine4offsetrightpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine4offsetrightpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine4offsetrightpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine4offsetrightpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine4offsetleftpwmup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine4offsetleftpwm++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine4offsetleftpwmdown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> engine4offsetleftpwm--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/speedup"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> speed++; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/speeddown"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> speed--;</span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/dowhatstate"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">3</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/lovestate"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">4</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/sickstate"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">5</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/yunstate"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">6</span>; </span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/time"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">8</span>; </span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/weather"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> emojiState = <span class="code-snippet__number">7</span>; <span class="code-snippet__comment">// 设置标志,执行舵机动作</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"Front function started"</span>); });</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/connect"</span>, HTTP_POST, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 获取POST参数:ssid、pass、uid、city、api</span></span></code><code><span class="code-snippet_outer"> String ssid = request->getParam(<span class="code-snippet__string">"ssid"</span>, <span class="code-snippet__keyword">true</span>)->value();</span></code><code><span class="code-snippet_outer"> String pass = request->getParam(<span class="code-snippet__string">"pass"</span>, <span class="code-snippet__keyword">true</span>)->value();</span></code><code><span class="code-snippet_outer"> String uid = request->getParam(<span class="code-snippet__string">"uid"</span>, <span class="code-snippet__keyword">true</span>)->value();</span></code><code><span class="code-snippet_outer"> String city = request->getParam(<span class="code-snippet__string">"city"</span>, <span class="code-snippet__keyword">true</span>)->value();</span></code><code><span class="code-snippet_outer"> String api = request->getParam(<span class="code-snippet__string">"api"</span>, <span class="code-snippet__keyword">true</span>)->value();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 打印接收到的参数</span></span></code><code><span class="code-snippet_outer"> Serial.println(ssid);</span></code><code><span class="code-snippet_outer"> Serial.println(pass);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 保存WiFi信息到JSON文件</span></span></code><code><span class="code-snippet_outer"> DynamicJsonDocument doc(<span class="code-snippet__number">1024</span>);</span></code><code><span class="code-snippet_outer"> doc[<span class="code-snippet__string">"ssid"</span>] = ssid;</span></code><code><span class="code-snippet_outer"> doc[<span class="code-snippet__string">"pass"</span>] = pass;</span></code><code><span class="code-snippet_outer"> doc[<span class="code-snippet__string">"uid"</span>] = uid;</span></code><code><span class="code-snippet_outer"> doc[<span class="code-snippet__string">"city"</span>] = city;</span></code><code><span class="code-snippet_outer"> doc[<span class="code-snippet__string">"api"</span>] = api;</span></code><code><span class="code-snippet_outer"> fs::File file = SPIFFS.open(ssidFile, <span class="code-snippet__string">"w"</span>); <span class="code-snippet__comment">// 打开文件进行写入</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (file) {</span></code><code><span class="code-snippet_outer"> serializeJson(doc, file); <span class="code-snippet__comment">// 将JSON内容写入文件</span></span></code><code><span class="code-snippet_outer"> file.close(); <span class="code-snippet__comment">// 关闭文件</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 更新全局变量</span></span></code><code><span class="code-snippet_outer"> useruid = uid;</span></code><code><span class="code-snippet_outer"> cityname = city;</span></code><code><span class="code-snippet_outer"> weatherapi = api;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 开始连接WiFi</span></span></code><code><span class="code-snippet_outer"> WiFi.begin(ssid.c_str(), pass.c_str());</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 发送HTML响应,告知用户正在连接</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/html"</span>, <span class="code-snippet__string">"<h1>Connecting...</h1>"</span>); });</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 检查SPIFFS文件系统中是否存在index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (SPIFFS.exists(<span class="code-snippet__string">"/index.html"</span>)) {</span></code><code><span class="code-snippet_outer"> fs::File file = SPIFFS.open(<span class="code-snippet__string">"/index.html"</span>, <span class="code-snippet__string">"r"</span>); <span class="code-snippet__comment">// 打开index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (file) {</span></code><code><span class="code-snippet_outer"> size_t fileSize = file.size(); <span class="code-snippet__comment">// 获取文件大小</span></span></code><code><span class="code-snippet_outer"> String fileContent;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 逐字节读取文件内容</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">while</span> (file.available()) {</span></code><code><span class="code-snippet_outer"> fileContent += (char)file.read();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> file.close(); <span class="code-snippet__comment">// 关闭文件</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 返回HTML内容</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/html"</span>, fileContent);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 如果文件不存在,返回404错误</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">404</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"File Not Found"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/control.html"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 检查SPIFFS文件系统中是否存在index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (SPIFFS.exists(<span class="code-snippet__string">"/control.html"</span>)) {</span></code><code><span class="code-snippet_outer"> fs::File file = SPIFFS.open(<span class="code-snippet__string">"/control.html"</span>, <span class="code-snippet__string">"r"</span>); <span class="code-snippet__comment">// 打开index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (file) {</span></code><code><span class="code-snippet_outer"> size_t fileSize = file.size(); <span class="code-snippet__comment">// 获取文件大小</span></span></code><code><span class="code-snippet_outer"> String fileContent;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 逐字节读取文件内容</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">while</span> (file.available()) {</span></code><code><span class="code-snippet_outer"> fileContent += (char)file.read();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> file.close(); <span class="code-snippet__comment">// 关闭文件</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 返回HTML内容</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/html"</span>, fileContent);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 如果文件不存在,返回404错误</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">404</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"File Not Found"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/engine.html"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 检查SPIFFS文件系统中是否存在index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (SPIFFS.exists(<span class="code-snippet__string">"/engine.html"</span>)) {</span></code><code><span class="code-snippet_outer"> fs::File file = SPIFFS.open(<span class="code-snippet__string">"/engine.html"</span>, <span class="code-snippet__string">"r"</span>); <span class="code-snippet__comment">// 打开index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (file) {</span></code><code><span class="code-snippet_outer"> size_t fileSize = file.size(); <span class="code-snippet__comment">// 获取文件大小</span></span></code><code><span class="code-snippet_outer"> String fileContent;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 逐字节读取文件内容</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">while</span> (file.available()) {</span></code><code><span class="code-snippet_outer"> fileContent += (char)file.read();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> file.close(); <span class="code-snippet__comment">// 关闭文件</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 返回HTML内容</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/html"</span>, fileContent);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 如果文件不存在,返回404错误</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">404</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"File Not Found"</span>); });</span></code><code><span class="code-snippet_outer"> server.on(<span class="code-snippet__string">"/setting.html"</span>, HTTP_GET, [](AsyncWebServerRequest *request)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 检查SPIFFS文件系统中是否存在index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (SPIFFS.exists(<span class="code-snippet__string">"/setting.html"</span>)) {</span></code><code><span class="code-snippet_outer"> fs::File file = SPIFFS.open(<span class="code-snippet__string">"/setting.html"</span>, <span class="code-snippet__string">"r"</span>); <span class="code-snippet__comment">// 打开index.html文件</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (file) {</span></code><code><span class="code-snippet_outer"> size_t fileSize = file.size(); <span class="code-snippet__comment">// 获取文件大小</span></span></code><code><span class="code-snippet_outer"> String fileContent;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 逐字节读取文件内容</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">while</span> (file.available()) {</span></code><code><span class="code-snippet_outer"> fileContent += (char)file.read();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> file.close(); <span class="code-snippet__comment">// 关闭文件</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 返回HTML内容</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">200</span>, <span class="code-snippet__string">"text/html"</span>, fileContent);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 如果文件不存在,返回404错误</span></span></code><code><span class="code-snippet_outer"> request->send(<span class="code-snippet__number">404</span>, <span class="code-snippet__string">"text/plain"</span>, <span class="code-snippet__string">"File Not Found"</span>); });</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 启动服务器</span></span></code><code><span class="code-snippet_outer"> server.begin();</span></code><code><span class="code-snippet_outer">};</span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">这部分的代码较长,是<span style="letter-spacing: 1px;color: rgb(0, 128, 255);"><strong>所有WebServer的页面路由监听</strong></span>,与页面中按钮触发的url对应,这里的</span><span style="letter-spacing: 1px;text-decoration: underline;">url务必检查仔细</span><span style="letter-spacing: 1px;">,如果</span><span style="letter-spacing: 1px;text-decoration: underline;">不能对应就无法监听到页面请求是否触发</span><span style="letter-spacing: 1px;">,硬件也无法做出对应的响应。<br></span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">另外,在/connect下还<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">添加了写入信息到FS文件系统中的功能</span></strong>,只要</span><span style="letter-spacing: 1px;text-decoration: underline;">每次开机执行读取</span><span style="letter-spacing: 1px;">就</span><span style="letter-spacing: 1px;text-decoration: underline;">不需要重复配置网络信息</span><span style="letter-spacing: 1px;">了。</span></p> <section data-role="paragraph"> <p><br></p> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4564944" draggable="true"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>05 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">读取FS系统保存的json文件</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">void</span> loadWiFiConfig()</span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (SPIFFS.begin())</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">fs</span>::File file = SPIFFS.open(ssidFile, <span class="code-snippet__string">"r"</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (file)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> DynamicJsonDocument doc(<span class="code-snippet__number">1024</span>);</span></code><code><span class="code-snippet_outer"> DeserializationError error = deserializeJson(doc, file);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (!error)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__built_in">String</span> ssid = doc[<span class="code-snippet__string">"ssid"</span>];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__built_in">String</span> pass = doc[<span class="code-snippet__string">"pass"</span>];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__built_in">String</span> uid = doc[<span class="code-snippet__string">"uid"</span>];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__built_in">String</span> city = doc[<span class="code-snippet__string">"city"</span>];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__built_in">String</span> api = doc[<span class="code-snippet__string">"api"</span>];</span></code><code><span class="code-snippet_outer"> useruid = uid;</span></code><code><span class="code-snippet_outer"> cityname = city;</span></code><code><span class="code-snippet_outer"> weatherapi = api;</span></code><code><span class="code-snippet_outer"> WiFi.begin(ssid.c_str(), pass.c_str());</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 尝试连接WiFi,最多等待10秒</span></span></code><code><span class="code-snippet_outer"> unsigned long startAttemptTime = millis();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">while</span> (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < <span class="code-snippet__number">5000</span>)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 如果连接失败,打印状态</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (WiFi.status() != WL_CONNECTED)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> Serial.println(<span class="code-snippet__string">"WiFi connection failed, starting captive portal..."</span>);</span></code><code><span class="code-snippet_outer"> handleWiFiConfig(); <span class="code-snippet__comment">// 启动强制门户</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">else</span></span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> Serial.println(<span class="code-snippet__string">"WiFi connected"</span>);</span></code><code><span class="code-snippet_outer"> timeClient.begin();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> file.close();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">前面我们讲了在/connect路由监听下,添加了将信息保存的FS文件系统,那么,这里的loadWiFiConfig()<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">方法就是</span></strong></span><span style="letter-spacing: 1px;text-decoration: underline;">读取FS文件系统的Json文件,并将数据同步到全局变量之中</span><span style="letter-spacing: 1px;">,这样就不需要每次开机进入配置页面配网了,<strong>程序会自动加载上次配网保存的信息</strong>,极为方便。</span></p> <section data-role="paragraph"> <p><br></p> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>06 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">运动状态</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="swift"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">switch</span> (actionstate)</span></code><code><span class="code-snippet_outer"> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">0</span> <span class="code-snippet__comment">/* constant-expression */</span>:</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">/* code */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">1</span>:</span></code><code><span class="code-snippet_outer"> front(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">2</span>:</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">left</span>(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">3</span>:</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">right</span>(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">4</span>:</span></code><code><span class="code-snippet_outer"> back(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">5</span>:</span></code><code><span class="code-snippet_outer"> toplefthand(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">6</span>:</span></code><code><span class="code-snippet_outer"> toprighthand(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">10</span>:</span></code><code><span class="code-snippet_outer"> left90(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">11</span>:</span></code><code><span class="code-snippet_outer"> right90(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">7</span>:</span></code><code><span class="code-snippet_outer"> lie(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">8</span>:</span></code><code><span class="code-snippet_outer"> sitdown(); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">case</span> <span class="code-snippet__number">9</span>:</span></code><code><span class="code-snippet_outer"> emojiState = random(<span class="code-snippet__number">0</span>, <span class="code-snippet__number">7</span>); <span class="code-snippet__comment">// 执行一次舵机动作</span></span></code><code><span class="code-snippet_outer"> actionstate = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">default</span>:</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> </span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;text-decoration: underline;">运动状态代码与前面的路由监听对应</span><span style="letter-spacing: 1px;">,之所以没有把动作函数直接写入路由监听的代码,这是因为会导致页面响应过久,导致页面无法加载或者触发程序死机然后重启。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">为了避免这个情况发生,我们<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">通过actionstate变量定义运动状态</span></strong>,然后再loop函数中判断。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">这里选择的是switch,而并没有使用if-else,</span><span style="letter-spacing: 1px;text-decoration: underline;">理论上对应顺序较长的数据switch性能略好</span><span style="letter-spacing: 1px;">,看个人喜欢,其实都可以用。</span></p> <section data-role="paragraph"> <p><br></p> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>07 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">前进运动</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">void</span> <span class="code-snippet__title">front</span>(<span class="code-snippet__params"></span>)</span></span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//+30C 2/3</span></span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine2offsetleftpwm);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine3offsetleftpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//-30C 1/4</span></span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine1offsetrightpwm);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine4offsetrightpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 0C 2/3</span></span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine2offsetrightpwm);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine3offsetrightpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 0C 1/4</span></span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine1offsetleftpwm);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine4offsetleftpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//+30C 1/4</span></span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine1offsetleftpwm);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine4offsetleftpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//-30C 2/3</span></span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine2offsetrightpwm);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine3offsetrightpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 0C 1/4</span></span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine1offsetrightpwm);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine4offsetrightpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo1.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo4.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 0C 2/3</span></span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span> + speed + engine2offsetleftpwm);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span> - speed - engine3offsetleftpwm);</span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">500</span>-runtime);</span></code><code><span class="code-snippet_outer"> servo2.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer"> servo3.writeMicroseconds(<span class="code-snippet__number">1500</span>);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <section data-role="paragraph"> <p><br></p> <p><br></p> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>08 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">ADC电量检测</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="width: 100%;" mpa-from-tpl="t"> <section style="overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;" mpa-from-tpl="t"> <section mpa-from-tpl="t" data-mpa-scroll-mark="0"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__comment">// 对 ADC 数据多次采样并计算平均值</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">float</span> <span class="code-snippet__title">getAverageAdcVoltage</span>(<span class="code-snippet__params"></span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">long</span> totalAdcValue = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 多次采样</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">int</span> i = <span class="code-snippet__number">0</span>; i < numSamples; i++) {</span></code><code><span class="code-snippet_outer"> totalAdcValue += analogRead(A0); <span class="code-snippet__comment">// 读取 ADC 数据</span></span></code><code><span class="code-snippet_outer"> delay(<span class="code-snippet__number">10</span>); <span class="code-snippet__comment">// 每次采样间隔 10ms</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 计算平均 ADC 值</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">float</span> averageAdcValue = totalAdcValue / (<span class="code-snippet__keyword">float</span>)numSamples;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 将 ADC 值转换为电压</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> (averageAdcValue / <span class="code-snippet__number">1023.0</span>) * <span class="code-snippet__number">1.0</span>; <span class="code-snippet__comment">// ESP8266 的参考电压为 1.0V</span></span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">// 计算电池电量百分比的函数</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">int</span> <span class="code-snippet__title">mapBatteryPercentage</span>(<span class="code-snippet__params"><span class="code-snippet__keyword">float</span> voltage</span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (voltage <= minVoltage) <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">0</span>; <span class="code-snippet__comment">// 小于等于最小电压时,电量为 0%</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (voltage >= maxVoltage) <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">100</span>; <span class="code-snippet__comment">// 大于等于最大电压时,电量为 100%</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 根据线性比例计算电量百分比</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> (<span class="code-snippet__keyword">int</span>)((voltage - minVoltage) / (maxVoltage - minVoltage) * <span class="code-snippet__number">100</span>);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> </section> </section> <p style="text-align: center;font-size: 12px;color: rgb(170, 170, 170);">可以上下滚动</p> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">与小车不同,</span><span style="letter-spacing: 1px;text-decoration: underline;">机器狗不能像小车那样简单控制</span><span style="letter-spacing: 1px;">电机正反转,实现前进后退,这里<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">需要</span></strong>观察四足动物,<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">进行一些仿生模拟</span></strong>,用舵机模拟四足动物前进时的四足变化情况。<strong>下一章,我们就讲这个!</strong></span></p> <h2 style="font-size: 17px;margin-top: 25px;margin-bottom: 25px;line-height: 2em;"> <section style="letter-spacing: 1px;margin-top: 40px;margin-bottom: 40px;line-height: 2em;"> <br> </section></h2> <section data-role="title" data-tools="135编辑器" data-id="us-4502227" draggable="true"> <section style="margin: 10px auto;display: flex;justify-content: center;"> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 40px;letter-spacing: 1.5px;color: transparent;-webkit-text-stroke: 1px #3d89ff;line-height: 1em;"> <em><strong>0</strong><strong data-original-title="" title="">4</strong></em> </section> </section> <section style="display: flex;"> <section style="font-size: 16px;color: rgb(61, 137, 255);text-align: center;padding-right: 7px;padding-left: 7px;"> <span style="font-size: 20px;"><strong data-brushtype="text">舵机校准</strong></span> </section> <section style="color: #466df1;transform: translateY(5px);-webkit-transform: translateY(5px);-moz-transform: translateY(5px);-o-transform: translateY(5px);"> <strong><span style="font-size: 25px;line-height: 0;font-family:ArialMT, Arial;">”</span></strong> </section> </section> <section style="flex-shrink: 0;margin-left: -10px;"> <section style="width: 30px;height: 30px;border-radius: 100%;background-color: rgb(237, 245, 255);"> <br> </section> </section> </section> </section> </section> <p style="text-align: justify;max-inline-size: 100%;margin-top: 20px;margin-bottom: 20px;cursor: text;color: rgb(51, 51, 51);caret-color: rgb(255, 0, 0);line-height: 2em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><em><span style="text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;font-size: 18px;"><strong>如何让机器狗麻溜滴【走起来】且不顺拐?</strong></span></em></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">机器小狗使用360度舵机,其拓展性高,但不像180度舵机那样,可以直接控制旋转角度,所有我们需要进行舵机校准,确保舵机转速,角度均合适。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="text-decoration: underline;"><em><span style="text-decoration: underline;letter-spacing: 1px;">说明:刷入程序的舵机校准数据并不是通用的,这要根据自己的舵机情况进行调整。</span></em></span></p> <p style="text-align: center;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="text-decoration: underline;"><em><span style="text-decoration: underline;letter-spacing: 1px;padding: 0px 0.5em;"><img class="rich_pages wxw-img" data-imgfileid="100178707" data-ratio="1.695" src="/upload/dc9ff7f6319b2c33d1d83d95516bcf40.png" data-type="png" data-w="400" style="vertical-align: inherit;letter-spacing: 0.578px;width: 207px;height: 351px;border-radius: 9px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"></span></em></span></p> <section style="margin-top: 16px;margin-bottom: 24px;line-height: 2em;"> <span style="letter-spacing: 1px;">通过【EDA-Robot控制中心】校准,会简单很多!教程如下:</span> </section> <h3 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;text-align: center;font-size: 17px;"><span style="text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;font-size: 32px;"><strong>校准步骤</strong></span></h3> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">参考下图,通过减少和增加电机【<span style="letter-spacing: 1px;">左右转补偿按钮</span>】校准电机。</span><br></p> <p style="text-align: center;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100178709" data-ratio="1.4578313253012047" src="/upload/c2b18cdb3329d018adc57370f51ef041.png" data-type="png" data-w="498" style="vertical-align: inherit;width: 296px;height: 432px;border-radius: 9px;"></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="font-size: 20px;text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;"><strong>粗略校准</strong></span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">1.<strong>将所有脚固定到相同角度</strong>。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">2.滑到校准页的底部,<strong>点击一次</strong>‘电机左转90度’。</span><br></p> <p style="text-align: center;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><img class="rich_pages wxw-img" data-backh="174" data-backw="451" data-imgfileid="100178706" data-ratio="0.3858093126385809" src="/upload/78131806100300d89fb492b3e7c300a5.png" data-type="png" data-w="451" style="vertical-align: inherit;width: 302px;height: 117px;"><span style="letter-spacing: 1px;"><br></span></p> <p style="text-align: justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">3.找到</span><span style="letter-spacing: 1px;text-decoration: underline;">转动大于90度</span><span style="letter-spacing: 1px;text-decoration: underline;">或小于</span><span style="letter-spacing: 1px;">90度的脚,<strong>进行舵机补偿</strong>。</span></p> <p style="text-align: justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;"><br></span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="font-size: 20px;text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;"><strong>精确校准</strong></span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">接着,请按一下步骤进行精调。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">1.将所有脚固定到相同角度。<br style="border-width: 0px;border-style: solid;border-color: rgb(229, 231, 235);">2.滑到校准页的底部,<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">点击4次</span></strong>‘电机左转90度’。<br style="border-width: 0px;border-style: solid;border-color: rgb(229, 231, 235);">3.找到</span><span style="letter-spacing: 1px;text-decoration: underline;">转动大于360度或小于360度的脚</span><span style="letter-spacing: 1px;">,<strong><span style="letter-spacing: 1px;color: rgb(0, 128, 255);">进行舵机补偿</span></strong>。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;"><br></span></p> <h3 style="margin-top: 20px;margin-bottom: 20px;line-height: 2em;font-size: 17px;"><span style="font-size: 20px;text-decoration: underline;background-color: rgb(255, 255, 196);letter-spacing: 1px;line-height: 1.7em;"><strong>修改程序重新烧录</strong></span></h3> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;text-decoration: underline;">记录下认为合理的各个电机补偿值,修改程序的补偿定义,重新刷入程序</span><span style="letter-spacing: 1px;">,当然,不重新输入也可以,这个值是立即生效的。<br></span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;"><span style="letter-spacing: 1px;color: rgb(178, 178, 178);"><em>但是为了能快速响应,避免重复刷写降低寿命,所以不会保存到FS文件系统,下次重启也不会被保留。</em></span></span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100178710" data-ratio="0.5546296296296296" src="/upload/b033c7e3c7eaddd4f7122eabdb34d262.png" data-type="png" data-w="1080" style="vertical-align: inherit;width: 100%;"></p> <p><span style="color: rgb(178, 178, 178);"><em>当然啦!</em></span><span style="color: rgb(217, 33, 66);"><em>其实更</em></span><span style="color: rgb(217, 33, 66);"><em>推荐使用180度版本</em></span><span style="color: rgb(178, 178, 178);"><em>,因为其自带限位器</em><em>,为了便于大家DIY,原工程中,已</em></span><span style="color: rgb(217, 33, 66);"><em>开源了180度舵机的版本</em></span><span style="color: rgb(178, 178, 178);"><em>。可参考第6章指引,前往原工程查看!</em></span></p> <section style="margin-top: 40px;margin-bottom: 40px;line-height: 2em;"> <br> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4502227"> <section style="margin: 10px auto;display: flex;justify-content: center;"> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 40px;letter-spacing: 1.5px;color: transparent;-webkit-text-stroke: 1px #3d89ff;line-height: 1em;"> <em><strong>05</strong></em> </section> </section> <section style="display: flex;"> <section style="font-size: 16px;color: rgb(61, 137, 255);text-align: center;padding-right: 7px;padding-left: 7px;"> <span style="font-size: 20px;"><strong data-brushtype="text">3D外壳结构</strong></span> </section> <section style="color: #466df1;transform: translateY(5px);-webkit-transform: translateY(5px);-moz-transform: translateY(5px);-o-transform: translateY(5px);"> <strong><span style="font-size: 25px;line-height: 0;font-family:ArialMT, Arial;">”</span></strong> </section> </section> <section style="flex-shrink: 0;margin-left: -10px;"> <section style="width: 30px;height: 30px;border-radius: 100%;background-color: rgb(237, 245, 255);"> <br> </section> </section> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">3D外壳设计软件:<span style="letter-spacing: 1px;">嘉立创云CAD</span><br></span></p> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>01 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">主体</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100178712" data-ratio="0.5537037037037037" src="/upload/93a677998d11846304bc3d388f25f90e.png" data-type="png" data-w="1080" style="vertical-align: inherit;width: 100%;"></p> <section> <section data-role="list"> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">红框部分是</span><span style="letter-spacing: 1px;text-decoration: underline;">8.4V的2串锂电池充电模块卡槽</span><span style="letter-spacing: 1px;">,连接到电路上的充电接口,可以用胶水固定</span></p> <section data-role="list"> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">蓝框部分是</span><span style="letter-spacing: 1px;text-decoration: underline;">船型10x15mm船型开关卡槽</span><span style="letter-spacing: 1px;">,连接到电路上的开关接口,用于通断供电电路</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;"></span></p> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><br></p> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>02 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">底壳</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100178713" data-ratio="0.5601851851851852" src="/upload/76679c3d42ab8a4245e98dc83476a658.png" data-type="png" data-w="1080" style="vertical-align: inherit;width: 100%;"></p> <section> <section data-role="list"> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">底壳部分为舵机设计了</span><span style="letter-spacing: 1px;text-decoration: underline;">4个限位槽</span><span style="letter-spacing: 1px;">,盖上主体壳后PCB会将舵机压住,所以没有设计螺丝孔,可以正常使用。</span></p> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;"><br></span></p> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4564944"> <section style="margin: 10px auto;display: flex;justify-content: flex-start;"> <section> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 30px;letter-spacing: 1.5px;color: #ffc14a;line-height: 1.1em;"> <span style="font-size:28px;"><strong>03 </strong></span> </section> </section> <section style="font-size: 20px;color: rgb(46, 140, 255);text-align: center;letter-spacing: 1.5px;padding-right: 5px;"> <strong data-brushtype="text">脚</strong> </section> </section> <section style="height: 4px;background-image: linear-gradient(to right, rgb(46, 140, 255), rgb(255, 193, 74));background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"> <br> </section> </section> </section> </section> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100178714" data-ratio="0.5583333333333333" src="/upload/1d9d84e9ce35a5443abb20774d042137.png" data-type="png" data-w="1080" style="vertical-align: inherit;width: 100%;"></p> <section> <section data-role="list"> <p style="text-align:justify;margin-top: 20px;margin-bottom: 20px;line-height: 2em;"><span style="letter-spacing: 1px;">红框部分是</span><span style="letter-spacing: 1px;text-decoration: underline;">螺丝卡槽</span><span style="letter-spacing: 1px;">,可以直接使用舵机附带的两颗大头螺丝。</span></p> </section> <section style="margin-top: 40px;margin-bottom: 40px;line-height: 2em;"> <br> </section> <section data-role="title" data-tools="135编辑器" data-id="us-4502227"> <section style="margin: 10px auto;display: flex;justify-content: center;"> <section style="display: flex;align-items: flex-end;"> <section style="flex-shrink: 0;"> <section style="font-size: 40px;letter-spacing: 1.5px;color: transparent;-webkit-text-stroke: 1px #3d89ff;line-height: 1em;"> <em><strong>0</strong><strong data-original-title="" title="" data-num="5">6</strong></em> </section> </section> <section style="display: flex;"> <section style="font-size: 16px;color: rgb(61, 137, 255);text-align: center;padding-right: 7px;padding-left: 7px;"> <span style="font-size: 20px;"><strong data-brushtype="text">开源网址</strong></span> </section> <section style="color: #466df1;transform: translateY(5px);-webkit-transform: translateY(5px);-moz-transform: translateY(5px);-o-transform: translateY(5px);"> <strong><span style="font-size: 25px;line-height: 0;font-family:ArialMT, Arial;">”</span></strong> </section> </section> <section style="flex-shrink: 0;margin-left: -10px;"> <section style="width: 30px;height: 30px;border-radius: 100%;background-color: rgb(237, 245, 255);"> <br> </section> </section> </section> </section> </section> <p style="margin-top: 20px;margin-bottom: 20px;text-wrap: wrap;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2em;><span style="outline: 0px;letter-spacing: 1px;">本项目已开源!</span></p> <p style="margin-top: 20px;margin-bottom: 20px;text-wrap: wrap;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2em;><span style="outline: 0px;color: rgb(0, 0, 0);caret-color: rgb(255, 0, 0);letter-spacing: 1px;font-family: 微软雅黑, sans-serif;">——想复刻<em style="outline: 0px;"><strong style="outline: 0px;"><span style="outline: 0px;font-size: 20px;">?</span></strong></em>想给作者点赞<em style="outline: 0px;"><strong style="outline: 0px;"><span style="outline: 0px;font-size: 20px;">?</span></strong></em></span><span style="outline: 0px;letter-spacing: 1px;caret-color: red;">可</span><em style="outline: 0px;letter-spacing: 1px;caret-color: red;"><strong style="outline: 0px;">复制开源网址 </strong></em><span style="outline: 0px;letter-spacing: 1px;caret-color: red;">前往原文。</span></p> <section data-tools="135编辑器" data-id="135523" style="margin-bottom: 0px;text-wrap: wrap;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);> <section style="margin: 10px auto;outline: 0px;"> <section style="padding: 4px;outline: 0px;border-width: 1px;border-style: dashed;border-color: rgb(165, 165, 165);border-radius: 15px;"> <section style="padding: 15px 10px;outline: 0px;background-color: rgb(242, 242, 242);border-radius: 15px;"> <section data-autoskip="1" style="outline: 0px;line-height: 1.75em;letter-spacing: 1.5px;font-size: 16px;color: rgb(38, 38, 38);background-color: transparent;"> <p style="outline: 0px;text-align: left;"><strong style="outline: 0px;">开源网址:</strong>https://oshwhub.com/course-examples/bot-dog</p> <p style="outline: 0px;text-align: left;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="259" data-backw="548" data-galleryid="" data-imgfileid="100178715" data-ratio="0.47314814814814815" src="/upload/4d45b2c8522b87437d438d93e1c3317e.png" data-type="gif" data-w="1080" style="width: 100%;height: auto;border-radius: 9px;"></p> <p style="margin-top: 15px;outline: 0px;text-align: left;">扫码也能直接进入原文。</p> <section style="outline: 0px;text-align: left;line-height: normal;"> <br> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100178711" data-ratio="1" data-s="300,640" src="/upload/14ee1df47e34e5ec489f980323a0f3c9.png" data-type="png" data-w="400" style="width: 218px;height: 218px;border-radius: 9px;"></p> <p style="text-align: center;"><br></p> <p style="text-align: left;">开发文档:https://wiki.lceda.cn/zh-hans/course-projects/smart-internet/eda-robot/eda-robot-introduce.html</p> <p style="text-align: left;"><br></p> <p style="text-align: center;"><strong>开发文档巨详细,完全手把手教程▼</strong></p> <p style="text-align: left;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100178719" data-ratio="0.4703703703703704" src="/upload/24f52afc2d238f963ef6ac80af1c57e4.png" data-type="gif" data-w="1080" style=""></p> <p style="text-align: center;"><br></p> <p style="text-align: justify;"><strong>扫码也可以查看开发文档。</strong></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100178720" data-ratio="1" data-s="300,640" src="/upload/c63a12d847581f09530295dd74baaa5b.png" data-type="png" data-w="400" style="width: 183px;height: 183px;"></p> <section style="text-align: center;line-height: normal;"> <br> </section> </section> </section> </section> </section> </section> <section data-role="paragraph" style="margin-bottom: 0px;letter-spacing: 0.578px;text-wrap: wrap;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;background-color: rgb(255, 255, 255);> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="324" data-backw="578" data-galleryid="" data-imgfileid="100178721" data-ratio="0.5607476635514018" src="/upload/dbdfeeff67c89a0c9e983a6fbf50889c.png" data-type="gif" data-w="856" style="width: 100%;height: auto;border-radius: 9px;"></p> <section data-mpa-template="t" mpa-from-tpl="t" style="letter-spacing: 0.544px;outline: 0px;"> <section data-mid="" mpa-from-tpl="t" style="outline: 0px;display: flex;flex-direction: column;"> <section data-mid="" mpa-from-tpl="t" style="outline: 0px;align-self: center;"> <section data-mid="" mpa-from-tpl="t" style="outline: 0px;width: 64px;height: 38px;display: flex;justify-content: center;align-items: center;"> <br> </section> <section data-mid="" mpa-from-tpl="t" style="outline: 0px;width: 64px;height: 38px;display: flex;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100178716" data-ratio="0.59375" src="/upload/deba5067e0a33efad5718ef4f2b412dc.png" data-w="128" style="outline: 0px;visibility: visible !important;width: 64px !important;"> </section> </section> </section> </section> <p style="letter-spacing: 0.544px;outline: 0px;"><br></p> </section> <section data-role="paragraph" style="margin-bottom: 0px;text-wrap: wrap;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);> <section style="margin-top: 32px;margin-bottom: 16px;outline: 0px;letter-spacing: 0.578px;"> <img class="rich_pages wxw-img" data-backh="89" data-backw="578" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="89" data-imgfileid="100178718" data-ratio="0.15555555555555556" data-s="300,640" src="/upload/af9e7c0fd1279005c8dbb25fea921b41.png" data-type="png" data-w="1080" style="height: 90px;outline: 0px;border-radius: 9px;width: 578px;visibility: visible !important;"> </section> </section> <p style="margin-bottom: 0px;letter-spacing: 0.578px;text-wrap: wrap;line-height: normal;"><br></p> <p style="line-height: 2em;margin-top: 16px;margin-bottom: 16px;text-align: left;"><span style="letter-spacing: 1px;font-size: 15px;">*本文转载了「立创开源硬件平台」的用户创作,如有侵权,请联系删除</span></p> <section data-tools="135编辑器" data-id="98898" style="white-space: normal;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;margin-bottom: 0px;"> <section style="margin: 10px auto;max-width: 100%;display: flex;justify-content: flex-end;align-items: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;box-sizing: border-box;text-align: center;letter-spacing: 3px;font-size: 14px;color: rgb(234, 245, 251);text-shadow: rgb(0, 102, 255) 1px 1px, rgb(0, 102, 255) 1px -1px, rgb(0, 102, 255) 1px -1px, rgb(0, 102, 255) -1px 1px, rgb(0, 102, 255) -1px -1px, rgb(0, 102, 255) 0px 1.4px, rgb(0, 102, 255) 0px -1.4px, rgb(0, 102, 255) -1.4px 0px, rgb(0, 102, 255) 1.4px 0px, 2px 0px, rgb(143, 171, 176) 0px 3px, rgb(143, 171, 176) 0px 3px, rgb(143, 171, 176) 0px 2px, rgb(143, 171, 176) 0px 2px;overflow-wrap: break-word !important;"> <span style="font-size: 17px;"><strong data-brushtype="text" hm_fix="382:506" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;">在看你就赞赞我!</strong></span> </section> <section style="margin-top: -6px;margin-left: -15px;max-width: 100%;width: 60px;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;width: 60px;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <img class="rich_pages wxw-img" data-imgfileid="100178717" data-ratio="0.8792270531400966" src="/upload/43fecf6d2ad8ac56602b0310aa6415da.png" data-type="gif" data-w="207" data-width="100%" style="vertical-align: inherit;width: 60px;display: block;overflow-wrap: break-word !important;"> </section> </section> </section> </section> <section data-role="title" data-tools="135编辑器" data-id="92876" style="margin-bottom: 0px;white-space: normal;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-width="100%" style="max-width: 100%;width: 578px;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;display: inline-block;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-brushtype="text" fix="281:195" hm="" style="padding: 10px 25px;max-width: 100%;box-sizing: border-box;height: 45px;line-height: 11px;background-image: url(" https: mmbiz.qpic.cn mmbiz_png nxrqbwknsfqwenobrxa9l7pxae7oiqoiaifh7hs4u862f8ub6zwxjtnxetzrxkfsesl4icjwbtdkcviborlia6bhvw 640?wx_fmt="png");background-repeat:" no-repeat;text-align: center;background-size: 100% 100%;font-size: 14px;letter-spacing: 2px;overflow-wrap: break-word !important;> <span style="font-size: 17px;"><strong>点击</strong><span style="font-size: 17px;color: rgb(0, 128, 255);"><strong>阅读原文</strong></span><strong>查看原工程</strong></span> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section class="mp_profile_iframe_wrp" nodeleaf=""> <mp-common-profile class="custom_select_card mp_profile_iframe mp_common_widget" data-pluginname="mpprofile" data-nickname="pyVideoTrans" data-alias="pyvideotrans" data-from="0" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/ibd7vtHfnZiaqtbmwErA54twV1uS1juxpGEaUtjzSoH733hAd10t0IVBFz8Vb2jhr2vYa5HLLoh7fgGlInApiaicyw/0?wx_fmt=png" data-signature="开源项目“视频翻译配音软件VideoTrans”作者公众号。项目开源主页: github.com/jianchang512/pyvideotrans项目官网: pyvideotrans.com" data-id="MzA5MDgyNjgxOA==" data-service_type="1"></mp-common-profile> </section> <p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf="">厌倦了笨重、昂贵的TTS(文本转语音)解决方案吗?可以试试最近火热的 </span><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">Kokoro</span></strong><span leaf="">:一款拥有8200万参数的开放式TTS模型,它以轻巧的架构实现了媲美大型模型的音质,同时拥有更快的速度、更简单的部署方式和更高的成本效益。</span></p> <h2 style="box-sizing: border-box;line-height: 1.5;margin-top: 35px;margin-bottom: 10px;padding: 6px 8px 0px 0px;font-size: 24px;display: inline-block;font-weight: 700;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 6px;margin-right: 2px;box-shadow: rgba(239, 112, 96, 0.2) 6px 3px 0px 0px;font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf=""> Kokoro 的核心优势:</span></h2> <section> <span style="color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;></span> </section> <ul style="box-sizing: border-box;padding-left: 28px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">卓越的音质:</span></strong> <section> <span leaf=""> 即使参数规模较小,Kokoro 也能生成自然流畅、富有表现力的语音。</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">轻量高效:</span></strong> <section> <span leaf=""> 占用资源少,运行速度快,对硬件要求低。</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">易于部署:</span></strong> <section> <span leaf=""> 得益于 Apache 2.0 许可,你可以将 Kokoro 部署到任何地方,从生产环境到个人项目,无需担心版权问题。</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">多语言支持:</span></strong> <section> <span leaf=""> 支持中文、英语、日语、法语、意大利语、葡萄牙语、西班牙语、印地语共 8 种语言的文字合成配音,满足你多样化的需求。</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">完全免费且开源:</span></strong> <section> <span leaf=""> 你可以自由地使用、修改和分发 Kokoro。</span> </section></li> </ul> <h2 style="box-sizing: border-box;line-height: 1.5;margin-top: 35px;margin-bottom: 10px;padding: 6px 8px 0px 0px;font-size: 24px;display: inline-block;font-weight: 700;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 6px;margin-right: 2px;box-shadow: rgba(239, 112, 96, 0.2) 6px 3px 0px 0px;font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf=""> 快速上手:简单易用的工具链</span></h2> <section> <span style="color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;></span> </section> <p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf="">为了更轻松地使用 Kokoro 以及对接 pyVideoTrans视频翻译软件,我们提供了一套开箱即用的工具 </span><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">Kokoro-uiapi</span></strong><span leaf=""> (</span><span leaf="">https://github.com/jianchang512/kokoro-uiapi</span><span leaf=""> )</span></p> <ol style="box-sizing: border-box;padding-left: 28px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">Web UI 界面:</span></strong></p><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><span leaf="">一个简洁直观的 Web UI 界面,让你无需编写代码即可体验 Kokoro 的强大功能。</span></p><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">Web 界面效果:</span></strong></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="300323314" data-ratio="0.4987864077669903" data-s="300,640" src="/upload/3a021b2cd1347e27be915ac189c34fb9.png" data-type="png" data-w="1648" style="height: auto !important;" type="block"> </section> <section style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;" nodeleaf=""></section></li> <ul style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">功能丰富:</span></strong> <section> <span leaf=""> 支持文字转语音、SRT 字幕配音、在线试听和下载语音文件、字幕对齐等功能。</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">操作简单:</span></strong> <section> <span leaf=""> 只需在浏览器中打开指定地址(项目启动后默认地址:</span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">http://127.0.0.1:5066</span></code><span leaf="">),即可开始使用。</span> </section></li> </ul> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">OpenAI SDK 兼容 API:</span></strong></p><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><span leaf="">如果你已经在使用 OpenAI 的 TTS 服务,那么你可以无缝切换到 Kokoro,无需修改大量代码。</span></p><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">请求示例:</span></strong></p><pre style=" box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 1em;overflow: auto; line-height: 1.75;box-shadow: rgba(110, 110, 0.45) 0px 8px;border-radius: 4px;margin: 16px;color: rgb(51, 51, 51);background: rgb(248, 248, 248);> <section style="box-sizing: border-box;display: flex;user-select: none;height: 28px;align-items: center;justify-content: space-between;box-shadow: rgb(136, 136, 136) 0px 4px 5px -6px;margin-bottom: 3px;background-color: rgb(248, 248, 248);"> <p> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"> <path d="M16.924 9.617A1 1 0 0 0 16 9H8a1 1 0 0 0-.707 1.707l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 .217-1.09z" data-name="Down"></path> </svg></p> <p><span style=" box-sizing: border-box;margin-left: 20px;font-size: 12px; opacity: 0.6; "><span leaf="">json</span></span></p> </section><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 12px;word-break: normal;border-radius: 2px;overflow-x: auto;background: rgb(248, 248, 248);color: rgb(51, 51, 51);padding-top: 15px;padding-right: 12px;padding-bottom: 15px;padding-left: 0px !important;margin: 0px;display: block;><span data-line-num="1" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;"><span leaf="">{</span></span></span><br><span data-line-num="2" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;"><span leaf="">"input"</span></span><span style="box-sizing: border-box;"><span leaf="">:</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">"需要配音的文字"</span></span><span style="box-sizing: border-box;"><span leaf="">,</span></span></span><br><span data-line-num="3" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;"><span leaf="">"voice"</span></span><span style="box-sizing: border-box;"><span leaf="">:</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">"配音角色"</span></span><span style="box-sizing: border-box;"><span leaf="">,</span></span></span><br><span data-line-num="4" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;"><span leaf="">"speed"</span></span><span style="box-sizing: border-box;"><span leaf="">:</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: teal;"><span leaf="">1.0</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"><span leaf="">// 语速,默认为 1.0</span></span></span><br><span data-line-num="5" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;"><span leaf="">}</span></span></span><br></code></pre><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">成功响应:</span></strong><span leaf=""> 返回 MP3 音频数据。</span></p><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">OpenAI SDK 使用示例:</span></strong></p><pre style=" box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 1em;overflow: auto; line-height: 1.75;box-shadow: rgba(110, 110, 0.45) 0px 8px;border-radius: 4px;margin: 16px;color: rgb(51, 51, 51);background: rgb(248, 248, 248);> <section style="box-sizing: border-box;display: flex;user-select: none;height: 28px;align-items: center;justify-content: space-between;box-shadow: rgb(136, 136, 136) 0px 4px 5px -6px;margin-bottom: 3px;background-color: rgb(248, 248, 248);"> <p> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"> <path d="M16.924 9.617A1 1 0 0 0 16 9H8a1 1 0 0 0-.707 1.707l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 .217-1.09z" data-name="Down"></path> </svg></p> <p><span style=" box-sizing: border-box;margin-left: 20px;font-size: 12px; opacity: 0.6; "><span leaf="">python</span></span></p> </section><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 12px;word-break: normal;border-radius: 2px;overflow-x: auto;background: rgb(248, 248, 248);color: rgb(51, 51, 51);padding-top: 15px;padding-right: 12px;padding-bottom: 15px;padding-left: 0px !important;margin: 0px;display: block;><span data-line-num="1" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 700;"><span leaf="">from</span></span><span leaf=""> openai </span><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 700;"><span leaf="">import</span></span><span leaf=""> OpenAI</span></span><br><span data-line-num="2" style="box-sizing: border-box;background-color: inherit;"></span><br><span data-line-num="3" style="box-sizing: border-box;background-color: inherit;"><span leaf="">client = OpenAI(</span></span><br><span data-line-num="4" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> api_key=</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'123456'</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"><span leaf=""># 随意填写</span></span></span><br><span data-line-num="5" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> base_url=</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'http://127.0.0.1:5066/v1'</span></span></span><br><span data-line-num="6" style="box-sizing: border-box;background-color: inherit;"><span leaf="">)</span></span><br><br><span data-line-num="8" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 700;"><span leaf="">try</span></span><span leaf="">:</span></span><br><span data-line-num="9" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> response = client.audio.speech.create(</span></span><br><span data-line-num="10" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> model=</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'tts-1'</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"><span leaf=""># 模型名称,随意填写</span></span></span><br><span data-line-num="11" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 134, 179);"><span leaf="">input</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'你好啊,亲爱的朋友们'</span></span><span leaf="">,</span></span><br><span data-line-num="12" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> voice=</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'zf_xiaobei'</span></span><span leaf="">,</span></span><br><span data-line-num="13" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> response_format=</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'mp3'</span></span><span leaf="">,</span></span><br><span data-line-num="14" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> speed=</span><span style="box-sizing: border-box;color: teal;"><span leaf="">1.0</span></span></span><br><span data-line-num="15" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> )</span></span><br><span data-line-num="16" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 700;"><span leaf="">with</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 134, 179);"><span leaf="">open</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'./test_openai.mp3'</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">'wb'</span></span><span leaf="">) </span><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 700;"><span leaf="">as</span></span><span leaf=""> f:</span></span><br><span data-line-num="17" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> f.write(response.content)</span></span><br><span data-line-num="18" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 134, 179);"><span leaf="">print</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">"MP3 file saved successfully to test_openai.mp3"</span></span><span leaf="">)</span></span><br><span data-line-num="19" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 700;"><span leaf="">except</span></span><span leaf=""> Exception </span><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 700;"><span leaf="">as</span></span><span leaf=""> e:</span></span><br><span data-line-num="20" style="box-sizing: border-box;background-color: inherit;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 134, 179);"><span leaf="">print</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(221, 17, 68);"><span leaf="">f"An error occurred: </span><span style="box-sizing: border-box;color: rgb(51, 51, 51);font-weight: 400;"><span leaf="">{e}</span></span><span leaf="">"</span></span><span leaf="">)</span></span><br></code></pre></li> <ul style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">API 地址:</span></strong> <section> <span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">http://127.0.0.1:5066/v1/audio/speech</span></code><span leaf=""> (项目启动后默认地址)</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">请求方法:</span></strong> <section> <span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">POST</span></code> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">请求数据类型:</span></strong> <section> <span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">application/json</span></code> </section></li> </ul> <ul style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">接口兼容:</span></strong> <section> <span leaf=""> API 接口与 OpenAI TTS 接口高度兼容,只需修改 </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">base_url</span></code><span leaf=""> 即可。</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">使用方便:</span></strong> <section> <span leaf=""> 你可以像使用 OpenAI SDK 一样使用 Kokoro 的 API。</span> </section></li> </ul> </ol> <h2 style="box-sizing: border-box;line-height: 1.5;margin-top: 35px;margin-bottom: 10px;padding: 6px 8px 0px 0px;font-size: 24px;display: inline-block;font-weight: 700;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 6px;margin-right: 2px;box-shadow: rgba(239, 112, 96, 0.2) 6px 3px 0px 0px;font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf=""> 安装指南:</span></h2> <section> <span style="color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;></span> </section> <p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf="">你可以根据自己的需求选择不同的安装方式。</span></p> <ol style="box-sizing: border-box;padding-left: 28px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">Windows 整合包:</span></strong></p></li> <ul style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">下载地址:</span></strong> <section> <span leaf=""> </span><span leaf="">https://github.com/jianchang512/kokoro-uiapi/releases</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">安装步骤:</span></strong></li> </ul> <ol style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">下载整合包并解压。</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">双击 </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">start.bat</span></code><span leaf=""> 启动服务。</span> </section></li> </ol> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">Linux/MacOS 源码部署:</span></strong></p></li> <ul style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">已安装 Python 3.8+ (建议 3.10 - 3.11)</span> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">已安装 ffmpeg (Linux: </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">apt install ffmpeg</span></code><span leaf=""> 或 </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">yum install ffmpeg</span></code><span leaf="">; MacOS: </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">brew install ffmpeg</span></code><span leaf="">)</span> </section></li> </ul> <ul style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">前提条件:</span></strong></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">安装步骤:</span></strong></li> </ul> <ol style="box-sizing: border-box;padding-left: 28px;margin-top: 3px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">拉取源码: </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">git clone https://github.com/jianchang512/kokoro-uiapi</span></code> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">创建并激活虚拟环境:</span> <pre style=" box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 1em;overflow: auto; line-height: 1.75;box-shadow: rgba(110, 110, 0.45) 0px 8px;border-radius: 4px;margin: 16px;color: rgb(51, 51, 51);background: rgb(248, 248, 248);> <section style="box-sizing: border-box;display: flex;user-select: none;height: 28px;align-items: center;justify-content: space-between;box-shadow: rgb(136, 136, 136) 0px 4px 5px -6px;margin-bottom: 3px;background-color: rgb(248, 248, 248);"> <p> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"> <path d="M16.924 9.617A1 1 0 0 0 16 9H8a1 1 0 0 0-.707 1.707l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 .217-1.09z" data-name="Down"></path> </svg></p> <p><span style=" box-sizing: border-box;margin-left: 20px;font-size: 12px; opacity: 0.6; "><span leaf="">bash</span></span></p> </section><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 12px;word-break: normal;border-radius: 2px;overflow-x: auto;background: rgb(248, 248, 248);color: rgb(51, 51, 51);padding-top: 15px;padding-right: 12px;padding-bottom: 15px;padding-left: 0px !important;margin: 0px;display: block;><span data-line-num="1" style="box-sizing: border-box;background-color: inherit;"><span style="box-sizing: border-box;color: rgb(0, 134, 179);"><span leaf="">cd</span></span><span leaf=""> kokoro-uiapi</span></span><br><span data-line-num="2" style="box-sizing: border-box;background-color: inherit;"><span leaf="">python3 -m venv venv</span></span><br><span data-line-num="3" style="box-sizing: border-box;background-color: inherit;"><span leaf="">. venv/bin/activate</span></span><br></code></pre> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">安装依赖: </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">pip3 install -r requirements.txt</span></code> </section></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;padding-left: 6px;"> <section> <span leaf="">启动服务: </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">python3 app.py</span></code> </section></li> </ol> </ol> <h2 style="box-sizing: border-box;line-height: 1.5;margin-top: 35px;margin-bottom: 10px;padding: 6px 8px 0px 0px;font-size: 24px;display: inline-block;font-weight: 700;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 6px;margin-right: 2px;box-shadow: rgba(239, 112, 96, 0.2) 6px 3px 0px 0px;font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf=""> 丰富的角色选择:</span></h2> <section> <span style="color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;></span> </section> <p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf="">Kokoro 提供了多种不同风格的配音角色,满足你不同的应用场景。</span></p> <ul style="box-sizing: border-box;padding-left: 28px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">英语配音角色:</span></strong></p><pre style=" box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 1em;overflow: auto; line-height: 1.75;box-shadow: rgba(110, 110, 0.45) 0px 8px;border-radius: 4px;margin: 16px;color: rgb(51, 51, 51);background: rgb(248, 248, 248);> <section style="box-sizing: border-box;display: flex;user-select: none;height: 28px;align-items: center;justify-content: space-between;box-shadow: rgb(136, 136, 136) 0px 4px 5px -6px;margin-bottom: 3px;background-color: rgb(253, 253, 253);"> <p> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"> <path d="M16.924 9.617A1 1 0 0 0 16 9H8a1 1 0 0 0-.707 1.707l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 .217-1.09z" data-name="Down"></path> </svg></p> <p><span style=" box-sizing: border-box;margin-left: 20px;font-size: 12px; opacity: 0.6; "></span></p> </section><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 12px;word-break: normal;border-radius: 2px;overflow-x: auto;background: rgb(253, 253, 253);color: rgb(51, 51, 51);padding-top: 15px;padding-right: 12px;padding-bottom: 15px;padding-left: 0px !important;margin: 0px;display: block;><span data-line-num="1" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_alloy</span></span><br><span data-line-num="2" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_aoede</span></span><br><span data-line-num="3" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_bella</span></span><br><span data-line-num="4" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_jessica</span></span><br><span data-line-num="5" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_kore</span></span><br><span data-line-num="6" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_nicole</span></span><br><span data-line-num="7" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_nova</span></span><br><span data-line-num="8" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_river</span></span><br><span data-line-num="9" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_sarah</span></span><br><span data-line-num="10" style="box-sizing: border-box;background-color: inherit;"><span leaf="">af_sky</span></span><br><span data-line-num="11" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_adam</span></span><br><span data-line-num="12" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_echo</span></span><br><span data-line-num="13" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_eric</span></span><br><span data-line-num="14" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_fenrir</span></span><br><span data-line-num="15" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_liam</span></span><br><span data-line-num="16" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_michael</span></span><br><span data-line-num="17" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_onyx</span></span><br><span data-line-num="18" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_puck</span></span><br><span data-line-num="19" style="box-sizing: border-box;background-color: inherit;"><span leaf="">am_santa</span></span><br><span data-line-num="20" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bf_alice</span></span><br><span data-line-num="21" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bf_emma</span></span><br><span data-line-num="22" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bf_isabella</span></span><br><span data-line-num="23" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bf_lily</span></span><br><span data-line-num="24" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bm_daniel</span></span><br><span data-line-num="25" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bm_fable</span></span><br><span data-line-num="26" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bm_george</span></span><br><span data-line-num="27" style="box-sizing: border-box;background-color: inherit;"><span leaf="">bm_lewis</span></span><br></code></pre></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">中文角色:</span></strong></p><pre style=" box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 1em;overflow: auto; line-height: 1.75;box-shadow: rgba(110, 110, 0.45) 0px 8px;border-radius: 4px;margin: 16px;color: rgb(51, 51, 51);background: rgb(248, 248, 248);> <section style="box-sizing: border-box;display: flex;user-select: none;height: 28px;align-items: center;justify-content: space-between;box-shadow: rgb(136, 136, 136) 0px 4px 5px -6px;margin-bottom: 3px;background-color: rgb(253, 253, 253);"> <p> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"> <path d="M16.924 9.617A1 1 0 0 0 16 9H8a1 1 0 0 0-.707 1.707l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 .217-1.09z" data-name="Down"></path> </svg></p> <p><span style=" box-sizing: border-box;margin-left: 20px;font-size: 12px; opacity: 0.6; "></span></p> </section><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 12px;word-break: normal;border-radius: 2px;overflow-x: auto;background: rgb(253, 253, 253);color: rgb(51, 51, 51);padding-top: 15px;padding-right: 12px;padding-bottom: 15px;padding-left: 0px !important;margin: 0px;display: block;><span data-line-num="1" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zf_xiaobei</span></span><br><span data-line-num="2" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zf_xiaoni</span></span><br><span data-line-num="3" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zf_xiaoxiao</span></span><br><span data-line-num="4" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zf_xiaoyi</span></span><br><span data-line-num="5" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zm_yunjian</span></span><br><span data-line-num="6" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zm_yunxi</span></span><br><span data-line-num="7" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zm_yunxia</span></span><br><span data-line-num="8" style="box-sizing: border-box;background-color: inherit;"><span leaf="">zm_yunyang</span></span><br></code></pre></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">日语角色:</span></strong></p><pre style=" box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 1em;overflow: auto; line-height: 1.75;box-shadow: rgba(110, 110, 0.45) 0px 8px;border-radius: 4px;margin: 16px;color: rgb(51, 51, 51);background: rgb(248, 248, 248);> <section style="box-sizing: border-box;display: flex;user-select: none;height: 28px;align-items: center;justify-content: space-between;box-shadow: rgb(136, 136, 136) 0px 4px 5px -6px;margin-bottom: 3px;background-color: rgb(253, 253, 253);"> <p> <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"> <path d="M16.924 9.617A1 1 0 0 0 16 9H8a1 1 0 0 0-.707 1.707l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 .217-1.09z" data-name="Down"></path> </svg></p> <p><span style=" box-sizing: border-box;margin-left: 20px;font-size: 12px; opacity: 0.6; "></span></p> </section><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 12px;word-break: normal;border-radius: 2px;overflow-x: auto;background: rgb(253, 253, 253);color: rgb(51, 51, 51);padding-top: 15px;padding-right: 12px;padding-bottom: 15px;padding-left: 0px !important;margin: 0px;display: block;><span data-line-num="1" style="box-sizing: border-box;background-color: inherit;"><span leaf="">jf_alpha</span></span><br><span data-line-num="2" style="box-sizing: border-box;background-color: inherit;"><span leaf="">jf_gongitsune</span></span><br><span data-line-num="3" style="box-sizing: border-box;background-color: inherit;"><span leaf="">jf_nezumi</span></span><br><span data-line-num="4" style="box-sizing: border-box;background-color: inherit;"><span leaf="">jf_tebukuro</span></span><br><span data-line-num="5" style="box-sizing: border-box;background-color: inherit;"><span leaf="">jm_kumo</span></span><br></code></pre></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">法语角色:</span></strong><span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">ff_siwis</span></code></p></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">意大利语角色:</span></strong><span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">if_sara, im_nicola</span></code></p></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">印地语角色:</span></strong><span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">hf_alpha, hf_beta, hm_omega, hm_psi</span></code></p></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">西班牙语角色:</span></strong><span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">ef_dora, em_alex, em_santa</span></code></p></li> <li style="box-sizing: border-box;margin-bottom: 0px;list-style: inherit;"><p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><strong style="box-sizing: border-box;font-weight: bolder;"><span leaf="">葡萄牙语角色:</span></strong><span leaf=""> </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">pf_dora, pm_alex, pm_santa</span></code></p></li> </ul> <h2 style="box-sizing: border-box;line-height: 1.5;margin-top: 35px;margin-bottom: 10px;padding: 6px 8px 0px 0px;font-size: 24px;display: inline-block;font-weight: 700;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 6px;margin-right: 2px;box-shadow: rgba(239, 112, 96, 0.2) 6px 3px 0px 0px;font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf=""> 网络代理 (VPN) 说明</span></h2> <section> <span style="color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;></span> </section> <p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;><span leaf="">源码部署方式需要从 Hugging Face 下载模型文件,如果你的网络无法直接访问 Hugging Face,你需要配置全局代理或系统代理。你也可以提前下载好模型文件,并将其解压到 </span><code style="box-sizing: border-box;font-family: " jetbranins mono, monaco, consolas, courier new, monospace;font-size: 0.87em;word-break: break-word;border-radius: 2px;overflow-x: auto;background-color: rgba(27, 31, 35, 0.05);color: rgb(255, 80, 44);padding: 0.065em 0.4em;><span leaf="">app.py</span></code><span leaf=""> 所在的目录下。</span></p> <blockquote style="box-sizing: border-box;margin-inline: 0px;border-left: 3px solid rgb(239, 112, 96);background: rgb(255, 249, 249);padding: 1px 20px;margin-top: 20px;color: rgb(51, 51, 51);font-family: -apple-system, BlinkMacSystemFont, " segoe ui, helvetica, arial, sans-serif, apple color emoji, segoe ui emoji;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;> <p style="box-sizing: border-box;line-height: inherit;margin-top: 22px;margin-bottom: 22px;"><span leaf="">模型下载地址 </span><span leaf="">https://github.com/jianchang512/kokoro-uiapi/releases/download/0.1/moxing--jieya--dao--app.py--mulu.7z</span></p> </blockquote> <section> <span leaf=""><br></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">上篇分享了 <a href="https://mp.weixin.qq.com/s?__biz=MjM5NzQxMTAyNw==&mid=2247485191&idx=1&sn=6590bae7fb960a2577c2b77c11479080&scene=21#wechat_redirect" textvalue="国产AI之光!DeepSeek本地部署教程,效果媲美GPT-4" data-itemshowtype="0" target="_blank" linktype="text" data-linktype="2">国产AI之光!DeepSeek本地部署教程,效果媲美GPT-4</a>,今天分享下deepseek +本地知识库的部署。</span></p> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">先画个数据流程流程。</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001569" data-ratio="0.7407407407407407" data-s="300,640" src="/upload/b9d2cbe838e5042ebfc5aa53248ab207.png" data-type="png" data-w="1080" type="block"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">基于Cherry Studio搭建(首选)</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">基于本地的deepseek搭建个人知识库。 使用本地服务,安装嵌入模型,用于将文本数据转换为向量标识的模型。</span></p> <pre data-tool="markdown.com.cn编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span leaf="">#命令行窗口执行拉取下即可。</span><span leaf=""><br></span><span leaf="">ollama pull bge-m3</span><span leaf=""><br></span><span leaf="">pulling manifest</span><span leaf=""><br></span><span leaf="">pulling daec91ffb5dd... 100% ▕████████████████████████████████████████████████████████▏ 1.2 GB</span><span leaf=""><br></span><span leaf="">pulling a406579cd136... 100% ▕████████████████████████████████████████████████████████▏ 1.1 KB</span><span leaf=""><br></span><span leaf="">pulling 0c4c9c2a325f... 100% ▕████████████████████████████████████████████████████████▏ 337 B</span><span leaf=""><br></span><span leaf="">verifying sha256 digest</span><span leaf=""><br></span><span leaf="">writing manifest</span><span leaf=""><br></span><span leaf="">success</span><span leaf=""><br></span></code></pre> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">下载cherry studio</span></h3> <section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="" data-pm-slice="1 1 [" para,{tagname:section,attributes:{id:nice,data-tool:markdown编辑器,data-website:https: markdown.com.cn editor,style:font-size: 16px; color: black; padding: 25px 30px; line-height: 1.6; word-spacing: 0px; letter-spacing: word-break: break-word; word-wrap: text-align: justify; font-family: optima-regular, optima, pingfangsc-light, pingfangtc-light, 'pingfang sc', cambria, cochin, georgia, times, 'times new roman', serif; margin-top: -10px;},namespaceuri:http: www.w3.org 1999 xhtml},para,{tagname:p,attributes:{data-tool:markdown.com.cn编辑器,style:font-size: padding-top: 8px; padding-bottom: margin: 0; 26px; black;},namespaceuri:http: xhtml}]>根据自己的环境下载cherry studio</span></p> </section> <section style="text-align: center;" nodeleaf=""> <img src="/upload/033dbd1e2df19c4521a29a8177d497b1.png" class="rich_pages wxw-img" data-ratio="0.43796296296296294" data-s="300,640" data-type="png" data-w="1080" type="block" data-imgfileid="100001546"> </section> <section> <span leaf="">安装的时候,注意安装到其他磁盘,不要在c盘安装。</span> </section> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">本地模型知识库</span><span style="display: none;"></span></h3> <h4 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span><span leaf="">配置本地ollama</span><span style="display: none;"></span></h4> <section style="text-align: center;" nodeleaf=""> <img src="/upload/c1453c4172d09f39c18803bf6292e496.png" class="rich_pages wxw-img" data-ratio="0.7157407407407408" data-s="300,640" data-type="png" data-w="1080" type="block" data-imgfileid="100001547"> </section> <section style="text-align: center;" nodeleaf=""> <img src="/upload/77940fdcc53c75ff2cf595c01c1e6a4d.png" class="rich_pages wxw-img" data-ratio="0.9148580968280468" data-s="300,640" data-type="png" data-w="599" type="block" data-imgfileid="100001549"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">操作步骤:</span></p> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">找到左下角设置图标</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">选择模型服务</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">选择ollama</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">点击管理</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">点击模型后面的加号(会自动查找到本地安装的模型)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">减号表示已经选择了</span> </section></li> </ol> <h4 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span><span leaf="">知识库配置</span></h4> </section> <section style="text-align: center;" nodeleaf=""> <img src="/upload/739b2e0a646ac3684558bdf4c50dc6a5.png" class="rich_pages wxw-img" data-ratio="0.6708074534161491" data-s="300,640" data-type="png" data-w="805" type="block" data-imgfileid="100001550"> </section> <section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">选择<span textstyle="" style="font-weight: bold;">知识库</span></span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">选择<span textstyle="" style="font-weight: normal;">添加</span></span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">选择<span textstyle="" style="font-weight: normal;">嵌入模型</span></span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">填写知识库名称</span> </section></li> </ol> <h4 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span><span leaf="">添加知识文档</span><span style="display: none;"></span></h4> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">cherry可以添加文档,也可以<span textstyle="" style="font-weight: bold;">添加目录(这个极其方便)</span>,添加完以后出现绿色的对号,表示向量化完成。</span></p> <section style="text-align: center;" nodeleaf=""> <img src="/upload/2d8ad53d167c0eedf873216171ace6ed.png" class="rich_pages wxw-img" data-ratio="0.7080436941410129" data-s="300,640" data-type="png" data-w="1007" type="block" data-imgfileid="100001551"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <h4 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span><span leaf="">搜索验证</span></h4> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001552" data-ratio="0.785982478097622" data-s="300,640" src="/upload/7044d4a9495460484758840f9727df5d.png" data-type="png" data-w="799" type="block"> </section> <section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">点击搜索知识库</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">输入搜索顺序</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">点击搜索 大家可以看下我搜索的内容和并没有完全匹配,不过已经和意境关联上了。</span> </section></li> </ol> <h4 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span><span leaf="">大模型处理</span></h4> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001555" data-ratio="0.7201492537313433" data-s="300,640" src="/upload/71182a27da7e148826d3387b5ea9477c.png" data-type="png" data-w="1072" type="block"> </section> </section> <section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">点击左上角的聊天图标</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">点击助手</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">点击默认助手(你也可以添加助手)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">选择大模型</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">选择本地deepseek,也可以选择自己已经开通的在线服务</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">设置知识库(不设置不会参考)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">输入提问内容</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">发问</span><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100001558" data-ratio="0.7180205415499533" data-s="300,640" src="/upload/bb6a2882af2da691c57cc0d55cf052ae.png" data-type="png" data-w="1071" style="text-align: center;color: black;letter-spacing: 0px;background-color: transparent;" type="block"></span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf=""><br></span> </section></li> </ol> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">大家可以看到deepseek已经把结果整理了,并告诉了我们参考了哪些资料。</span></p> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">满血版</span><span style="display: none;"></span></h3> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">差别就是大模型的选择,在模型服务里配置下在线的deepseek服务即可。</span></p> <blockquote style="display: block;font-size: 0.9em;overflow: auto;overflow-scrolling: touch;border-left: 3px solid rgba(0, 0, 0, 0.4);color: #6a737d;padding-top: 10px;padding-bottom: 10px;padding-left: 20px;padding-right: 10px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(239, 112, 96);background: #fff9f9;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;"><span leaf="">如果你的知识库有隐私数据,不要联网!不要联网!不要联网!</span></p> </blockquote> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">方案二 基于AnythingLLM搭建</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">下载AnythingLLM Desktop</span></h3> <section style="text-align: center;" nodeleaf=""> <img src="/upload/d55f19487bf88a253d666a874882e755.png" class="rich_pages wxw-img" data-ratio="0.5981481481481481" data-s="300,640" data-type="png" data-w="1080" type="block" data-imgfileid="100001557"> </section> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span></h3> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">下载以后,安装的时候,注意安装到其他磁盘,不要在c盘安装。</span></p> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">AnythingLLM 配置</span></h3> </section> <section style="text-align: center;" nodeleaf=""> <img src="/upload/21a0f2f8ae31d6747e9ed233778b8ef5.png" class="rich_pages wxw-img" data-ratio="0.9686221009549796" data-s="300,640" data-type="png" data-w="733" type="block" data-imgfileid="100001559"> </section> <section> <span leaf="">点击左下角的设置</span> </section> <section style="text-align: center;" nodeleaf=""> <img src="/upload/26043630b88a5e6fb313d8750f9473a0.png" class="rich_pages wxw-img" data-ratio="0.6039325842696629" data-s="300,640" data-type="png" data-w="1068" type="block" data-imgfileid="100001560"> </section> <section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">1. 点击 LLM首选项</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">2. 选择ollama作为模型提供商</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">3. 选择已安装的deepsek 模型</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">4. 注意下地址</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">5. 保存</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf=""><img src="/upload/44ae3d3719ca095adb8c3192bc5bdf1e.png" class="rich_pages wxw-img" data-ratio="0.37900874635568516" data-s="300,640" data-type="png" data-w="1029" type="block" data-imgfileid="100001561"></span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">1. 向量数据库不用动即可,使用自带的(ps:如果没有选择安装目录,默认在c盘,如果后续有需要可以挪走)</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">2. 嵌入模型配置</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">3. 可以使用自带的,也可以使用ollama安装好的</span> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">4. 配置完点击左下角的返回即可</span> </section> <section style="margin-top:5px;margin-bottom:5px;line-height:26px;text-align:left;color:rgb(1,1,1);font-weight:500;"> <span leaf=""><br></span> </section> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">配置工作区</span><span style="display: none;"></span></h3> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><img src="/upload/eb3299d98a074d5aadab4af3b44381c8.png" class="rich_pages wxw-img" data-ratio="0.9086859688195991" data-type="png" data-w="449" data-imgfileid="100001562"></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001563" data-ratio="0.6112920738327905" data-s="300,640" src="/upload/9c4e0dc044d3e3539e14ce33a4d8405a.png" data-type="png" data-w="921" type="block"> </section> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">新建的工作区</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">默认会话</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">上传知识库文档</span> </section></li> </ol> <section style="text-align: center;" nodeleaf=""> <img src="/upload/f4a0f93ddc4fbd08f10d57324c7bea8a.png" class="rich_pages wxw-img" data-ratio="0.49722222222222223" data-s="300,640" data-type="png" data-w="1080" type="block" data-imgfileid="100001564"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">将文档拖拽到上传框。ps: 只需要拖拽一次就行了,它在聊天框能看到。不知道为什么,我这拖拽以后,没看到上传成功,然后又拖拽了几次。然后聊天框就好多份。</span></p> <section style="text-align: center;" nodeleaf=""> <img src="/upload/f4a0f93ddc4fbd08f10d57324c7bea8a.png" class="rich_pages wxw-img" data-ratio="0.49722222222222223" data-s="300,640" data-type="png" data-w="1080" type="block" data-imgfileid="100001565"> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001566" data-ratio="0.473792394655704" data-s="300,640" src="/upload/7594d3f06f66d60294d1fa4545b9d0c6.png" data-type="png" data-w="973" type="block"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">当然你可以配置远程文档,confluence、github都可以。</span></p> <section style="text-align: center;" nodeleaf=""> <img src="/upload/e1dd2ec2e23958fe3122963a64443be3.png" class="rich_pages wxw-img" data-ratio="0.6012903225806452" data-s="300,640" data-type="png" data-w="775" type="block" data-imgfileid="100001567"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">ps: 需要注意的是文档在工作区间内是共用的。</span></p> <h4 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span><span leaf="">api功能</span><span style="display: none;"></span></h4> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">AnythingLLM 可以提供api访问的功能,这个可以作为公共知识库使用。</span></p> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001568" data-ratio="0.5374753451676528" data-s="300,640" src="/upload/e3933f8ed83b3f7c1eeb0eb49b56aa24.png" data-type="png" data-w="1014" type="block"> </section> <section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">总结</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">整个操作下来,AnythingLLM 的体验没有cherry好。AnythingLLM就像一个包壳的web应用(后来查了下,确实是)。AnythingLLM 得具备一定的程序思维,给技术人员用的。非技术人员还是使用cherry吧。作为喜欢折腾的开发人员,我们可以结合dify使用。</span></p> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">最后</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">个人知识库+本地大模型的优点</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">隐私性很好,不用担心自己的资料外泄、离线可用</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">在工作和学习过程中对自己整理的文档,能快速找到,并自动关联</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">在代码开发上,能参考你的开发习惯,快速生成代码</span> </section></li> </ul> <section style="margin-top:5px;margin-bottom:5px;line-height:26px;text-align:left;color:rgb(1,1,1);font-weight:500;"> <span leaf=""><br></span> </section> <section style="margin-top:5px;margin-bottom:5px;line-height:26px;text-align:left;color:rgb(1,1,1);font-weight:500;"> <span leaf="">大家感兴趣的可以关注下,后续我再研究点新东西分享给大家。</span> </section> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(10, 10, 10);letter-spacing: normal;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75;font-family: Menlo, Monaco, " courier new, monospace;font-size: 15px;> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);"><span style="letter-spacing: 0.1em;">日常工作中,我们经常需要处理大量文档和资料:</span></p> </section> <section style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(10, 10, 10);letter-spacing: normal;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75;font-family: Menlo, Monaco, " courier new, monospace;font-size: 15px;> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;line-height: 1.75;color: rgb(63, 63, 63);" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 产品文档、技术文档散落在各处,查找费时费力</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 新人入职培训需要反复讲解相同的内容</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 客户咨询的问题高度重复,但每次都要人工回答</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 公司内部知识难以沉淀和复用</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 各类参考资料缺乏统一管理和快速检索的方案</p></li> </ul> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">传统的文档管理系统只能按目录存储和搜索关键词,而商业AI助手又无法导入私有数据。这时,一个能将文档智能化并支持对话的系统就显得尤为重要。AnythingLLM正是为解决这些痛点而生。</p> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);"><img class="rich_pages wxw-img" data-imgfileid="505310517" data-ratio="0.25125" src="/upload/557995b212d65272a542c51b945303e8.png" data-type="png" data-w="800"></p> <h2 style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 19.5px;font-weight: bold;margin: 4em auto 2em;text-align: center;line-height: 1.75;display: table;padding: 0.3em 1em;color: rgb(255, 255, 255);background: rgb(85, 201, 234);border-radius: 8px;box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px;">核心功能详解</h2> <h3 style="border-width: 0px 0px 1px 4px;border-style: solid solid dashed;border-bottom-color: rgb(85, 201, 234);border-left-color: rgb(85, 201, 234);font-size: 18px;font-weight: bold;margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;line-height: 1.2;padding-left: 12px;color: rgb(63, 63, 63);">1. 灵活的文档处理能力</h3> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">AnythingLLM支持处理多种类型的文档和内容:</p> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;padding-left: 1.5em;line-height: 1.75;color: rgb(63, 63, 63);" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">多格式支持</strong>:可以导入PDF、Word、TXT等常见文档格式</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">网页抓取</strong>:直接输入URL即可抓取网页内容</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">智能分割</strong>:自动将长文档分割成适合向量化的片段</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">元数据提取</strong>:自动提取文档的标题、作者等信息</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">增量更新</strong>:支持文档的增量更新,无需重新处理全部内容</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">大规模处理</strong>:能高效处理GB级别的文档集合</p></li> </ul> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">这种灵活的文档处理能力让你可以轻松将各类知识资料导入系统,构建起完整的知识库。</p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="505310516" data-ratio="0.5625" src="/upload/2d1fd0673b143e8d75dc06512aeac58a.png" data-type="gif" data-w="800" style=""></p> <h3 style="border-width: 0px 0px 1px 4px;border-style: solid solid dashed;border-bottom-color: rgb(85, 201, 234);border-left-color: rgb(85, 201, 234);font-size: 18px;font-weight: bold;margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;line-height: 1.2;padding-left: 12px;color: rgb(63, 63, 63);">2. 工作区(Workspace)管理</h3> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">工作区是AnythingLLM的核心概念,它提供了一种组织和隔离内容的方式:</p> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;padding-left: 1.5em;line-height: 1.75;color: rgb(63, 63, 63);" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">独立上下文</strong>:每个工作区都有独立的上下文环境,不会互相干扰</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">文档共享</strong>:允许多个工作区共享同一份文档,避免重复导入</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">权限控制</strong>:可以为不同用户设置不同的工作区访问权限</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">场景隔离</strong>:可以按业务场景、部门或项目创建专属工作区</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">灵活组织</strong>:支持工作区的创建、删除、重命名等管理操作</p></li> </ul> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">通过工作区,你可以将知识有序地组织起来,便于团队协作和知识沉淀。</p> <h3 style="border-width: 0px 0px 1px 4px;border-style: solid solid dashed;border-bottom-color: rgb(85, 201, 234);border-left-color: rgb(85, 201, 234);font-size: 18px;font-weight: bold;margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;line-height: 1.2;padding-left: 12px;color: rgb(63, 63, 63);">3. 强大的对话能力</h3> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">AnythingLLM提供了两种对话模式,满足不同场景的需求:</p> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;padding-left: 1.5em;line-height: 1.75;color: rgb(63, 63, 63);" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">聊天模式</strong>:</p></li> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;padding-left: 1.5em;line-height: 1.75;" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 保留对话历史,支持多轮交互</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 理解上下文,回答更连贯自然</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 可以追问和澄清问题</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 适合深入探讨和学习</p></li> </ul> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">查询模式</strong>:</p></li> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;padding-left: 1.5em;line-height: 1.75;" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 针对具体问题快速给出答案</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 直接定位相关文档片段</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 响应速度更快</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 适合查找特定信息</p></li> </ul> </ul> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">每次回答都会标注信息来源,方便进一步查证和学习。</p> <h3 style="border-width: 0px 0px 1px 4px;border-style: solid solid dashed;border-bottom-color: rgb(85, 201, 234);border-left-color: rgb(85, 201, 234);font-size: 18px;font-weight: bold;margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;line-height: 1.2;padding-left: 12px;color: rgb(63, 63, 63);">4. 模型与数据库选择</h3> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">AnythingLLM支持多种主流的语言模型和向量数据库:</p> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;padding-left: 1.5em;line-height: 1.75;color: rgb(63, 63, 63);" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">语言模型</strong>:</p></li> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;padding-left: 1.5em;line-height: 1.75;" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 商业模型:OpenAI、Anthropic、Google等</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 开源模型:支持任何llama.cpp兼容的模型</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 本地部署:可使用LocalAI、Ollama等方案</p></li> </ul> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• <strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">向量数据库</strong>:</p></li> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;padding-left: 1.5em;line-height: 1.75;" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 默认使用轻量级的LanceDB</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 支持Pinecone、Weaviate等主流方案</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 可根据规模和需求选择合适的方案</p></li> </ul> </ul> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">这种灵活性让你可以根据预算和性能需求选择最适合的组合。</p> <h2 style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 19.5px;font-weight: bold;margin: 4em auto 2em;text-align: center;line-height: 1.75;display: table;padding: 0.3em 1em;color: rgb(255, 255, 255);background: rgb(85, 201, 234);border-radius: 8px;box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px;">安装与实战</h2> <h3 style="border-width: 0px 0px 1px 4px;border-style: solid solid dashed;border-bottom-color: rgb(85, 201, 234);border-left-color: rgb(85, 201, 234);font-size: 18px;font-weight: bold;margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;line-height: 1.2;padding-left: 12px;color: rgb(63, 63, 63);">下载AnythingLLM桌面版</h3> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="505310518" data-ratio="0.600925925925926" data-s="300,640" src="/upload/ccfae560c2583360be0485cddabf4441.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;">为了方便大家下载,我专门将所有应用下载到网盘,进入即可保存或者下载</p> <p><span style="color: rgb(61, 170, 214);">https://pan.quark.cn/s/d5f8ce6fc915</span></p> <h3 style="border-width: 0px 0px 1px 4px;border-style: solid solid dashed;border-bottom-color: rgb(85, 201, 234);border-left-color: rgb(85, 201, 234);font-size: 18px;font-weight: bold;margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;line-height: 1.2;padding-left: 12px;color: rgb(63, 63, 63);">AnythingLLM + DeepSeek实战</h3> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">安装之后搜索DeepSeek</p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="505310519" data-ratio="0.6324074074074074" data-s="300,640" src="/upload/679224b1888f3d9f2d706725ea249293.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;">获取DeepSeek-V3的Token,DeepSeek与其他模型对比图。</p> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);"><img class="rich_pages wxw-img" data-imgfileid="505310522" data-ratio="0.7842592592592592" src="/upload/8feae7d18484cec0a9ef570374bb1df9.jpg" data-type="jpeg" data-w="1080"></p> <h2 style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 19.5px;font-weight: bold;margin: 4em auto 2em;text-align: center;line-height: 1.75;display: table;padding: 0.3em 1em;color: rgb(255, 255, 255);background: rgb(85, 201, 234);border-radius: 8px;box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px;">写在最后</h2> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">AnythingLLM为知识管理和智能问答提供了一个开源的整体解决方案。它不仅能帮助个人和团队更好地管理和利用知识资产,还能大幅提升工作效率。虽然部署和配置需要一定技术基础,但投入的时间和精力是值得的。</p> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);">经过一段时间的使用,你会发现它能极大地改善团队的知识管理和信息获取效率。特别是对于需要经常查阅大量文档的团队来说,AnythingLLM可以成为一个强大的助手。</p> <p style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;letter-spacing: 0.1em;color: rgb(63, 63, 63);"><strong style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-size: inherit;color: rgb(85, 201, 234);">相关链接:</strong></p> <ul style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;padding-left: 1.5em;line-height: 1.75;color: rgb(63, 63, 63);" class="list-paddingleft-1"> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 开源项目地址:https://github.com/Mintplex-Labs/anything-llm</p></li> <li style="border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;text-indent: -1em;display: block;margin: 0.5em 8px;"><p>• 文档:https://docs.anythingllm.com/</p></li> </ul> </section>
作者:微信小助手
<p> 本机号码一键登录<span style="letter-spacing: 0.578px;">是一种</span><span style="letter-spacing: 0.578px;">新型</span><span style="letter-spacing: 0.578px;">的登录方式</span>,登录方式的演变过程大致可以分几个阶段:</p> <p style="text-align: left;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001847" data-ratio="0.233387358184765" data-s="300,640" src="/upload/627ed5ac7185c86487d81926e788e29c.png" data-type="png" data-w="617" style=""></p> <p> 一键登录从用户体验和安全性上来讲是更优的一种登录方式,目前在很多APP的目前都支持“本机号码一键登录”功能,如下图所示的一键登录图:</p> <p style="text-align: left;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001845" data-ratio="0.9772079772079773" data-s="300,640" src="/upload/7d17f84c26a1743e6808a24c1918058c.png" data-type="png" data-w="351" style="width: 290px;height: 283px;"></p> <p><span style="letter-spacing: 0.578px;"> APP中会展示一个带有手机号掩码(中间4位号码隐藏了)的授权登录页面,用户点击“同意授权”按钮后,应用APP通过运营商获取完整的手机号码(因为为了保护用户隐私,Android和IOS系统限制了应用直接获取本机号码的能力),然后有了<span style="letter-spacing: 0.578px;">完整的手机号码后可以</span>实现以本机号码的方式登录。那么本机号码一键登录是如何实现的呢?下面我们来聊聊它的实现原理和流程。</span></p> <p><strong><span style="letter-spacing: 0.578px;">1、本机号码一键登录的基础原理</span></strong><span style="letter-spacing: 0.578px;"></span></p> <p><span style="letter-spacing: 0.578px;"> 手机流量上网原理是实现一键登录的关键。流量上网采用PPP协议进行点对点连接。在物理层,流量通过手机内置的基带模块进行无线信号的调制、解调工作。</span></p> <p><span style="letter-spacing: 0.578px;"> 流量上网过程分为接入和传输两个阶段,接入阶段中手机携带IMSI信息连接MME(移动控制单元),MME通过HSS(归属签约用户服务器)验证后,进行初始化并提供加密传输支持。传输阶段中数据包经过基站、S-GW(服务网关)、P-GW(PDN网关)到达互联网资源,同时运营商能够通过IMSI或GUTI获取当前用户的手机号码。</span></p> <p><span style="letter-spacing: 0.578px;"> 获取手机号码的能力通过数据网关实现,运营商具备验证连接用户身份的能力,手机卡中的IMSI信息在运营商数据库中记录,确保基站能够验证用户身份。</span></p> <p><strong><span style="letter-spacing: 0.578px;">2、APP中<span style="letter-spacing: 0.578px;">本机号码一键登录的实现流程</span></span></strong><span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;"></span></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001850" data-ratio="0.8053691275167785" data-s="300,640" src="/upload/5bac2325816ebbb3d5af25df2726e720.png" data-type="png" data-w="894" style=""></p> <p>(1)获取手机掩码并唤起授权页</p> <p> 当用户打开APP需要登录的时候,APP会取运营商那里查询用户的手机号码掩码,运营商验证通过之后将当前的手机号掩码返回给APP并在认证的运营商的认证SDK上缓存手机号的掩码,最后就是展示给用户手机号的掩码,如下图所示的展示的手机号掩码:</p> <p style="text-align: left;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100001849" data-ratio="0.6144578313253012" data-s="300,640" src="/upload/38c2d62934dc23b42ceee235159d2713.png" data-type="png" data-w="249" style=""></p> <p>(2)获取手机号掩码的token</p> <p> 用户点击“本机号码一键登录”按钮之后,APP发送授权请求到运营商服务器上,运营商验证通过之后返回手机号掩码和手机号掩码对应的token给应用APP。</p> <p>(3)获取手机号的应用授权token_a</p> <p> 应用APP携带手机号掩码token发起登录请求到手机APP服务器上,然后<span style="letter-spacing: 0.578px;">手机APP</span><span style="letter-spacing: 0.578px;">服务器上通过携带手机号掩码token、应用id和签名请求运营商服务器。运营商服务器验证通过之后返回完整的手机号码给<span style="letter-spacing: 0.578px;">手机APP</span><span style="letter-spacing: 0.578px;">服务器,然后<span style="letter-spacing: 0.578px;">手机APP</span><span style="letter-spacing: 0.578px;">服务器生成对应的应用授权token_a,并返回<span style="letter-spacing: 0.578px;">应用授权</span><span style="letter-spacing: 0.578px;">token_</span><span style="letter-spacing: 0.578px;">a给APP,<span style="letter-spacing: 0.578px;">APP缓存应用授权<span style="letter-spacing: 0.578px;">token_a并提示登录成功。</span></span></span></span></span></span></p> <p>(4)APP携带应用授权token_a访问服务器:</p> <p> 每当APP请求访问手机APP服务器的时候,客户端都会带着token_a访问服务器,服务端验证token_a同通过后便让请求访问。</p> <p>至此就完成了本机号码一键登录请求的流程。</p> <p>总结:</p> <p>(1)<span style="letter-spacing: 0.578px;">本机号码</span><span style="letter-spacing: 0.578px;">一键登录是</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">实现不用记复杂的密码,不送接收验证码,真正的实现<span style="letter-spacing: 0.578px;">2秒</span>轻松的登录</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">。</span></p> <p><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">(2)<span style="letter-spacing: 0.578px;">本机号码</span><span style="letter-spacing: 0.578px;">一键登录经过<span style="letter-spacing: 0.578px;">获</span><span style="letter-spacing: 0.578px;">取手机掩码、<span style="letter-spacing: 0.578px;">获取</span><span style="letter-spacing: 0.578px;">手机号</span><span style="letter-spacing: 0.578px;">掩码的token、<span style="letter-spacing: 0.578px;">获取手机号的应用授权token_a等几个关键步骤后实现登录流程。</span></span></span></span></span></p> <p><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;"><span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;">(3)三个运营商的都有各自的开放平台(</span></span></span></span></span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">移动 - 互联网能力开放平台、</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">电信-天翼账号开放平台、</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">联通-WO+开放平台</span><span style="letter-spacing: 0.578px;font-size: var(--articleFontsize);">),如果</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">要兼容三大运营商就需要分别接入三个SDK,目前已经有了第三方</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">整合了三大运营商认证能力的第三方SDK(常见的有</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">阿里-号码认证服务、</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">创蓝-闪验、</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">极光-极光认证、</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">mob-秒验</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">)</span><span style="font-size: var(--articleFontsize);letter-spacing: 0.034em;">。</span></p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-bottom: 0px;padding-left: 10px;padding-right: 10px;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;font-family: Optima, PingFangSC-light, serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;word-spacing: 0em;letter-spacing: 0em;word-break: break-word;text-align: left;"> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkzMDI1NjcyOQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/EoJib2tNvVtf7icAmS0BQH6oDVG37Q8NzcfdguS5qAqOhfxvZyIKqmuX5BbnDjynrBbZzktp1EiaeFLzapp1nHysw/0?wx_fmt=png" data-nickname="码哥跳动" data-alias="MageByte" data-signature="《Redis 高手心法》作者,10 年 Java 互联网大厂工作经验,作为后端架构师,喜欢用简介、风趣幽默的语言深入浅出的讲解技术,宗旨是拥抱技术和对象,面向人民币编程。" data-from="0" data-is_biz_ban="0" data-service_type="1"></mp-common-profile> </section> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">大家好,我是码哥,<a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&mid=2247503946&idx=1&sn=5139719b897a3ca8d37b267b9913136e&scene=21#wechat_redirect" textvalue="《Redis 高手心法》" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">《Redis 高手心法》</a>作者。本书获得<span style="color: rgb(0, 0, 0);font-family: PingFangSC-regular, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);">前阿里 P9 级资深技术专家李运华的推荐。</span></p> <section> <mp-common-cpsad class="js_uneditable custom_select_card new_cps_iframe" data-pluginname="mpcps" data-templateid="list" data-traceid="543fe46d-e2f7-4ca2-acc2-961094d5f086" data-goodssouce="1" data-pid="101_14705628" data-appuin="3930256729" data-cpsversion="v120"></mp-common-cpsad> </section> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;"><span style="color: rgb(0, 0, 0);font-family: PingFangSC-regular, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);"></span></p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;text-align: center;"><span style="color: rgb(0, 0, 0);font-family: PingFangSC-regular, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);"><img class="rich_pages wxw-img" data-imgfileid="100021344" data-ratio="0.6592592592592592" src="/upload/34746561a514a21e6cc5f550dc5a5d0f.png" data-w="1080" style="width: 388px;height: 256px;"></span></p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">进入正文......<br></p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">在<a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&mid=2247504969&idx=1&sn=555fc9696295a3f05238b00f1ddeaa0c&scene=21#wechat_redirect" textvalue="《Redis 为什么这么快》" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">《Redis 为什么这么快》</a>这篇文章中,我们已经知道 Redis 使用全局 dict 字典表 + 内存数据库 + 丰富高效的数据结构 + 单线程模型 + I/O 多路复用事件驱动框架使得 Redis 快到飞起。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">Redis 的网络 I/O 以及键值对指令读写是由单个线程来执行的,避免了不必要的上再问切换和资源竞争,对于性能提升有很大的帮助。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">然而,Redis 官方在 2020 年 5 月正式推出 6.0 版本,引入了 I/O 多线程模型。</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“为什么之前是单线程模型?为什么 6.0 引入了 I/O 多线程模型?主要解决了什么问题?”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">今天,咱们就详细的聊下 I/O 多线程模型带来的效果到底是黛玉骑鬼火,该强强,该弱弱;还是犹如光明顶身怀绝技的的张无忌,招招都是必杀技。</p> <h2 data-tool="mdnice编辑器" style="border-color: rgb(248, 57, 41) rgb(0, 0, 0) rgb(0, 0, 0);margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: solid none none;border-width: 2px 1px 1px;border-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: center;line-height: 1.5em;overflow: unset;text-align: center;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(255, 255, 255);background: none 0% 0% / auto no-repeat scroll padding-box border-box rgb(248, 57, 41);line-height: 1.8em;letter-spacing: 0em;align-items: unset;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px 0px 13px 13px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;padding: 3px 5px 5px;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">单线程模型真的只有一个线程么?</span><span style="display: none;"></span></h2> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“码哥, Redis 6.0 之前单线程指的是 Redis 只有一个线程干活么?”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">非也,我们通常说的单线程模型指的是 Redis 在处理客户端的请求时,包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">而其他的清理过期键值对数据、释放无用连接、内存淘汰策略执行、<code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>BGSAVE</code> 生成 RDB 内存快照文件、AOF rewrite 等都是其他线程处理。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">命令执行阶段,每一条命令并不会立马被执行,而是进入一个一个 socket 队列,当 socket 事件就绪则交给事件分发器分发到对应的事件处理器处理,单线程模型的命令处理如下图所示。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100021337" data-ratio="0.4375678610206297" src="/upload/ecec8fa9a0e83cfce80b8b4466c5ea4e.png" data-type="png" data-w="921" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> <figcaption style="color: rgb(136, 136, 136);font-size: 12px;line-height: 1.5em;letter-spacing: 0em;text-align: center;margin-top: 5px;"> 图 4-23 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">图 4-23</p> <h2 data-tool="mdnice编辑器" style="border-color: rgb(248, 57, 41) rgb(0, 0, 0) rgb(0, 0, 0);margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: solid none none;border-width: 2px 1px 1px;border-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: center;line-height: 1.5em;overflow: unset;text-align: center;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(255, 255, 255);background: none 0% 0% / auto no-repeat scroll padding-box border-box rgb(248, 57, 41);line-height: 1.8em;letter-spacing: 0em;align-items: unset;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px 0px 13px 13px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;padding: 3px 5px 5px;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">线程模型的演化</span><span style="display: none;"></span></h2> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“为什么 Redis6.0 之前是单线程模型?”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">以下是官方关于为什么 6.0 之前一直使用单线程模型的回答。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> Redis 的性能瓶颈主要在于内存和网络 I/O,CPU 不会是性能瓶颈所在。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> Redis 通过使用 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>pipelining</code> 每秒可以处理 100 万个请求,应用程序的所时候用的大多数命令时间复杂度主要使用 O(N) 或 O(log(N)) 的,它几乎不会占用太多 CPU。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 单线程模型的代码可维护性高。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。 </section></li> </ul> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">Redis 通过基于 I/O 多路复用实现的 AE 事件驱动框架将 I/O 事件和事件事件融合在一起,实现高性能网络处理能力,再加上基于内存的数据处理,没有引入多线程的必要。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">而且<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">单线程机制让 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等线程不安全的命令都可以无锁进行</strong>。</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“既然单线程这么好,为什么 6.0 版本引入多线程模型?”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">因为随着底层网络硬件性能提升,Redis 的性能瓶颈逐渐体现在网络 I/O 的读写上,<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">单个线程处理网络读写的速度跟不上底层网络硬件执行的速度</strong>。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">因为读写网络的 read/write 系统调用占用了 Redis 执行期间大部分 CPU 时间。所以 Redis 采用多个 I/O 线程来处理网络请求,提高网络请求处理的并行度。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;"><strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">需要注意的是,Redis 多 IO 线程模型只用来处理网络读写请求,对于 Redis 的读写命令,依然是单线程处理</strong>。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">这是因为,<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">网络 I/O 读写是瓶颈,可通过多线程并行处理可提高性能。而继续使用单线程执行读写命令,不需要为了保证 Lua 脚本、事务、等开发多线程安全机制,实现更简单。</strong></p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“码哥,你真是斑马的脑袋,说的头头是道。”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">我谢谢您嘞,主线程与 I/O 多线程共同协作处理命令的架构图如下所示。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100021336" data-ratio="0.4181091877496671" src="/upload/3b4f85b8953e62d00aa91605db96602a.png" data-type="png" data-w="751" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> <figcaption style="color: rgb(136, 136, 136);font-size: 12px;line-height: 1.5em;letter-spacing: 0em;text-align: center;margin-top: 5px;"> 图 4-24 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">图 4-24</p> <h2 data-tool="mdnice编辑器" style="border-color: rgb(248, 57, 41) rgb(0, 0, 0) rgb(0, 0, 0);margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: solid none none;border-width: 2px 1px 1px;border-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: center;line-height: 1.5em;overflow: unset;text-align: center;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(255, 255, 255);background: none 0% 0% / auto no-repeat scroll padding-box border-box rgb(248, 57, 41);line-height: 1.8em;letter-spacing: 0em;align-items: unset;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px 0px 13px 13px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;padding: 3px 5px 5px;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">I/O 多线程模型解读</span><span style="display: none;"></span></h2> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“如何开启多线程呢?”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">Redis 6.0 的多线程默认是禁用的,如需开启需要修改 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>redis.conf</code> 配置文件的配置<code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>io-threads-do-reads yes</code>。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">开启多线程后,还要设置线程数才能生效,同样是修改 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>redis.conf</code>配置文件。</p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;margin-top: 10px;margin-bottom: 10px;"><span style="display: block;background: url(" https: mmbiz.qpic.cn mmbiz_svg 7n2jrawoorbcpmv9swrbdjianq0672hfmai5jyljfxzrgiaib3skvibma70icmtmezc6clcwpdfiuuctlxbm1pbiacxiandxedyhuv5 640?wx_fmt="svg&from=appmsg")" 10px 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;">io-threads 4<br></code></pre> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“码老师,线程数是不是越多越好?”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">当然不是,关于线程数的设置,官方有一个建议:线程数的数量最好小于 CPU 核心数,起码预留一个空闲核处理,因为 Redis 是主线程处理指令,如果系统出现频繁上下文切换,效率会降低。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">比如 4 核的机器建议设置为 2 或 3 个线程,8 核的机器建议设置为 6 个线程,线程数一定要小于机器核数。</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“码老师真厉害,就好像卖盆的进村一套一套的。我什么时候也能像你这样连贯又有逻辑的掌握 Redis。”</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">认真读 Redis 高手心法,长线放风筝慢慢来。</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">谢霸哥:“主线程与 I/O 线程是如何实现协作呢?”</p> </blockquote> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100021338" data-ratio="1.5067567567567568" src="/upload/af7785cbc626e6f807f5c2369efdfdec.png" data-type="png" data-w="740" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> <figcaption style="color: rgb(136, 136, 136);font-size: 12px;line-height: 1.5em;letter-spacing: 0em;text-align: center;margin-top: 5px;"> 图 4-25 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">图 4-25</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;"><strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">主要流程</strong>。</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程负责接收建立连接请求,通过轮询将可读 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>socket</code> 分配给 I/O 线程绑定的等待队列。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">阻塞等待</strong>,直到 I/O 线程完成 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>socket</code> 读取和解析。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程执行 I/O 线程读取和解析出来的 Redis 请求命令。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">阻塞等待</strong> I/O 线程将指令执行结果回写回 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>socket</code>完毕。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程清空等待队列,等待下一次客户端后续的请求。 </section></li> </ol> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">思路:<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">将主线程 IO 读写任务拆分出来给一组独立的线程处理,使得多个 socket 读写可以并行化,但是 Redis 命令还是主线程串行执行。</strong></p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">大家注意第三和第五步,主线程并不是挂起线程让出 CPU 分片时间。而是通过 for 循环进行忙等,不断的检测所有 I/O 线程处理任务是否已经完成,完成再执行下一步。</p> <h2 data-tool="mdnice编辑器" style="border-color: rgb(248, 57, 41) rgb(0, 0, 0) rgb(0, 0, 0);margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: solid none none;border-width: 2px 1px 1px;border-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: center;line-height: 1.5em;overflow: unset;text-align: center;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(255, 255, 255);background: none 0% 0% / auto no-repeat scroll padding-box border-box rgb(248, 57, 41);line-height: 1.8em;letter-spacing: 0em;align-items: unset;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px 0px 13px 13px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;padding: 3px 5px 5px;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">源码解析</span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">看完流程图以及主要步骤,接着跟着源码走一个。通过 4.3 章节的学习,我们知道 Redis 是通过 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>server.c</code>的<code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>main</code>函数启动的,经过一系列的初始化操作后,调用 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>aeMain(server.el);</code>启动事件驱动框架,也就是整个 Redis 的核心。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="display: none;"></span><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">初始化线程</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">I/O 多线程模型的开端也是由 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>server.c</code>的<code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>main</code>方法中的 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>InitServerLast</code>来初始化,该方法内部会调用 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>networking.c</code> 的 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>initThreadedIO</code>来执行实际 I/O 线程初始化工作。</p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;margin-top: 10px;margin-bottom: 10px;"><span style="display: block;background: url(" https: mmbiz.qpic.cn mmbiz_svg 7n2jrawoorbcpmv9swrbdjianq0672hfmai5jyljfxzrgiaib3skvibma70icmtmezc6clcwpdfiuuctlxbm1pbiacxiandxedyhuv5 640?wx_fmt="svg&from=appmsg")" 10px 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">/* networking.c */</span><br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">initThreadedIO</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">void</span>)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 设置成 0 表示激活 I/O 多线程模型</span><br> server.io_threads_active = <span style="color: #d19a66;line-height: 26px;">0</span>;<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* I/O 线程处于空闲状态 */</span><br> io_threads_op = IO_THREADS_OP_IDLE;<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 如果 redis.conf 的 io-threads 配置为 1 表示使用单线程模型,直接退出 */</span><br> <span style="color: #c678dd;line-height: 26px;">if</span> (server.io_threads_num == <span style="color: #d19a66;line-height: 26px;">1</span>) <span style="color: #c678dd;line-height: 26px;">return</span>;<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 线程数超过最大值 128,退出程序</span><br> <span style="color: #c678dd;line-height: 26px;">if</span> (server.io_threads_num > IO_THREADS_MAX_NUM) {<br> ....省略<br> <span style="color: #e6c07b;line-height: 26px;">exit</span>(<span style="color: #d19a66;line-height: 26px;">1</span>);<br> }<br><br> <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">int</span> i = <span style="color: #d19a66;line-height: 26px;">0</span>; i < server.io_threads_num; i++) {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* io_threads_list 链表,用于存储该线程要执行的 I/O 操作。*/</span><br> io_threads_list[i] = listCreate();<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 0 号线程不创建,0 号就是主线程,主线程也会处理任务逻辑。</span><br> <span style="color: #c678dd;line-height: 26px;">if</span> (i == <span style="color: #d19a66;line-height: 26px;">0</span>) <span style="color: #c678dd;line-height: 26px;">continue</span>;<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建线程,主线程先对子线程上锁,挂起子线程,不让其进入工作模式</span><br> <span style="color: #c678dd;line-height: 26px;">pthread_t</span> tid;<br> pthread_mutex_init(&io_threads_mutex[i],<span style="color: #56b6c2;line-height: 26px;">NULL</span>);<br> setIOPendingCount(i, <span style="color: #d19a66;line-height: 26px;">0</span>);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 挂起子线程,先不进入工作模式,等待主线程发出干活信号再执行任务。</span><br> pthread_mutex_lock(&io_threads_mutex[i]);<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建线程,指定I/O线程的入口函数 IOThreadMain</span><br> <span style="color: #c678dd;line-height: 26px;">if</span> (pthread_create(&tid,<span style="color: #56b6c2;line-height: 26px;">NULL</span>,IOThreadMain,(<span style="color: #c678dd;line-height: 26px;">void</span>*)(<span style="color: #c678dd;line-height: 26px;">long</span>)i) != <span style="color: #d19a66;line-height: 26px;">0</span>) {<br> serverLog(LL_WARNING,<span style="color: #98c379;line-height: 26px;">"Fatal: Can't initialize IO thread."</span>);<br> <span style="color: #e6c07b;line-height: 26px;">exit</span>(<span style="color: #d19a66;line-height: 26px;">1</span>);<br> }<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// I/O 线程数组</span><br> io_threads[i] = tid;<br> }<br>}<br></code></pre> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 检查是否开启 I/O 多线程模型:默认不激活 I/O 多线程模型,当 redis.conf 的 io-threads 配置大于 1 并且小于 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>IO_THREADS_MAX_NUM</code>(128) 则表示开启 I/O 多线程模式。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 创建 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>io_threads_list</code> 链表,用于保存每个线程需要处理的 I/O 任务。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 创建子线程,创建的时候先上锁,挂起子线程不让其进入工作模式,等初始化工作完成再开启。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 指定 I/O 线程的入口函数 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>IOThreadMain</code>,I/O 线程开始工作。 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="display: none;"></span><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">I/O 线程核心函数</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;"><code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>IOThreadMain</code> 函数主要负责等待启动信号、执行特定的 I/O 操作,并在完成操作后重置线程状态,以便再次等待下一次启动信号。</p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;margin-top: 10px;margin-bottom: 10px;"><span style="display: block;background: url(" https: mmbiz.qpic.cn mmbiz_svg 7n2jrawoorbcpmv9swrbdjianq0672hfmai5jyljfxzrgiaib3skvibma70icmtmezc6clcwpdfiuuctlxbm1pbiacxiandxedyhuv5 640?wx_fmt="svg&from=appmsg")" 10px 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">void</span> *<span style="color: #61aeee;line-height: 26px;">IOThreadMain</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">void</span> *myid)</span> </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 每个线程创建一个 id */</span><br> <span style="color: #c678dd;line-height: 26px;">long</span> id = (<span style="color: #c678dd;line-height: 26px;">unsigned</span> <span style="color: #c678dd;line-height: 26px;">long</span>)myid;<br> <span style="color: #c678dd;line-height: 26px;">char</span> thdname[<span style="color: #d19a66;line-height: 26px;">16</span>];<br> .....<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 进入无限循环,等待主线程发出干活信号</span><br> <span style="color: #c678dd;line-height: 26px;">while</span>(<span style="color: #d19a66;line-height: 26px;">1</span>) {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 没有使用 sleep 设置等待时间实现忙等,而是循环,耗费 CPU*/</span><br> <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">int</span> j = <span style="color: #d19a66;line-height: 26px;">0</span>; j < <span style="color: #d19a66;line-height: 26px;">1000000</span>; j++) {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 等待待处理的 I/O 操作出现,也就是读写客户端数据</span><br> <span style="color: #c678dd;line-height: 26px;">if</span> (getIOPendingCount(id) != <span style="color: #d19a66;line-height: 26px;">0</span>) <span style="color: #c678dd;line-height: 26px;">break</span>;<br> }<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/*留机会给主线程上锁,挂起当前子线程 */</span><br> <span style="color: #c678dd;line-height: 26px;">if</span> (getIOPendingCount(id) == <span style="color: #d19a66;line-height: 26px;">0</span>) {<br> pthread_mutex_lock(&io_threads_mutex[id]);<br> pthread_mutex_unlock(&io_threads_mutex[id]);<br> <span style="color: #c678dd;line-height: 26px;">continue</span>;<br> }<br><br> serverAssert(getIOPendingCount(id) != <span style="color: #d19a66;line-height: 26px;">0</span>);<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 根据线程 id 以及待分配列表进行任务分配 */</span><br> listIter li;<br> listNode *ln;<br> listRewind(io_threads_list[id],&li);<br> <span style="color: #c678dd;line-height: 26px;">while</span>((ln = listNext(&li))) {<br> client *c = listNodeValue(ln);<br> <span style="color: #c678dd;line-height: 26px;">if</span> (io_threads_op == IO_THREADS_OP_WRITE) {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 将可写客户端任务分配</span><br> writeToClient(c,<span style="color: #d19a66;line-height: 26px;">0</span>);<br> } <span style="color: #c678dd;line-height: 26px;">else</span> <span style="color: #c678dd;line-height: 26px;">if</span> (io_threads_op == IO_THREADS_OP_READ) {<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 读取客户端 socket 数据</span><br> readQueryFromClient(c->conn);<br> } <span style="color: #c678dd;line-height: 26px;">else</span> {<br> serverPanic(<span style="color: #98c379;line-height: 26px;">"io_threads_op value is unknown"</span>);<br> }<br> }<br><br> listEmpty(io_threads_list[id]);<br> setIOPendingCount(id, <span style="color: #d19a66;line-height: 26px;">0</span>);<br> }<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="display: none;"></span><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">待读取客户端任务分配</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">Redis 会在主线程 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>initServer</code> 初始化服务器的时候会注册 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>beforeSleep</code>函数,里面会调用 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>handleClientsWithPendingReadsUsingThreads</code>函数实现待处理任务分配逻辑。该函数的主要作用如下。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 将所有待读的客户端平均分配到不同的 I/O 线程的列表中。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 通过设置 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>io_threads_op</code> 和调用 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>setIOPendingCount</code> 函数,通知各个 I/O 线程开始处理可读取的客户端数据。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程也参与处理客户端读取,以确保更好的并发性能。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程等待所有 I/O 线程完成读取 socket 工作。 </section></li> </ul> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;"><strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">这种设计采用了“扇出 -> 扇入”的范式,通过将工作分发到多个 I/O 线程,再将结果合并回主线程,以提高并发性能。</strong></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;margin-top: 10px;margin-bottom: 10px;"><span style="display: block;background: url(" https: mmbiz.qpic.cn mmbiz_svg 7n2jrawoorbcpmv9swrbdjianq0672hfmai5jyljfxzrgiaib3skvibma70icmtmezc6clcwpdfiuuctlxbm1pbiacxiandxedyhuv5 640?wx_fmt="svg&from=appmsg")" 10px 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">int</span> <span style="color: #61aeee;line-height: 26px;">handleClientsWithPendingReadsUsingThreads</span><span style="line-height: 26px;">(<span style="color: #c678dd;line-height: 26px;">void</span>)</span> </span>{<br> ......<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 将所有待处理的客户端平均分配到不同的 I/O 线程的列表中*/</span><br> listIter li;<br> listNode *ln;<br> listRewind(server.clients_pending_read,&li);<br> <span style="color: #c678dd;line-height: 26px;">int</span> item_id = <span style="color: #d19a66;line-height: 26px;">0</span>;<br> <span style="color: #c678dd;line-height: 26px;">while</span>((ln = listNext(&li))) {<br> client *c = listNodeValue(ln);<br> <span style="color: #c678dd;line-height: 26px;">int</span> target_id = item_id % server.io_threads_num;<br> listAddNodeTail(io_threads_list[target_id],c);<br> item_id++;<br> }<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 通过设置 `io_threads_op` 和调用 `setIOPendingCount` 函数,通知各个 I/O 线程开始处理可读取的客户端数据。 */</span><br> io_threads_op = IO_THREADS_OP_READ;<br> <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">int</span> j = <span style="color: #d19a66;line-height: 26px;">1</span>; j < server.io_threads_num; j++) {<br> <span style="color: #c678dd;line-height: 26px;">int</span> count = listLength(io_threads_list[j]);<br> setIOPendingCount(j, count);<br> }<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 主线程处理第一个等待队列任务 */</span><br> listRewind(io_threads_list[<span style="color: #d19a66;line-height: 26px;">0</span>],&li);<br> <span style="color: #c678dd;line-height: 26px;">while</span>((ln = listNext(&li))) {<br> client *c = listNodeValue(ln);<br> readQueryFromClient(c->conn);<br> }<br> listEmpty(io_threads_list[<span style="color: #d19a66;line-height: 26px;">0</span>]);<br><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">/* 主线程处理完任务后,忙等等待所有 I/O 线程完成读取 socket 工作 */</span><br> <span style="color: #c678dd;line-height: 26px;">while</span>(<span style="color: #d19a66;line-height: 26px;">1</span>) {<br> <span style="color: #c678dd;line-height: 26px;">unsigned</span> <span style="color: #c678dd;line-height: 26px;">long</span> pending = <span style="color: #d19a66;line-height: 26px;">0</span>;<br> <span style="color: #c678dd;line-height: 26px;">for</span> (<span style="color: #c678dd;line-height: 26px;">int</span> j = <span style="color: #d19a66;line-height: 26px;">1</span>; j < server.io_threads_num; j++)<br> pending += getIOPendingCount(j);<br> <span style="color: #c678dd;line-height: 26px;">if</span> (pending == <span style="color: #d19a66;line-height: 26px;">0</span>) <span style="color: #c678dd;line-height: 26px;">break</span>;<br> }<br><br> ......<br><br> <span style="color: #c678dd;line-height: 26px;">return</span> processed;<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="display: none;"></span><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">待写回客户端任务分配</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">与上面类似, <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>beforeSleep</code>函数里面会调用 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>handleClientsWithPendingWritesUsingThreads</code>函数实现可写客户端处理任务分配给 I/O 线程,源代码跟 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>handleClientsWithPendingReadsUsingThreads</code>类似,不贴了。差别就是这个函数处理的事情是把响应写回 socket。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 将所有待写的客户端平均分配到不同的 I/O 线程的列表中。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 设置 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>io_threads_op</code> 为 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: " operator mono, consolas, monaco, menlo, monospace;word-break: break-all;>IO_THREADS_OP_READ</code>通知各个 I/O 线程开始处理可写的客户端数据。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程也参与处理客户端读取,以确保更好的并发性能。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 主线程等待所有 I/O 线程完成读取 socket 工作。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="border-color: rgb(248, 57, 41) rgb(0, 0, 0) rgb(0, 0, 0);margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: solid none none;border-width: 2px 1px 1px;border-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: center;line-height: 1.5em;overflow: unset;text-align: center;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(255, 255, 255);background: none 0% 0% / auto no-repeat scroll padding-box border-box rgb(248, 57, 41);line-height: 1.8em;letter-spacing: 0em;align-items: unset;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px 0px 13px 13px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;padding: 3px 5px 5px;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">模型缺陷</span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">Redis 的多线程网络模型实际上并不是一个标准的 Multi-Reactors/Master-Workers 模型,I/O 线程任务仅仅是通过 socket 读取客户端请求命令并解析,以及把指令执行结果回写给 socket ,没有真正去执行命令。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">所有客户端命令最后还需要回到主线程去执行,因此对多核的利用率并不算高,而且每次主线程都必须在分配完任务之后忙轮询等待所有 I/O 线程完成任务之后才能继续执行其他逻辑。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">在我看来,Redis 目前的多线程方案更像是一个折中的选择,只是黛玉骑鬼火,还未达到必杀技的阶段。</p> <p><br></p> <section style="border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 235);padding: 20px 14px;"> <section style="width: 100%;display: flex;justify-content: center;align-items: center;align-items: flex-end;"> <section style="display: flex;justify-content: center;align-items: center;background-color: rgb(255, 255, 255);margin-bottom: -10px;z-index: 10;"> <section style="width: 10px;height: 10px;border-radius: 50%;border-width: 1px;border-style: solid;border-color: rgb(51, 51, 51);"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;height: 20px;font-size: 14px;color: rgb(51, 51, 51);line-height: 20px;"> <p>往期推荐</p> </section> <section style="width: 10px;height: 10px;border-radius: 50%;border-width: 1px;border-style: solid;border-color: rgb(51, 51, 51);"> <br> </section> </section> </section> <section style="width: 100%;height: 1px;background: #333333;margin-bottom: 16px;"> <br> </section> <section> <section><a href="http://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&mid=2247504969&idx=1&sn=555fc9696295a3f05238b00f1ddeaa0c&chksm=c27f967ff5081f69b40f1f28881a3a8fd802d87738d5079955d9e60b8ca2b769ea1f5dabfe06&scene=21#wechat_redirect" data-linktype="2"> <section style="background: rgb(245, 245, 245);display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;color: rgb(51, 51, 51);line-height: 18px;"> <p style="text-wrap-mode: nowrap;overflow: hidden;text-overflow: ellipsis;">京东二面:Redis 为什么这么快?我说是纯内存操作,他对我笑了笑......</p> </section> </a> </section> <section><a href="http://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&mid=2247504959&idx=1&sn=47164fafcb80cdb2a1316a1cce85ece3&chksm=c27f9609f5081f1f3996ed9b46bd8bcf8e68e8b7db1264c954fddc7553b917f95261ce747395&scene=21#wechat_redirect" data-linktype="2"> <section style="background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;color: rgb(51, 51, 51);line-height: 18px;"> <p style="text-wrap-mode: nowrap;overflow: hidden;text-overflow: ellipsis;">微服务架构中的服务注册与发现有哪些?Zookeeper、Eureka、Nacos、Consul 都有什么区别,实现原理是什么?</p> </section> </a> </section> <section><a href="http://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&mid=2247504921&idx=1&sn=12ab3ba0e1f10dc2f1090bbf950bced8&chksm=c27f962ff5081f3931fa7c3ff852b5002e5d097254223f224819171e0726010cacaea805eefc&scene=21#wechat_redirect" data-linktype="2"> <section style="background: rgb(245, 245, 245);display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;color: rgb(51, 51, 51);line-height: 18px;"> <p style="text-wrap-mode: nowrap;overflow: hidden;text-overflow: ellipsis;">我的 2024 盘点来了 | 愿你我闯过人生的每一道关</p> </section> </a> </section> <section><a href="http://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&mid=2247504905&idx=1&sn=f96884bd1f321b4aeb66185e7371afde&chksm=c27f963ff5081f2921794f25276a6d4c989afbcc14eeb5c89a3cfb06547846cbfae1293ea4c3&scene=21#wechat_redirect" data-linktype="2"> <section style="background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px;font-size: 13px;color: rgb(51, 51, 51);line-height: 18px;"> <p style="text-wrap-mode: nowrap;overflow: hidden;text-overflow: ellipsis;">Redis Sets 使用场景有哪些?如何实现共同好友?</p> </section> </a> </section> </section> </section> <p><br></p> </section> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkzMDI1NjcyOQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/EoJib2tNvVtf7icAmS0BQH6oDVG37Q8NzcfdguS5qAqOhfxvZyIKqmuX5BbnDjynrBbZzktp1EiaeFLzapp1nHysw/0?wx_fmt=png" data-nickname="码哥跳动" data-alias="MageByte" data-signature="《Redis 高手心法》作者,10 年 Java 互联网大厂工作经验,作为后端架构师,喜欢用简介、风趣幽默的语言深入浅出的讲解技术,宗旨是拥抱技术和对象,面向人民币编程。" data-from="0" data-is_biz_ban="0" data-service_type="1"></mp-common-profile> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="markdown编辑器" data-website="https://markdown.com.cn/editor" style="font-size: 16px;color: black;padding: 25px 30px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: justify;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;margin-top: -10px;"> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""> 同时大家也提了一些问题,汇总一下大家的问题:</span></p> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">已经有现成的知识库(自动采集)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">embdding向量拆分的时候可能会丢失信息(分段优化)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">给llm的信息受token数量限制(分级召回策略)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">使用dify建知识库加集成ollama,感觉效果一般(索引优化)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">局域网内多终端访问同一个向量数据库(web应用)</span> </section></li> </ol> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">在后面方案里详细地给大家说明。</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001624" data-ratio="0.6677265500794912" data-s="300,640" src="/upload/f45faa1c1309e1aa6f76eeb542025a21.png" data-type="png" data-w="629" type="block"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">方案说明</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">我简单地梳理了下流程。理想的情况下:</span></p> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">知识的维护是一波人,维护过后的知识,直接向量化到向量库了里</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">知识的使用可能是另外一波人,他甚至都不知道有这些知识,只是在应用的时候,自动检索到并组装上下文给到deepseek。</span> </section></li> </ol> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">知识库</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">支持多人同时编辑</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">具备以下条件:</span> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">事件通知机制:新增或修改以后同步通知(有最佳)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">有对外的api或可以爬取的页面</span> </section></li> </ul> </ul> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">关于dify 和MaxKB的知识库</span><span style="display: none;"></span></h3> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">共同点:</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">都可以使用通用知识库:(上传文档)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">可以网页抓取(支持同步)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">可以设置分段模式,也可以自定义分段(解决文档结构的差异性)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">指定向量模型 差异点:</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">dify支持直接写接口查询向量库(ps:两边的规则要一致)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">dify 检索可以调整相似度阈值和Rerank 模型(进行重新排序,从而改进语义排序的结果)</span> </section></li> </ul> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">向量化</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;"><span leaf="">高精度要求</span></strong><strong style="font-weight: bold;color: black;"><span leaf="">建议自己写程序处理,更准确一些,能解决索引质量和信息丢失的问题</span></strong><span leaf=""> 因为每个企业的知识结构和习惯不一样,大家处理数据的方式也会有差别,这个需要好好的调试。 这里注意的是需要记录下每篇知识向量化后的id,以及对应的版本或时间戳,方便后续删除向量数据。 deepseek给的方案是</span></p> <pre data-tool="markdown.com.cn编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span leaf="">分段优化三原则: </span><span leaf=""><br></span><span leaf="">▸ 语义完整性校验(BERTScore>0.85) </span><span leaf=""><br></span><span leaf="">▸ 动态重叠窗口(建议15%-20%文本长度) </span><span leaf=""><br></span><span leaf="">▸ 关键实体锚点锁定(使用spaCy实体识别)</span><span leaf=""><br></span></code></pre> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;"><span leaf="">低精度要求</span></strong><span leaf="">会有一定的丢失概率,直接使用dify或maxKB即可。</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">分段标识默认都是/n (需要根据自己的结构化调整)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">分段重叠长度 设置为tokens大小的10%~15%</span> </section></li> </ul> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">向量库(具备研发能力)</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">具备研发能力的同学,可以看这块。</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">根据数据量的大小和是否持久化评估自己评估</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">Dify 在 </span><strong style="font-weight: bold;color: black;"><span leaf="">v0.6.x 及更高版本中默认集成 </span><span leaf="">PGVector</span></strong><span leaf="">(基于 PostgreSQL 的向量扩展)在配置文件中可改</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">MaxKB 默认使用 </span><strong style="font-weight: bold;color: black;"><span leaf="">Weaviate</span></strong><span leaf=""> 作为向量存储引擎</span> </section></li> </ul> <table style="display: table;text-align: left;"> <thead> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">数据库</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">存储容量</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">查询延迟</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">扩展性</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">典型场景</span> </section></th> </tr> </thead> <tbody> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">Milvus</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">PB级(分布式)</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">毫秒级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">⭐⭐⭐⭐⭐</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">大规模AI应用</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: #F8F8F8;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">FAISS</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">内存限制</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">微秒~毫秒级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">⭐⭐</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">内存内快速检索</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">Weaviate</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">TB级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">毫秒级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">⭐⭐⭐</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">混合查询</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: #F8F8F8;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">Vespa</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">PB级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf=""><50ms</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">⭐⭐⭐⭐</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">企业级实时搜索</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">Qdrant</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">TB级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">毫秒级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">⭐⭐⭐</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">带过滤的向量搜索</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: #F8F8F8;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">Chroma</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">GB级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">毫秒级</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">⭐</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">原型开发与小规模应用</span> </section></td> </tr> </tbody> </table> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">选型建议</span><span style="display: none;"></span></h3> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;"><span leaf="">超大规模数据+分布式</span></strong><span leaf="">:Milvus、Vespa。</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;"><span leaf="">高维向量+GPU加速</span></strong><span leaf="">:FAISS(需自研存储层)、Milvus。</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;"><span leaf="">轻量级+快速开发</span></strong><span leaf="">:Chroma、Annoy。</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;"><span leaf="">混合查询(向量+属性)</span></strong><span leaf="">:Weaviate、Qdrant。</span> </section></li> </ul> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;"><span leaf="">提示</span></strong><span leaf="">: 实际性能受数据维度、硬件配置(如SSD/NVMe)、索引参数影响强烈,建议通过真实数据基准测试验证。</span></p> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">应用客户端</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">要求如下:</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">可以外部访问(web应用或提供api)</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">可以直接使用外部的向量库或通过api调用</span> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">不需要自己再添加文档,向量化到向量库里</span> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">可以关联知识库</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">可以召回</span> </section></li> </ul> <table style="display: table;text-align: left;"> <thead> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">产品</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">形式</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">对外api服务</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">外部知识库</span> </section></th> <th valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;font-weight: bold;background-color: #f0f0f0;"> <section> <span leaf="">外部向量库</span> </section></th> </tr> </thead> <tbody> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">cherry studio</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">桌面</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: #F8F8F8;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">anythingLLM</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">桌面或web</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">dify</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">web</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: #F8F8F8;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">MaxKB</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">web</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">ragflow</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">web</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">/</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: #F8F8F8;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">FastGPT</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">web</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">是</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">否</span> </section></td> </tr> <tr style="border: 0;border-top: 1px solid #ccc;background-color: white;"> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">openwebui</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf="">web</span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf=""><br></span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf=""><br></span> </section></td> <td valign="top" style="font-size: 16px;border: 1px solid #ccc;padding: 5px 10px;text-align: left;"> <section> <span leaf=""><br></span> </section></td> </tr> </tbody> </table> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MaxKB和dify 都可以召回,我们可以通过高级功能,做一个流程来解决</span><strong style="font-weight: bold;color: black;"><span leaf="">问题3</span></strong><span leaf="">。先获取topn的向量,大模型排序,根据规则进行过滤。 deepseek给的解决方案:不知道dify和maxKB如何配置。</span></p> <pre data-tool="markdown.com.cn编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span leaf="">① BM25粗筛(Top100)→ ② 向量精排(Top10)→ ③ 元数据过滤</span><span leaf=""><br></span></code></pre> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">MaxKB</span><span style="display: none;"></span></h3> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">创建应用的时候,可以关联多个知识库,高级应用可以做流程编排。</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001626" data-ratio="0.5305555555555556" data-s="300,640" src="/upload/3fcc6b9d828b63820484259cbb06619b.png" data-type="png" data-w="1080" type="block"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MaxKB 的智能分段,</span></p> <section style="text-align: center;" nodeleaf=""> <img src="/upload/27171fed2416faf187cd0ec7f18d7d47.png" class="rich_pages wxw-img" data-ratio="1.146589259796807" data-s="300,640" data-type="png" data-w="689" type="block" data-imgfileid="100001627"> </section> <section> <span leaf="">maxKB的高级分段功能。</span> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <section style="text-align: center;" nodeleaf=""> <img src="/upload/1ac03a2044598c7d217089554985009a.png" class="rich_pages wxw-img" data-ratio="1.4133504492939666" data-s="300,640" data-type="png" data-w="779" type="block" data-imgfileid="100001628"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">dify</span><span style="display: none;"></span></h3> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">创建应用的时候也可以关联多个知识库。可以设置多路召回。</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001629" data-ratio="0.20092592592592592" data-s="300,640" src="/upload/a686ce89d629ec6daa85fd3829c18742.png" data-type="png" data-w="1080" type="block"> </section> <section style="text-align: center;" nodeleaf=""> <img src="/upload/cf523de26097a059cc48984455a658e8.png" class="rich_pages wxw-img" data-ratio="1.24282982791587" data-s="300,640" data-type="png" data-w="523" type="block" data-imgfileid="100001630"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">dify中知识库分段和清洗可以自定义设置</span></p> <section style="text-align: center;" nodeleaf=""> <img src="/upload/f36ced638ff29b7fc8462920041f854d.png" class="rich_pages wxw-img" data-ratio="1.300233644859813" data-s="300,640" data-type="png" data-w="856" type="block" data-imgfileid="100001631"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <h3 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span leaf="">FastGpt</span><span style="display: none;"></span></h3> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100001632" data-ratio="1.183794466403162" data-s="300,640" src="/upload/4368816df14534d7728e90d6efae3ed3.png" data-type="png" data-w="506" type="block"> </section> <p data-tool="markdown.com.cn编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf=""><br></span></p> <h2 data-tool="markdown.com.cn编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;"><span leaf="">总结</span></span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"><span leaf=""> </span></span></h2> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">在不想动用人力开发的情况下。企业内部的知识库使用dify和MaxKB都可以。dify的定制性功能更强一些。</span> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">分段和检索那块好好的调教下</span> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span leaf="">对有研发能力,可以使用dify+自定义数据,能实现多种可能性,精度由自己的程序控制。只要调教好检索即可。</span> </section></li> </ul> </section>
作者:じ☆ve不哭
## 下载 清华镜像:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ anaconda:https://www.anaconda.com/products/individual miniconda:https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh miniconda 与 anaconda 的区别:minicoda 是只有conda基础功能的软件,相当于⽑坯房。 anaconda 除了 minicoda 功能外,加⼊了⼤量常⽤的包,相当于精装房。 ## 安装 ``` sh Anaconda3-2024.10-1-Linux-x86_64.sh ``` ### 配置环境变量 **vi /etc/profile** ``` export PATH=~/home/studyjava/miniconda3/bin:$PATH ``` 设置生效:**source /etc/profile** ## 配置镜像 vi ~/.condarc 替换原⽂件内容为: ``` channels: - defaults show_channel_urls: true default_channels: - http://mirrors.aliyun.com/anaconda/pkgs/main - http://mirrors.aliyun.com/anaconda/pkgs/r - http://mirrors.aliyun.com/anaconda/pkgs/msys2 custom_channels: conda-forge: http://mirrors.aliyun.com/anaconda/cloud msys2: http://mirrors.aliyun.com/anaconda/cloud bioconda: http://mirrors.aliyun.com/anaconda/cloud menpo: http://mirrors.aliyun.com/anaconda/cloud pytorch: http://mirrors.aliyun.com/anaconda/cloud simpleitk: http://mirrors.aliyun.com/anaconda/cloud ``` ## conda命令 ``` 1. conda --version #查看conda版本,验证是否安装 2. conda update conda #更新⾄最新版本,也会更新其它相关包 3. conda update --all #更新所有包 4. conda update package_name #更新指定的包 5. conda create -n env_name package_name #创建名为env_name的新环境,并在该环境下安装名 为package_name 的包,可以指定新环境的版本号,例如:conda create -n python2 python=2.7 numpy pandas,创建了python2环境,python版本为2.7,同时还安装了numpy pandas包 6. conda activate env_name #切换⾄env_name环境 7. conda deactivate #退出环境 8. conda info -e #显⽰所有已经创建的环境 9. conda create --name new_env_name --clone old_env_name #复制old_env_name为 new_env_name 10. conda remove --name env_name ‒all #删除环境 11. conda list #查看所有已经安装的包 12. conda install package_name #在当前环境中安装包 13. conda install --name env_name package_name #在指定环境中安装包 14. conda remove -- name env_name package #删除指定环境中的包 15. conda remove package #删除当前环境中的包 16. conda env remove -n env_name #采⽤第10条的⽅法删除环境失败时,可采⽤这种⽅法 ``` ## conda 虚拟环境 导出 requirement ``` 1. 激活需要导出依赖关系的虚拟环境。可以使⽤以下命令激活: 2. 3. conda activate env_name 4. 使⽤以下命令将虚拟环境的依赖关系导出到 YAML ⽂件中: 5. 6. conda env export > env_name.yml 7. 这个命令会将当前虚拟环境的所有依赖关系(包括 Python 版本、Conda 包、Pip 包等)导出到名 为 env_name.yml 的⽂件中。 8. 可以使⽤⽂本编辑器打开 env_name.yml ⽂件,查看导出的依赖关系信息。 9. 10. name: env_name channels: - defaults dependencies: - python=3.8 - numpy=1.19.1 - pandas=1.1.1 - pip: - jupyterlab==2.2.6 - matplotlib==3.3.1 11. 其中, name 表⽰虚拟环境的名称, channels 表⽰使⽤的 Conda 软件源, dependencies 表⽰虚拟环境的依赖关系,其中包括 Python 版本、Conda 包和 Pip 包等。 可 以根据需要修改或增加依赖关系,然后使⽤ conda env create 命令创建⼀个新的虚拟环 境,或者将这个⽂件共享给其他⼈,让他们创建⼀个相同的虚拟环境。 12. conda env create -f env_name.yml 13. 这个命令会根据 YAML ⽂件中的依赖关系创建⼀个新的虚拟环境。 希望这个回答对您有所帮助。 ```