tauri2+typescript+vue+vite+leaflet等的简单联合使用(一)

项目目标

主要的目的是学习tauri。

流程

1、搭建项目

2、简单的在项目使用leaflet

3、打包

准备项目

环境准备

废话不多说,直接开始

需要有准备能运行Rust的环境和Node,对于Rust可以参考下面这位大佬的文章,Node不必细说。

Rust 和 Cargo 安装指南-CSDN博客https://blog.csdn.net/qq_44154915/article/details/139365116

建立项目

进入tauri2

官网https://tauri.app/start/

笔者将使用pnpm建立项目,项目名称为ttvvl

如下

使用VSCode或者WebStorm打开项目

安装依赖

pnpm install 

运行

pnpm tauri dev

然后就在compiling

这笔者感到疑惑,可能是第一次运行,搞了许久

运行结果

 没有问题。

看一下文件夹的属性

6个G,有点大。

如果以

pnpm run dev

点击按钮,会出现错误

观察上面的代码,我们可以发现,这个是invoke好像是个方法。第一个参数是个字符串greet

第二个参数是个对象,属性是name。

同时找到src-tauri/src/lib.rs中的代码,如下

fn 是Rust的关键字,相当与定义了一个函数,函数名叫greet,参数name

format!是个格式化字符串的函数

其他不是很懂,但我们可以把这段代码给deepseek,问一问

解答如下

从这里我们可以得到关键信息——被这个宏标记的函数能被前端调用

因为Rust函数的函数名叫greet,而invoke的第一个参数是字符串greet,我们可以很容易猜测

二者必然有关系,我们可以检验一下

修改函数名为greets,运行

发现报错了

我们可以看到下面还有一个函数

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

可以问一问deepseek

原来下面那个函数是入口函数,invoke_handler是注册器,因此,把中括号里面的greet改成greets

应该可以运行了,(每次都要编译,有点慢)。

如果点击按钮,下面应该不会出现字

事实确实如此。

那么推断很有可能是正确的,那么我们把字符串greet改成greets,就可以出现字了

事实确实如此,笔者明白了。

再次观察,Rust函数greets返回值是String,

而返回格式化后的字符串,对于App.vue中的TypeScript代码,打印出greetMsg.value的值

在运行后的的tauri中,可以打开开发者工具,打印结果如下。

既然如此,感觉明白了,invoke作为Rust与TypeScript交互的关键函数

安装leaflet有关依赖

pnpm install leaflet leaflet-geoman-free

因为使用typescipt,还需要安装类型定义包

 pnpm install --save @types/leaflet.pm @types/leaflet

显示地图

这也是很麻烦的事情。

安装vue-router

pnpm install vue-router

新建一些目录和文件,如下

在router目录的index.ts中

import {createRouter, createWebHashHistory, Router, RouteRecordRaw, RouterOptions} from "vue-router";
const routes:RouteRecordRaw[]=[
    {
        path:"/",
        redirect:"/map",
        children:[
            {
                path:"map",
                component:()=>import("../views/Map.vue")
            }]
    }
]
const options:RouterOptions={
    history:createWebHashHistory(),
    routes
}
const router:Router=createRouter(options)
export default router

暂时先这么写

main.ts的内容

import { createApp } from "vue";
import App from "@/App.vue";
import router from "@/router";
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
const app=createApp(App);
app.use(router);
app.config.globalProperties.$L = L;

app.mount("#app");

将L作为Vue的全局属性,并且引入插件leaflet-geoman-free及相关样式

关于@符号,不多解释。

在constant/data.ts中

export const MAP_URL= "https://tile-a.openstreetmap.fr/hot/{z}/{x}/{y}.png";

 这个是地图瓦片的URL。通过它就能访问地图。

在utils/Map.ts中

import {MAP_URL} from "@/constant/data.ts";
import L from 'leaflet';
const GetMap = (
    control: any=null, //控件
    language:any = 'zh' //语言
): L.Map => {
    const options: L.MapOptions = {
        center: [30.6667, 104.0667], //中心点
        minZoom: 0,
        maxZoom: 30,
        zoom: 10,
        zoomControl: true,
        doubleClickZoom: true,
        attributionControl: true,
        dragging: true,
        boxZoom: true,
        scrollWheelZoom: true,
        zoomSnap: 0.5,
    };
    const map = L.map('map', options);
    L.tileLayer(MAP_URL, {
        attribution: '',
    }).addTo(map);
    map.pm.addControls(control); 
    map.pm.setLang(language);
    return map;
};
export default GetMap;

如果不写 

import L from 'leaflet'

Vue: 'L' refers to a UMD global, but the current file is a module. Consider adding an import instead.

在views/Map.vue中 

<script setup lang="ts">
import GetMap from "@/utils/Map.ts";
import { onMounted } from 'vue';
let map: any = null
onMounted(() => {
  map = GetMap();
    map.on('click', (e: any) => {
        console.log(e);
    });
})
</script>

<template>
<div id="map"></div>
</template>

<style scoped>
#map {
  height: 100vh;
  width: 200vh;
}
</style>

运行,结果如下

地图定位到成都市。

显示控件

可以查看leaflet-geoman-free文档

Introduction | Documentation for Leaflet-Geomanhttps://geoman.io/docs/leaflet在constant/data.ts中

export const MAP_CONTROL={
}

可以写一些设置,但有默认选项,就不改了。

在views/Map.vue中导入MAP_CONTROL,作为GetMap的参数

map = GetMap(MAP_CONTROL);

,使用控件,运行结果如下

搞点小操作1——计算两点之间的距离

操作过程

点两个点,通过invoke函数发送经纬度到rust函数,返回结果

计算距离函数

使用Haversine 公式

haversine公式计算两经纬度点距离-CSDN博客https://blog.csdn.net/spatial_coder/article/details/116605509使用Rust实现,src-tauri/src/lib.rs的代码如下

const EARTH_RADIUS_KM: f64 = 6371.0; // 地球半径,单位:公里
#[tauri::command]
// 计算两个经纬度点之间的距离(单位:公里)
fn haversine_distance(start:[f64;2],end:[f64;2]) -> f64 {
    // 将经纬度从度数转换为弧度
    let lat1_rad = start[0].to_radians();
    let lon1_rad =  start[1].to_radians();
    let lat2_rad = end[0].to_radians();
    let lon2_rad = end[1].to_radians();

    // 经纬度差值
    let dlat = lat2_rad - lat1_rad;
    let dlon = lon2_rad - lon1_rad;

    // Haversine 公式
    let a = (dlat / 2.0).sin().powi(2) + lat1_rad.cos() * lat2_rad.cos() * (dlon / 2.0).sin().powi(2);
    let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());

    // 计算距离
    EARTH_RADIUS_KM * c
}



#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![haversine_distance])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

以公里作为单位

对两个点marker的思考

点了两个点marker,我们通过leaflet和有关插件的某些事件可以获得这两个点的属性,

我们可以修改这些属性。

那应该然后修改?

可以尝试使用tauri的多窗口。

marker位于父窗口,发送信号到子窗口,在子窗口进行修改,返回父窗口。

父子窗口以及发送信号

关于窗口的配置

src-tauri/capabilities/default.json

{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": ["main","marker-name"],
  "permissions": [
    "core:default",
    "opener:default",
    "core:window:allow-hide",
    "core:window:allow-show"

  ]
}

在子窗口添加一个路由

src/router/index.ts

    {
        path:"/name",
        component:()=>import("../views/name.vue")
    }

src-tauri/tauri.conf.json

"windows": [
      {
        "title": "ttvvl",
        "label": "main",
        "width": 800,
        "height": 600
      },
      {
        "title": "点位窗口",
        "width": 400,
        "height": 300,
        "label": "marker-name",
        "resizable": true,
        "parent": "main",
        "visible": false,
        "url":"#/name",
        "decorations": false,
        "center": true
      }
    ],

参数的具体含义,可以参考官网或者deekssek

{
  "windows": [
    {
      "label": "main", // 窗口的唯一标识符
      "title": "My Tauri App", // 窗口标题
      "width": 800, // 窗口宽度
      "height": 600, // 窗口高度
      "x": null, // 窗口初始水平位置(null 表示由系统决定)
      "y": null, // 窗口初始垂直位置(null 表示由系统决定)
      "minWidth": null, // 窗口最小宽度
      "minHeight": null, // 窗口最小高度
      "maxWidth": null, // 窗口最大宽度
      "maxHeight": null, // 窗口最大高度
      "resizable": true, // 是否允许调整窗口大小
      "fullscreen": false, // 是否全屏
      "focus": true, // 窗口是否在创建时获得焦点
      "visible": true, // 窗口是否可见
      "decorations": true, // 是否显示窗口装饰(标题栏、边框等)
      "alwaysOnTop": false, // 窗口是否始终置顶
      "maximized": false, // 窗口是否最大化
      "transparent": false, // 窗口背景是否透明
      "center": true, // 窗口是否居中
      "theme": "system", // 窗口主题("system"、"light"、"dark")
      "url": "index.html", // 窗口加载的页面路径
      "fileDropEnabled": true, // 是否启用文件拖放功能
      "skipTaskbar": false, // 是否在任务栏中显示窗口
      "shadow": true, // 是否显示窗口阴影
      "acceptFirstMouse": false, // 是否接受首次鼠标点击事件
      "tabbingIdentifier": null, // macOS 标签页标识符
      "titleBarStyle": "visible", // macOS 标题栏样式("visible"、"transparent"、"overlay")
      "hiddenTitle": false // 是否隐藏标题栏标题
    }
  ]
}

父窗口

src/views/Map.vue

<script setup lang="ts">
//@ts-nocheck
import GetMap from "@/utils/Map.ts";
import {MAP_CONTROL} from "@/constant/data.ts";
import {invoke} from "@tauri-apps/api/core";
import {emit,listen} from "@tauri-apps/api/event";
import {onMounted, ref} from 'vue';
import WindowManager from '@/utils/window';

const windowManager = new WindowManager();
let startName=ref<String>('起点');
let endName=ref<String>('终点');
let markerWindow,mainWindow,markerIndex=null;
let map: any = null
let markerList: L.Marker[] = [];
let distance=ref<number>(0);

listen('message-to-main-window', (event)=>{  //监听消息
  let payload:any=event.payload
  if(payload.close){
    windowManager.closeWindow('marker-name')
    mainWindow.show()
  }
  if(markerIndex===null){
    return
  }
  if(markerIndex===0){
    startName.value='起点'+payload.tooltipContent
  }else{
    endName.value='终点'+payload.tooltipContent
  }
  markerList[markerIndex].bindTooltip(payload.tooltipContent)
});
async function sendMsg(tooltipContent:String,nowClickMarkerId:Number) {  //发送消息
  markerWindow=await windowManager.getWindowByLabel('marker-name') //子窗口
  mainWindow=await windowManager.getWindowByLabel('main')  //父窗口
  if(markerWindow) {
    mainWindow.hide()
    markerWindow.show();
    markerIndex=markerList.findIndex(
        (marker:L.Marker)=>marker._leaflet_id===nowClickMarkerId
    )
    emit('message-to-second-window', { //发送消息 参数
          lat: markerList[0].getLatLng().lat,
          lng: markerList[0].getLatLng().lng,
          markerIndex:markerIndex,
          tooltipContent:tooltipContent
        }
    )
  }
}



async function get_distance(){
  let start=markerList[0].getLatLng(); //开始点
  let end=markerList[1].getLatLng();   //终点
  let startArray=[start.lat,start.lng];
  let endArray=[end.lat,end.lng];
  distance.value = await invoke('haversine_distance', { //发送给rust tauri
    start: startArray,
    end: endArray
  });
}
onMounted(() => {
  // openWindow()
  map = GetMap(MAP_CONTROL);
  map.on('pm:create', (e: any) => { //  map create事件
    let marker:L.Marker = e.marker;
    marker.on('click',(e)=>{ // marker的点击事件
      let nowClickMarkerId=e.target._leaflet_id  // 获取marker的id
      sendMsg(e.target.getTooltip(),nowClickMarkerId)  // 发送消息
    })
    markerList.push(marker);
    let length = markerList.length;
    if(length==2){  // 起始点 和终点
      get_distance()  //获取距离
    }else if(length>2){
      markerList[0].remove(); //移除第一个点
      markerList.shift();
      get_distance()   // 获取距离
    }

  })

})
</script>

<template>
<div id="map">

  <div id="distance-text" v-if="markerList.length>=2">从{{startName}}到{{endName}}的距离为</div>
  <div>
  <button type="button" id="show" >{{distance}}</button>
  </div>
  <div id="unit">
    公里
  </div>

</div>
</template>

<style scoped>
#map {
  margin: 0 auto;
  width: 100%;
  height: 900px;
}
#show {
  max-width: 200px;
  max-height: 50px;
  padding: 10px;
  background-color: blue;
  color: white;
  text-align: center;
  position: absolute;
  top: 100px;
  right: 10px;
  z-index: 999;
  border-radius: 20px;
}
#distance-text {
  max-width: 200px;
  max-height: 50px;
  padding: 10px;
  background-color: #af8433;
  color: white;
  text-align: center;
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 999;
  border-radius: 20px;
}
#unit {
  max-width: 200px;
  max-height: 50px;
  padding: 10px;
  background-color: #af8433;
  color: white;
  text-align: center;
  position: absolute;
  top: 150px;
  right: 10px;
  z-index: 999;
  border-radius: 20px;
}

</style>

子窗口

src/views/Name.vue

<script setup>
import {listen,emit} from "@tauri-apps/api/event";
import {onMounted, ref} from "vue";
let lat = ref(0);
let lng = ref(0);
let markerIndex = ref(0); // 0 替换成起点 1 替换成终点
let inputValue = ref('');
let oldTooltip=null


const handleClicked = () => {
  emit('message-to-main-window', {
    tooltipContent:inputValue.value,
    close: true,
  });
}
const handleCancel = () => {
  emit('message-to-main-window', {
    tooltipContent:oldTooltip,
    close: true,
  });
}
onMounted(
  () => {
    listen('message-to-second-window', (event) => {
      let payload = event.payload;
      lat.value = payload.lat;
      lng.value = payload.lng;
      markerIndex.value = payload.markerIndex;
      inputValue.value=payload.tooltipContent;
      oldTooltip=payload.tooltipContent
    });
  }
)

</script>
<template>
  <div  data-tauri-drag-region class="titlebar"  >
  <h1>{{markerIndex===0?'起点':'终点'}}</h1>
  <div v-if="lat>0">纬度:{{lat  }}</div>
  <div v-if="lng>0">经度:{{lng  }}</div>
  <div>名称
    <br/>
    <input v-model="inputValue"></input>
  </div>
  <br/>
  <button type="button" @click="handleClicked" class="sure">确定</button>
  <button type="button" @click="handleCancel" class="cancel">取消</button>
  </div>
</template>
<style >
.sure{
  padding: 10px ;
  margin-right: 10vw;
  background-color: #5174ff;
}
.cancel{
  padding: 10px ;
  margin-right: 10vw;
  background-color: #ffb43e;

}

</style>

窗口管理

src/utils/window.ts

import { getAllWebviewWindows } from '@tauri-apps/api/webviewWindow';


export class WindowManager {
    async getWindowByLabel(label: string) {
        const windows = await getAllWebviewWindows();
        return windows.find((win) => win.label === label);
    }
    async closeWindow(label: string) {
        const window = await this.getWindowByLabel(label);
        if (window) {
            window.hide();
        }
    }
}

export default WindowManager;

运行结果

运行结果倒是没问题,代码写得不行,算了。不管那些。

打包

本地打包

打包成exe命令

pnpm tauri build

因为笔者不是第一次打包,如果是第一次打包,需要下载一些东西,笔者就不展示了,可参考下面这位大佬的过程。 

从零开始的 Tauri 开发 & 打包成 exe 【Windows 平台】_tauri 打包-CSDN博客https://blog.csdn.net/u010263423/article/details/136006546对于leaflet打包,会出现一个bug,解决过程可看这篇文章

解决Vue+Vite打包后Leaflet的marker图标不显示的问题_leaflet l.marker 没有-CSDN博客https://blog.csdn.net/qq_63401240/article/details/139972362?spm=1001.2014.3001.5502总之。打包结果

打包运行结果

可以。

上传到github并打包

在github上通过工作流打包

工作流代码参考下面这位大佬

tauri使用github的action自动发布release,让别人也可以看到下载链接_tauri github action-CSDN博客https://blog.csdn.net/weixin_44786530/article/details/140904091在大佬的基础上做出小的修改

修改了工件的版本,其他改动不大

运行结果如下

发现ubuntu出错了。笔者没有深究。

笔者再次打包,只选择了window系统,结果如下

项目地址

qe-present/ttvvlhttps://github.com/qe-present/ttvvl

总结

简单地使用了tauri,使用了信号通信,多窗口,打包。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【FastGPT】如何新增用户修改密码

【FastGPT】如何新增用户&修改密码 摘要查看运行中的容器进入mongo容器登录mongo数据库切换数据库查询用户集合数据新增用户查询团队表数据创建团队查询团队成员集合数据把用户加入团队FastGPT用户密码的加密规则介绍加密算法Java版参考代码&单元测试代码修改密码 摘要…

复试准备日常

实验室目前投了 aiot 这周四 感知计算面试3.5号下午2点开始&#xff08;面完了他问我有没有项目&#xff09; 532图像处理实验室&#xff08;我的项目大多也是图像处理的&#xff09;&#xff08;预计下周末&#xff09;提前到3.4号下午6点 我不在第一批里面 软专不知道要几个 …

HiRT:利用分层机器人Transformer 增强机器人控制

25年2月来自清华、伯克利分校和上海姚期智研究院的论文“HiRT: Enhancing Robotic Control with Hierarchical Robot Transformers”。 大型视觉-语言-动作 (VLA) 模型利用强大的预训练视觉-语言模型 (VLM) 后端&#xff0c;由于其深刻的泛化能力而在机器人控制方面显示出良好…

Netty笔记3:NIO编程

Netty笔记1&#xff1a;线程模型 Netty笔记2&#xff1a;零拷贝 Netty笔记3&#xff1a;NIO编程 Netty笔记4&#xff1a;Epoll Netty笔记5&#xff1a;Netty开发实例 Netty笔记6&#xff1a;Netty组件 Netty笔记7&#xff1a;ChannelPromise通知处理 Netty笔记8&#xf…

MySQL-高级查询

查询处理 排序&#xff08;默认不是按主键排序的&#xff09; order by 字段1[&#xff0c;字段2] [asc|desc] 默认是升序排序也可以指定 select 列表中列的序号进行排序如果是多个字段&#xff0c;那么在上一个字段排序完的基础上排序下一个 限制数量 limit 行数&#xff0…

解决各大浏览器中http地址无权限调用麦克风摄像头问题(包括谷歌,Edge,360,火狐)后续会陆续补充

项目场景&#xff1a; 在各大浏览器中http地址调用电脑麦克风摄像头会没有权限&#xff0c;http协议无法使用多媒体设备 原因分析&#xff1a; 为了用户的隐私安全&#xff0c;http协议无法使用多媒体设备。因为像摄像头和麦克风属于可能涉及重大隐私问题的API&#xff0c;ge…

权限系统设计方案实践(Spring Security + RBAC 模型)

前言 权限系统设计基本上是所有项目中都会涉及的一个重要部分。通过权限系统&#xff0c;我们将对用户角色、功能模块访问进行限制&#xff0c;从而保证系统安全性。本文将介绍中大型项目中常用的一套权限系统设计方案&#xff0c;通过 SpringSecurity 安全管理框架&#xff0c…

数学软件Matlab下载|支持Win+Mac网盘资源分享

如大家所了解的&#xff0c;Matlab与Maple、Mathematica并称为三大数学软件。Matlab应用广泛&#xff0c;常被用于数据分析、无线通信、深度学习、图像处理与计算机视觉、信号处理、量化金融与风险管理、机器人&#xff0c;控制系统等领域。 Matlab将数值分析、矩阵计算、科学…

植物大战僵尸杂交版v3.3最新版本(附下载链接)

B站游戏作者潜艇伟伟迷于12月21日更新了植物大战僵尸杂交版3.3版本&#xff01;&#xff01;&#xff01;&#xff0c;有b站账户的记得要给作者三连关注一下呀&#xff01; 不多废话下载链接放上&#xff1a; 夸克网盘链接&#xff1a;&#xff1a;https://pan.quark.cn/s/6f2a…

GPU、NPU与LPU:大语言模型(LLM)硬件加速器全面对比分析

引言&#xff1a;大语言模型计算基础设施的演进 随着大语言模型&#xff08;LLM&#xff09;的快速发展与广泛应用&#xff0c;高性能计算硬件已成为支撑LLM训练与推理的关键基础设施。目前市场上主要有三类处理器用于加速LLM相关任务&#xff1a;GPU&#xff08;图形处理单元…

计算机网络数据传输探秘:包裹如何在数字世界旅行?

计算机网络数据传输探秘:包裹如何在数字世界旅行? 一、从快递网络看数据传输本质 想象你网购了一件商品: 打包:商家用纸箱包装,贴上地址标签(数据封装)运输:包裹经过网点→分拣中心→运输车(网络节点与链路)签收:快递员核对信息后交付(数据校验与接收)数据的网络…

VirtualBox虚拟机MacOS从Big Sur升级到Sequoia(失败)

VirtualBox虚拟机里安装好Big Sur版本&#xff0c;尝试升级到Sequoia&#xff0c;但是最终失败了。 软件升级 直接在系统偏好-软件更新里可以看到提示&#xff0c;提示可以升级到15版本Sequoia 点击同意&#xff0c;看能不能升级到Sequoia吧。升级前先用时光做了备份。 升级…

从数据到决策,永洪科技助力良信电器“智”领未来

在数字经济浪潮汹涌的时代&#xff0c;数字化转型已成为企业增强竞争力、实现可持续发展的必由之路。良信电器&#xff0c;作为国内知名的电气设备制造企业&#xff0c;积极响应时代号召&#xff0c;携手永洪科技&#xff0c;共同开启了数字化转型的新篇章。 上海良信电器股份有…

dify接入语音转文本模型后报错: microphone not authorized

遇到microphone not authorized莫慌,这是因为没有获取到设备的麦克风权限导致的 解决方法:&#xff08;三种选其一&#xff0c;我实际使用的是第三种&#xff09; 1.将http路径转换成https 2.接入的前端增加获取麦克风权限的功能 3.打开设备麦克风权限:&#xff08;能快速验证…

华为hcia——Datacom实验指南——配置手工模式以太网链路聚合

什么是以太网链路聚合&#xff08;Eth-trunk&#xff09; 是一种将多个物理链路捆绑在一起&#xff0c;让设备以为是一条大链路&#xff0c;能够增加带宽&#xff0c;增加冗余度&#xff0c;提升可靠性&#xff0c;实现负载平衡。 传输方式有两种 基于数据流传输和基于数据包…

【随手笔记】利尔达NB模组

1.名称 移芯EC6263GPP 参数 指令备注 利尔达上电输出 [2025-03-04 10:24:21.379] I_AT_WAIT:i_len2 [2025-03-04 10:24:21.724] LI_AT_WAIT:i_len16 [2025-03-04 10:24:21.724] [2025-03-04 10:24:21.733] Lierda [2025-03-04 10:24:21.733] [2025-03-04 10:24:21.745] OK移…

RNN实现精神分裂症患者诊断(pytorch)

RNN理论知识 RNN&#xff08;Recurrent Neural Network&#xff0c;循环神经网络&#xff09; 是一种 专门用于处理序列数据&#xff08;如时间序列、文本、语音、视频等&#xff09;的神经网络。与普通的前馈神经网络&#xff08;如 MLP、CNN&#xff09;不同&#xff0c;RNN…

阿里万相,正式开源

大家好&#xff0c;我是小悟。 阿里万相正式开源啦。这就像是AI界突然开启了一扇通往宝藏的大门&#xff0c;而且还是免费向所有人敞开的那种。 你想想看&#xff0c;在这个科技飞速发展的时代&#xff0c;AI就像是拥有神奇魔法的魔法师&#xff0c;不断地给我们带来各种意想…

json介绍、python数据和json数据的相互转换

目录 一 json介绍 json是什么&#xff1f; 用处 Json 和 XML 对比 各语言对Json的支持情况 Json规范详解 二 python数据和json数据的相互转换 dumps() : 转换成json loads(): 转换成python数据 总结 一 json介绍 json是什么&#xff1f; 实质上是一条字符串 是一种…

250301-OpenWebUI配置DeepSeek-火山方舟+硅基流动+联网搜索+推理显示

A. 最终效果 B. 火山方舟配置&#xff08;一定要点击添加&#xff09; C. 硅基流动配置&#xff08;最好要点击添加&#xff0c;否则会自动弹出所有模型&#xff09; D. 联网搜索配置 E. 推理过程显示 默认是没有下面的推理过程的显示的 F. SearXNG配置 注意&#xff1a;此…