[datawhale202211]跨模态神经搜索实践:前端简介 Streamlit

news2025/1/11 5:36:50

结论速递

VCED项目使用一个十分简单好用的 Web 应用程序框架Streamlit。

本次任务简单学习Streamlit的基本使用。并逐行阅读学习VCED项目的前端代码,学习数据的传递,中间存储方式,以及功能的实现。

前情回顾

  1. 环境配置
  2. Jina生态
  3. 跨模态模型

目录

    • 结论速递
    • 前情回顾
  • 1 Streamlit
    • 1.1 Streamlit简介
    • 1.2 安装和使用
      • 1.2.1 安装
      • 1.2.2 使用
  • 2 VCED项目的前端
    • 2.1 使用流程
    • 2.2 代码实现

1 Streamlit

1.1 Streamlit简介

Streamlit 是一个基于 Python 的 Web 应用程序框架,可以帮助数据科学家和学者在短时间内开发机器学习可视化仪表板。只需几行代码,就可以构建并部署强大的数据应用程序。其特点如下:

  • 跨平台,支持 Windows、macOS、Linux
  • 只需要掌握 Python,开发者就可以构建 Web App,不需要有任何的前端基础
  • 开源,社区资源丰富(Community forum、Github)

由于 Streamlit 基于 Python,开发者无需学习其他就可以搭建一个较为完整的系统。因此此次教程,VCED项目就通过 Streamlit + Jina 构建了一套系统。

1.2 安装和使用

1.2.1 安装

Streamlit目前支持Python 3.7以上的版本。用pip安装就可以。官方有一个预设网页:

streamlit hello

启动后长这样:

请添加图片描述

1.2.2 使用

Streamlit 框架提供了很多 API 供开发者使用。教程提供下面步骤将指引你一步一步构建自己的第一个 Web App:

  1. 打开 IDE(如 vscode),创建一个 hello-streamlit.py 文件,输入:
import streamlit as st
  1. 每个Web页面都会有一个title:
st.set_page_config(page_title="Hello Streamlit")
  1. Streamlit API 中提供了很多页面中常见的 elements:
st.title('This is your first Streamlit page!')  # 标题

st.markdown('Streamlit is **_really_ cool**.')  # markdown

code = '''def hello():
     print("Hello, Streamlit!")'''
st.code(code, language='python')  # code

df = pd.DataFrame(
     np.random.randn(50, 20),
     columns=('col %d' % i for i in range(20)))
st.dataframe(df)  # dataframe

st.latex(r'''
     a + ar + a r^2 + a r^3 + \cdots + a r^{n-1} =
     \sum_{k=0}^{n-1} ar^k =
     a \left(\frac{1-r^{n}}{1-r}\right)
     ''')  # latex
  • st.title:标题
  • st.markdown:markdown
  • st.code:代码
  • st.dataframe:数据帧
  • st.latex:latex公式

上述生成的界面如下:

请添加图片描述

确实是really cool

这里只介绍了 Streamlit 的冰山一角,更多特性和细节感兴趣的同学可以去官网进一步学习。另外,官网也有很多 Streamlit 模板,可以帮助你更高效地搭建自己的应用。

2 VCED项目的前端

2.1 使用流程

VCED项目实现的流程有:

  1. 上传视频
  2. 输入描述
  3. 输入Top N值
  4. 点击搜索,等待返回结果
  5. 查看搜索结果

2.2 代码实现

定义存储路径,监听端口(这些都属于数据传输)

VIDEO_PATH = f"{os.getcwd()}/data"
# 视频存储的路径
if not os.path.exists(VIDEO_PATH):
    os.mkdir(VIDEO_PATH)
# 视频剪辑后存储的路径
if not os.path.exists(VIDEO_PATH + "/videos/"):
    os.mkdir(VIDEO_PATH + "/videos")

# GRPC 监听的端口
port = 45679
# 创建 Jina 客户端
c = Client(host=f"grpc://localhost:{port}")

接下去就是一个一个的定义功能。

首先定义页面

# 设置标签栏
st.set_page_config(page_title="VCED", page_icon="🔍")
# 设置标题
st.title('Welcome to VCED!')

定义视频上传组件,使用st.file_uploader实现上传,然后根据上传结果创建st.video对象,并存储到先前定义的路径下,方便后端读取。

# 视频上传组件
uploaded_file = st.file_uploader("Choose a video")
video_name = None  # name of the video
# 判断视频是否上传成功
if uploaded_file is not None:
    # preview, delete and download the video
    video_bytes = uploaded_file.read()
    st.video(video_bytes)

    # save file to disk for later process
    video_name = uploaded_file.name
    with open(f"{VIDEO_PATH}/{video_name}", mode='wb') as f:
        f.write(video_bytes)  # save video to disk

video_file_path = f"{VIDEO_PATH}/{video_name}"
uid = uuid.uuid1()

同时生成一个uid。

定义文本输入框和top k 输入框。

# 文本输入框
text_prompt = st.text_input(
    "Description", placeholder="please input the description", help='The description of clips from the video')

# top k 输入框
topn_value = st.text_input(
    "Top N", placeholder="please input an integer", help='The number of results. By default, n equals 1')

然后定义三个功能函数:

  • 时间还原:将秒数转化为str时间戳,截取视频用
  • 截取视频:根据时间戳截取视频
  • 后端交互:生成jina对象,通过Client post数据,得到返回结果resp,存入json。
# 根据秒数还原 例如 10829s 转换为 03:04:05
def getTime(t: int):
    m,s = divmod(t, 60)
    h, m = divmod(m, 60)
    t_str = "%02d:%02d:%02d" % (h, m, s)
    print (t_str)
    return t_str

# 根据传入的时间戳位置对视频进行截取
def cutVideo(start_t: str, length: int, input: str, output: str):
    """
    start_t: 起始位置
    length: 持续时长
    input: 视频输入位置
    output: 视频输出位置
    """
    os.system(f'ffmpeg -ss {start_t} -i {input} -t {length} -c:v copy -c:a copy -y {output}')

# 与后端交互部分
def search_clip(uid, uri, text_prompt, topn_value):
    video = DocumentArray([Document(uri=uri, id=str(uid) + uploaded_file.name)])
    t1 = time.time()
    c.post('/index', inputs=video) # 首先将上传的视频进行处理
    
    text = DocumentArray([Document(text=text_prompt)])
    print(topn_value)
    resp = c.post('/search', inputs=text, parameters={"uid": str(uid), "maxCount":int(topn_value)}) # 其次根据传入的文本对视频片段进行搜索
    data = [{"text": doc.text,"matches": doc.matches.to_dict()} for doc in resp] # 得到每个文本对应的相似视频片段起始位置列表
    return json.dumps(data)

定义Serach按钮,同时实现功能。

单击后,生成对象给后端查找,返回时间戳,剪视频,输出。

# search
search_button = st.button("Search")
if search_button: # 判断是否点击搜索按钮
    if uploaded_file is not None: # 判断是否上传视频文件
        if text_prompt == None or text_prompt == "": # 判断是否输入查询文本
            st.warning('Please input the description first!')
        else:
            if topn_value == None or topn_value == "": # 如果没有输入 top k 则默认设置为1
                topn_value = 1
            with st.spinner("Processing..."):
                result = search_clip(uid, video_file_path, text_prompt, topn_value) 
                result = json.loads(result) # 解析得到的结果
                for i in range(len(result)):
                    matchLen = len(result[i]['matches'])
                    for j in range(matchLen):
                        print(j)
                        left = result[i]['matches'][j]['tags']['leftIndex'] # 视频片段的开始位置
                        right = result[i]['matches'][j]['tags']['rightIndex'] # 视频片段的结束位置
                        print(left)
                        print(right)
                        start_t = getTime(left) # 将其转换为标准时间
                        output = VIDEO_PATH + "/videos/clip" + str(j) +".mp4"
                        cutVideo(start_t,right-left, video_file_path, output) # 对视频进行切分
                        st.video(output) #将视频显示到前端界面
                st.success("Done!")
    else:
        st.warning('Please upload video first!')

此处有一个疑问

?:为什么要通过json传递数据,直接字典不可以吗

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

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

相关文章

[python]basemap后安装后hello world代码

import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.basemap import Basemap m Basemap() # 实例化一个map m.drawcoastlines() # 画海岸线 m.drawmapboundary(fill_colorwhite) m.fillcontinents(colorwhite,lake_colorwhite) # 画大洲&#x…

点云配准(四) Sparse Point Registration 算法浅析

Sparse Point Registration (SPR)是一篇2017年的点云配准算法,该算法的主要目的是对稀疏点云进行配准,并且取得了不错的成果和突破。本文一方面是对SPR配准算法模型进行了简单的原理解析以及附加代码实现,另一方面是对之前工作的总结,也算水篇博文,接下来的工作主要就是…

正统类加载器Tomcat(tomcat二探)

主流的Java Web服务器,如Tomcat、Jetty、WebLogic、WebSphere或其他笔者没有列举的服务器, 都实现了自己定义的类加载器,而且一般还都不止一个。因为一个功能健全的Web服务器,都要解决 如下的这些问题: 部署在同一个服…

C++设计模式之桥模式

桥模式也是设计模式中单一组件模式的一种。什么是单一组件模式呢? 单一组件模式: 在软件组件设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化而变化,子类急剧膨胀,同时充斥着重复代…

SpringBoot-Dubbo中的Customer怎么获取了注册中心的服务呢?

1.Dubbo中的Customer怎么获取了注册中心的服务呢? (1)要在pom文件中导入接口依赖 (2)在配置文件中指定服务中心的ip地址 (3)使用的dubbo自己的注解向服务中心中获取服务,并且将获取…

史上最简单:SpringCloud 集成 mybatis-plus(以若依微服务版本为例)

编者按:若依微服务版是基于Spring Boot、Spring Cloud & Alibaba的微服务的权限管理系统,也是笔者比较推荐的个人学习和企业实践都比较优秀的开源项目。 笔者也以此项目为例,介绍一下我自己是如何操作 SpringCloud 集成 mybatis-plus 的。…

API网关之Nginx作为网关的优势及实战

基于Nginx的网关的优势: 1 .速度更快、并发更高 单次请求或者高并发请求的环境下,Nginx都会比其他Web服务器响应的速度更快。一方面在正常情况下,单次请求会得到更快的响应,另一方面,在高峰期(如有数以万计的并发请求…

【Pytorch with fastai】第 20 章 :结语与问题

🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎 📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃 🎁欢迎各位→点赞…

开启linux的网络服务, FTP、SSH和NFS服务

在使用linux中开发的时候,我们可以选择启用一些网络服务方便我们进行开发,加快开发的进度。 现在很多用linux进行开发的工程师,他们大多都是在windows系统上安装虚拟机,然后在虚拟机中安装linux系统,然后在里面完成项目…

Java项目——表白墙(前后端连接+数据库存储)

前端的表白墙实现代码在之前的博客中有 Message类 表白墙中的每一个表白信息都由Message对象呈现,其包含form——表白者,to——被表白者,message——表白信息,以及一系列get和set方法 public class Message {private String fr…

我是如何构建自己的笔记系统的?

我是如何构建自己的笔记系统的? 关于笔记系统的重要性互联网上有许多的资料, 我这里将不再赘述. 下面我将直接介绍我的笔记从记录到整理文章发布的所有详细步骤和工具 我的笔记系统可能并不完善, 而且带着极强的个人倾向性, 只希望它能提供给你一种思考的方向 原文地址: https…

ArrayList 可以完全替代数组吗?

本文已收录到 GitHub AndroidFamily,有 Android 进阶知识体系,欢迎 Star。技术和职场问题,请关注公众号 [彭旭锐] 加入 Android 交流群。 前言 大家好,我是小彭。 在前面的文章里,我们学习了很多数据结构与算法思想…

【Nacos案例】

0、整体 整体项目概览 整体服务概览 1、新建父工程demo-nacos 删除src &#xff0c;切记 packaging&#xff1a;pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"ht…

[Apollo Cyber RT] Timer实现

Timer的实现方式 Timer有多种实现方式&#xff0c;CyberRT采用了时间轮(TimingWheel)方式。关于Timing Wheels的详细描述可以参考附录的链接。此处不赘述。 CyberRT Timer的类构成 实现细节 Timer Timer类是门户&#xff0c;但定时器真正的核心是TimingWheel。 Timer的定义…

索引的基础使用

索引&#xff1a; 分类&#xff1a; 功能逻辑&#xff1a;普通索引、唯一索引、主键索引、全文索引物理实现方式&#xff1a;聚簇索引&#xff0c;非聚簇索引作用字段个数&#xff1a;单列索引&#xff0c;联合索引 索引创建&#xff1a; --主键索引 CREATE TABLE dept( de…

SpringBoot的使用

一、Maven的环境搭建 暂时未完成.... 二、创建项目 创建完以后的目录如下&#xff1a; 然后配置pom.xml 再放入配置项 <!-- 2 我的依赖仓库源 , 首先配置仓库的服务器位置,首选阿里云&#xff0c;也可以配置镜像方式&#xff0c;效果雷同 --><repositories><re…

章节四:RASA 训练数据介绍

一、前言 一般来说&#xff0c;机器人可以跟人对话&#xff0c;机器人说什么是最难的&#xff0c;顶多是人工编写几种规则和模版来回复即可。但是要让机器人理解人的意图&#xff0c;确实非常难的事情。因为语言具有多样性&#xff0c;多义词&#xff0c;一语双关&#xff0c;…

872. 最大公约数(史上最详细讲解 7种算法,STL+算法标准实现)

一&#xff0c;什么是最大公约数 最大公约数&#xff08;Greatest Common Divisor&#xff09;指两个或多个整数共有约数中最大的一个。也称最大公因数、最大公因子&#xff0c;a&#xff0c; b的最大公约数记为&#xff08;a&#xff0c;b&#xff09;&#xff0c;同样的&…

测试架构工程师需要具备哪些能力 ?

目录 前言 为什么软件项目需要架构设计&#xff1f; 测试架构师需要解决什么问题&#xff1f; 测试架构师需要具备哪些能力&#xff1f; 测试工程师如何培养架构能力&#xff1f; 总结 重点&#xff1a;配套学习资料和视频教学 前言 相比于我们常见的研发架构师&#xf…

深入ftrace kprobe原理解析

Linux krpobe调试技术是内核开发者专门为了编译跟踪内核函数执行状态所涉及的一种轻量级内核调试技术&#xff0c;利用kprobe技术&#xff0c;内核开发人员可以在内核的绝大多数指定函数中动态插入探测点来收集所需的调试状态信息而基本不影响内核原有的执行流程。本章的是基于…