前言👀
项目地址:小汐创作助手: 小汐创作助手 (gitee.com)
为了能够快速完成页面的开发,提高开发速度降低开发成本。因此,我们整个项目,没有直接采用原来的前后端分离方案,而是直接使用streamlit完成搭建。streamlit是一款基于Python编写的前端机器学习组件库。简单高效,内置丰富的组件,同时我们也可以使用css对部分样式进行改造处理。 docs.streamlit.io/ 那么很显然,我们本篇博文的目的就是如何快速来实现,我们先前预设的UI效果。
首页: 对话助手 小说视频生成 设置页面 这里我们会简单介绍一下,我们在项目当中使用到的基本组件。当然streamlit本身还有非常丰富的组件,可以去查看官方文档探索,虽然是英文的,但是可以使用浏览器翻译来快速阅览,查找文档。文档当中有丰富的示例,因此可以直接看到效果,然后拿过来进行修改。
页面编写⚽
那么废话不多说,我们来看到我们整个页面是如何开始完成编写的。这里我们按照模块去进行拆分,希望,通过本篇博文,读者应该可以,将我们的整体页面跑起来,这样的话,我们接下来就只需关系到我们的功能实现即可了。
页面侧边导航
在开始之前,我们需要简单了解一下关于streamlit的一些机制的问题,首先的话,streamlit是支持热加载的。整个执行过程大致是这样的:1. 页面展示 2. 监听事件 3.执行事件函数 4. 重新刷新页面 因此这里要注意,在重新刷新页面的时候,是相当于把你写的代码重新执行了一遍的,因此,你先前保留在内存当中的变量都是会被重置的,因此如果要进行状态的保存的话,需要使用到它提供的session机制来进行保存。 那么这个事件的触发,执行,包括:按钮的点击,文本框的触发。而我们的侧边栏导航的实现,是通过单选框来进行实现的,因此每一次选择的话,其实都相当于重新运行了一下界面,只是我们会把一些状态进行保存而已。因此这一点需要特别注意🍡
整个侧边导航的实现非常简单:
python
def page_content(page):
if page == ':rainbow[首页]':
index()
if page == ':green[novel助手]':
assistant = AssistantNovel()
assistant.page()
elif page == ':blue[novel生成]':
novelGenerate = NovelGenerate()
novelGenerate.page()
elif page == ':red[设置]':
novelSettings = NovelSettings()
novelSettings.page()
custom_css = """
<style>
.block-container.st-emotion-cache-gh2jqd.ea3mdgi5 {
width: 100%;
margin: 0 auto;
max-width: 1200px;
}
.st-emotion-cache-1i41fkg.e1f1d6gn2{
height: 600px;
overflow-y: scroll; /* 添加垂直滚动条 */
}
</style>
"""
st.markdown(custom_css, unsafe_allow_html=True)
selected_page = st.sidebar.radio(
'Select Page which you want 👇',
[":rainbow[首页]", ":green[novel助手]", ":blue[novel生成]",":red[设置]"],
captions=["HomePage👻", "Novel Assistant😊", "Novel generation🤑","Settings😶"]
)
page_content(selected_page)
在切换单选按钮时,执行不同的页面展示函数进行实现。同时为了满足我们的要求,我们这里重新修改了一下css。这块你可能比较好奇,为什么这个css的选择器那么奇怪。其实这个是streamit渲染之后,对应的容器的div的class。这个可以通过控制台进行获取。为了让内容显示可以有更大的空间,这里我们做了这样的修改:
python
custom_css = """
<style>
.block-container.st-emotion-cache-gh2jqd.ea3mdgi5 {
width: 100%;
margin: 0 auto;
max-width: 1200px;
}
.st-emotion-cache-1i41fkg.e1f1d6gn2{
height: 600px;
overflow-y: scroll; /* 添加垂直滚动条 */
}
</style>
"""
首页🐱🏍
首页的话,主要是对项目的介绍,因此页面的形式和内容比较简单。这里的话,我们是直接使用st.markdown来实现文字的展示的。
python
def index():
st.markdown("*Novel-Video创作助手* is **really** ***cool*** --v0.1beta( ̄︶ ̄)↗ .")
st.markdown('''
:red[自带] :orange[小汐] :green[创作助手] :blue[完成文档润色] :violet[流水线]
:gray[内容生成] :rainbow[解放双手].''')
st.markdown("Welcome to here! —\
:tulip::cherry_blossom::rose::hibiscus::sunflower::blossom:")
current_file_path = os.path.abspath(__file__)
current_dir = os.path.dirname(current_file_path)
st.image(current_dir+r"/assert/img/bg.jpg",width=800)
当然,在这里,我们使用到一些配置相关的东西,但是这里没有涉及到具体的功能实现,因此我们不需要太关心。
到此,我们把我们最开始需要运行的main.py文件进行了实现。这将作为我们的整个程序的主入口。完整代码如下:
python
"""
@Author:Huterox
@Description:Go For It
@Time:2024/4/16 8:58
@Copyright:©2018-2024 awesome!
"""
from webui.streamlit.novelAssistant import AssistantNovel
from webui.streamlit.novelGenerate import NovelGenerate
from webui.streamlit.novelSettings import NovelSettings
import os
import streamlit as st
def index():
st.markdown("*Novel-Video创作助手* is **really** ***cool*** --v0.1beta( ̄︶ ̄)↗ .")
st.markdown('''
:red[自带] :orange[小汐] :green[创作助手] :blue[完成文档润色] :violet[流水线]
:gray[内容生成] :rainbow[解放双手].''')
st.markdown("Welcome to here! —\
:tulip::cherry_blossom::rose::hibiscus::sunflower::blossom:")
current_file_path = os.path.abspath(__file__)
current_dir = os.path.dirname(current_file_path)
st.image(current_dir+r"/assert/img/bg.jpg",width=800)
if __name__ == '__main__':
def page_content(page):
if page == ':rainbow[首页]':
index()
if page == ':green[novel助手]':
assistant = AssistantNovel()
assistant.page()
elif page == ':blue[novel生成]':
novelGenerate = NovelGenerate()
novelGenerate.page()
elif page == ':red[设置]':
novelSettings = NovelSettings()
novelSettings.page()
custom_css = """
<style>
.block-container.st-emotion-cache-gh2jqd.ea3mdgi5 {
width: 100%;
margin: 0 auto;
max-width: 1200px;
}
.st-emotion-cache-1i41fkg.e1f1d6gn2{
height: 600px;
overflow-y: scroll; /* 添加垂直滚动条 */
}
</style>
"""
st.markdown(custom_css, unsafe_allow_html=True)
selected_page = st.sidebar.radio(
'Select Page which you want 👇',
[":rainbow[首页]", ":green[novel助手]", ":blue[novel生成]",":red[设置]"],
captions=["HomePage👻", "Novel Assistant😊", "Novel generation🤑","Settings😶"]
)
page_content(selected_page)
对话助手
我想在这块,你应该注意到了,我们还导入了如下包:
python
from webui.streamlit.novelAssistant import AssistantNovel
from webui.streamlit.novelGenerate import NovelGenerate
from webui.streamlit.novelSettings import NovelSettings
实际上,这个就是我们接下来需要逐一实现的页面。 那么这块我们还是先来看到我们的对话助手。注意,在我们本篇文章里面,还是先讨论我们如何实现这个页面,而不涉及到我们具体的实现,具体的实现,我们将在具体的章节讲到。 那么关于对话助手的实现的话,还是比较简单的,这里我们使用了streamlit提供的专门的对话组件,所以实现很快,并且实现效果还是很不错的。这个风格我也挺喜欢的,当然这里还是没有做历史话题记录,因为如果要做的话,那么我们这里最好还是要设计一套用户系统,这样的话,开发事件又上去了。 那么对话助手的实现如下:
python
class AssistantNovel(object):
def __init__(self):
self.chat = ChatBotHandler()
def get_response(self,prompt, history):
return self.chat.signChat(history)
def clear_chat_history(self):
st.session_state.messages = [{"role": "assistant", "content": "🍭🍡你好!我是全能创作助手~小汐🥰,可以帮助您完善补充文案细节?🧐"}]
def page(self):
# 主聊天对话窗口
prompt = st.chat_input(placeholder="请输入对话")
if "messages" not in st.session_state.keys():
st.session_state.messages = [{"role": "assistant", "content": "🍭🍡你好!我是全能创作助手~小汐🥰,可以帮助您完善补充文案细节?🧐"}]
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.write(message["content"])
if prompt:
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.write(prompt)
if st.session_state.messages[-1]["role"] != "assistant":
with st.chat_message("assistant"):
with st.spinner("Thinking..."):
try:
response = "我是返回的结果,你好"
except Exception as e:
print(e)
response = "哦┗|`O′|┛ 嗷~~,出错了,请稍后再试!😥"
placeholder = st.empty()
full_response = ''
for item in response:
full_response += item
time.sleep(0.01)
placeholder.markdown(full_response)
placeholder.markdown(full_response)
message = {"role": "assistant", "content": full_response}
st.session_state.messages.append(message)
st.button('清空历史对话', on_click=self.clear_chat_history)
那么在这块,我们的重点(后面实现功能的时候)就是:response = "我是返回的结果,你好"
这块代码的返回结果需要配合到我们的真正的AI返回。当然这块为了简便,我们也是实现了打字机特效,只是这个特效的前提不是以流式调用openai得到的,而是一次性拿到结果,然后再本地实现打字机特效进行加载的。这样的话,实现更加简答,而且一次性传输,虽然总体上慢一点,但是开销也小一点。
设置页面🍭
这块的话,我们先聊哪个小说视频页面是怎么实现的,因为这个的话还是比较复杂的。但是我们可以先聊一聊,这个设置页面,这个页面相对简单。 那么在这里的话,我们也是用到了streamlit的布局系统: streamlit默认是垂直布局的,也就是所有的元素默认往下放置的。那么当我们要实现刚刚的这样的效果的时候,就不得不使用到水平布局,使用水平布局非常方便:
python
c1,c2 = st.columns(2)
with c1:
pass
with c2:
pass
这样一来就直接完成了布局,这默认是1:1,所以你还可以这样传递参数:
python
c1,c2 = st.columns([1,2])
with c1:
pass
with c2:
pass
这样的话,左边比右边就是1:2布局。
okey,那么接下来的话,我们直接看到总体代码吧:
python
class NovelSettings(object):
def __init__(self):
self.current_file_path = os.path.abspath(__file__)
self.current_dir = os.path.dirname(self.current_file_path)
def __temp_save_config(self,openai_key,base_url,default_model,mj_api_key,global_temperature):
Config.settings["openai_api_key"] = openai_key
Config.settings["openai_api_base"] = base_url
Config.settings["default_model"] = default_model
Config.settings["image_api_key"] = mj_api_key
Config.settings["temperature"] = global_temperature
st.session_state.settings = Config.settings
def page(self):
# 左侧边栏还是设置,右侧还是音频展示
col1,col2 = st.columns([1, 2])
gap = "50px"
# 为列之间的间隔添加CSS样式
st.markdown(f"<style>.streamlit-column{{ padding-right: {gap}; }}</style>", unsafe_allow_html=True)
with col1:
st.markdown('''
:red[设置仅当前有效哟😎],\n
:green[刷新后回复默认设置😝]''')
# 创建文本输入框
openai_key = st.text_input("请输入你的OpenAI key", value=Config.settings.get("openai_api_key"))
base_url = st.text_input("请输入你的Base Url", value=Config.settings.get("openai_api_base"))
default_model = st.text_input("请输入你的Default Model", value=Config.settings.get("default_model"))
mj_api_key = st.text_input("请输入你的绘画API Key", value=Config.settings.get("image_api_key"))
# 创建数字输入框
global_temperature = st.number_input("设置全局temperature", min_value=0.1, max_value=1.0, step=0.1,
value=Config.settings.get("temperature"))
save_button = st.button("保存设置")
# 这里可以根据需要添加保存设置的逻辑
if save_button:
self.__temp_save_config(openai_key, base_url, default_model, mj_api_key, global_temperature)
show_popup = st.empty()
with st.expander("提示🍡", expanded=True):
st.write(":green[nice,仅当前有效哟~😊。]")
# 添加一个按钮来关闭弹窗
if st.button("关闭"):
show_popup.empty()
with col2:
st.markdown('''
:blue[语音试听🍳]''')
c01,c02,c03 = st.columns(3)
with c01:
st.text("小艺")
st.audio(self.current_dir+r"\..\..\assert\audio\test01.mp3")
st.text("云建")
st.audio(self.current_dir+r"\..\..\assert\audio\test02.mp3")
st.text("云溪")
st.audio(self.current_dir + r"\..\..\assert\audio\test03.mp3")
with c02:
st.text("云霞")
st.audio(self.current_dir+r"\..\..\assert\audio\test04.mp3")
st.text("云阳")
st.audio(self.current_dir + r"\..\..\assert\audio\test05.mp3")
st.text("小北")
st.audio(self.current_dir + r"\..\..\assert\audio\test06.mp3")
with c03:
st.text("小妮")
st.audio(self.current_dir+r"\..\..\assert\audio\test07.mp3")
这里的话,我们用到了关于config的信息,那么关于config的话,其实无法也就这几条:
python
{
"openai_api_key": "key",
"openai_api_base": "https://api.moonshot.cn/v1",
"language": "auto",
"hide_history_when_not_logged_in": true,
"default_model": "moonshot-v1-8k",
"temperature": 0.5,
"multi_api_key": false,
"server_name": "0.0.0.0",
"server_port": 9090,
"autobrowser": false,
"share": false,
"system_xiaoxi": "你是一个全能小助手,你的名字叫小汐,尤其擅长写作和故事改编。",
"image_api_key": "key"
}
只不过是这样读取了一下而已:
python
def getConfig()->dict:
try:
with open(r"./config.json", 'r', encoding="utf-8") as f:
config = json.load(f)
except Exception as e:
try:
current_file_path = os.path.abspath(__file__)
current_dir = os.path.dirname(current_file_path)
with open(current_dir + "/../config.json", 'r', encoding="utf-8") as f:
config = json.load(f)
except Exception as e:
current_file_path = os.path.abspath(__file__)
current_dir = os.path.dirname(current_file_path)
with open(current_dir + "/config.json", 'r', encoding="utf-8") as f:
config = json.load(f)
if ("settings" in st.session_state.keys()):
config = st.session_state.settings
else:
st.session_state.settings = config
return config
# config 变为全局变量
class Config(object):
settings = getConfig()
因为我们设置还是需要将配置里面的一些信息进行展示的😃
视频生成页面🦁
之后的话,就是我们的视频生成页面了,这个部分确实还是比较麻烦的。而且有几个小细节需要注意。当然,总体的页面实现还是不复杂的,我们开始依次进行拆解。
页面布局😃
毫无以为,我们还是先来看到我们的页面布局吧: 框起来的都是意味着,我们使用到了对应的水平布局的:
所以这里废话不多少,我们先来看到我们是怎么吧我们的组件给布置上去的,先不讨论,怎么实现功能。这里我们看到我们专门的page方法。
python
def page(self):
self.col1,self.col2 = st.columns([1,2])
with self.col1:
gen_data = self.__get_gen_data()
self.novel_text = st.text_area(label="文本输入",placeholder="请输入小说文本🎈",
height=380,value=gen_data.get("novel_text"))
self.temperature = st.slider("temperature",min_value=0.2,max_value=1.0,step=0.1,
value=gen_data.get("temperature"),)
self.b_c0,self.b_c1 = st.columns([1,2])
with self.b_c0:
self.template = st.button("模板生成",type="primary")
if(self.template):
self.__gen_model_fn()
with self.col2:
st.markdown("当前版本可直接生成视频,也可导出素材至剪映等剪辑软件ヾ(≧▽≦*)o")
c1,c2,c3,c4,c5,c6 = st.columns(6)
with c1:
self.batch_gen = st.button("批量生成",type="primary",on_click=self.__batch_gen_fn)
with c2:
# self.export_button_jianying = st.button("导出剪映",type="primary",on_click=self.__export_jianying_fn)
self.export_button_jianying = st.button("导出素材",type="primary",on_click=self.__export_source_fn)
with c3:
self.export_button_video = st.button("导出视频",type="primary",on_click=self.__export_video_fn)
with c4:
self.audio_select = st.selectbox("音频选择",("小艺","云建","云溪","云霞","云阳","小北","小妮"))
if self.audio_select:
self.gen_data["audio_select"] = self.audio_select
st.session_state.gen_data = self.gen_data
with c5:
self.language_select = st.selectbox("语言选择",("中文","英文"))
if self.language_select:
self.gen_data["language_select"] = self.language_select
st.session_state.gen_data = self.gen_data
with c6:
self.add_button = st.button("添加",type="primary",on_click=self.__current_add)
# 展示数据的容器
st.markdown("----------------->生成内容👻🦅👇")
self.data_container = st.container(height=400)
data = self.gen_data
for index in range(len(data.get("data"))):
with self.data_container:
# 创建一行多列的布局,现在拿到当前行的数据
c01, c02, c03, c04,c06,c07 = st.columns([4, 3, 2, 2, 2,2])
current_line_data = data.get("data")[index]
with c01:
# 加载图片
if(current_line_data["图片"] != self.default_img):
if(current_line_data["图片"]!=-1):
st.image(current_line_data["图片"] ,caption="生成-成功",)
else:
image = Image.open(self.default_img)
st.image(image, caption="生成-失败")
else:
image = Image.open(self.default_img)
st.image(image, caption="示例")
with c02:
# 加载音频
if (current_line_data["音频"] != self.default_audio):
if(current_line_data["音频"]!=-1):
st.text("生成-成功")
st.audio(current_line_data["音频"])
else:
st.text("生成-失败")
st.audio(self.default_audio)
else:
st.text("示例")
st.audio(self.default_audio)
with c03:
# 查看文本-提示词
st.button("提示"+str(index),on_click=self.c03_button_click,args=(index,current_line_data,))
with c04:
# 查看文本-分段
st.button("分段" + str(index), on_click=self.c04_button_click,args=(index,current_line_data,))
with c06:
if st.button("删除"+str(index)):
self.__current_delete(index)
with c07:
if st.button("生成"+str(index),type="primary"):
self.__current_gen(index)
当然在这里我们还绑定了一些函数,这些函数我们先默认实现都是空,先不管。
数据加载
现在我们看到了我们完成了基本的页面布局,并且把我们的组件都搞上去了。但是细心的你应该是发现了,那就是这部分是动态加载的数据。 那么这块的话,就不得不说回到我们先前说的关于streamlit的特性,那就是我们的streamlit再执行一个方法,按钮(被触发)之后,我们的整个页面会重新刷新,所以如果,你执行完毕之后,能够把数据存起来,那么他会自动刷新页面,然后我们加载的组件又是根据数据来的,这样的话,就完成了我们的数据的动态的添加操作了。那么在这块的话,我们主要看到我们数据张什么样子:
python
self.gen_data = {
"novel_text":"",
"temperature":0.4,
"audio_select": "小艺",
"language_select":"中文",
"data":[
{
"提示词":"prompt0",
"分段":"part0",
"图片":self.default_img,
"音频":self.default_audio
},
{
"提示词": "prompt1",
"分段": "part1",
"图片": self.default_img,
"音频": self.default_audio
},
]
}
那么重点是看到这一块:
那么这里的话,其实就是我们需要唯一注意的点,在页面的展示阶段。当然我们接下来还有几个细节需要注意。
注意细节☠
我们刚刚谈到,关于streamlit的执行机制的问题,因此的话,虽然这个执行机制非常的好,可以帮助我们及时将数据刷新过来,这一点有点类似于vue的响应式。(说到这个,最近也有研究,有机会可以聊聊如何通过proxy+观察者模式实现这个数据的双向绑定)
- text_area 获取输入值,这里我们获取输入值,需要使用这里面绑定的key 至于是为啥,因为这个组件默认就是触发的,所以只能通过这种方式来拿到值,具体的可以思考思考😊并不难想到
- 函数的绑定,同样由于刷新机制的问题,在弹窗当中的按钮绑定事件,只能使用on_click来绑定,才能保证触发。为什么同样是刚刚的原因。总结就是:同一时刻(只能有一个方法运行(按钮))on_click绑定类似于call_back的方式,所以一定会触发。总结就是,当你不确定的时候,直接使用on_click 绑定事件。而不是if来判断触发
那么到这块这边的细节就这些了,在实际实现的时候,还有细节,我们到时候再说。
完整代码🐨
python
import streamlit as st
from streamlit_modal import Modal
modal = Modal(key="Data",title="view😀")
class NovelGenerate:
def __init__(self):
# 在这里定义到我们的数据
self.current_file_path = os.path.abspath(__file__)
self.current_dir = os.path.dirname(self.current_file_path)
self.storyBoardHandler = StoryBoardHandler()
self.default_img = self.current_dir+r"/../../assert/img/wait.jpg"
self.default_audio = self.current_dir + r"\..\..\assert\audio\test01.mp3"
self.sources = self.current_dir+"/../../resource/sources"
self.video_builder = VideoBuilder()
self.exportSource = ExportSource()
self.zip_file_path = self.sources+"/default.zip"
self.gen_data = {
"novel_text":"",
"temperature":0.4,
"audio_select": "小艺",
"language_select":"中文",
"data":[
{
"提示词":"prompt0",
"分段":"part0",
"图片":self.default_img,
"音频":self.default_audio
},
{
"提示词": "prompt1",
"分段": "part1",
"图片": self.default_img,
"音频": self.default_audio
},
]
}
if("gen_data" in st.session_state.keys()):
self.gen_data = st.session_state.gen_data
else:
st.session_state.gen_data = self.gen_data
"""
-- v0.2.5 版本暂不考虑此方案
"""
def __export_jianying_fn(self):
# 导出剪映模板
pass
def __export_source_do(self):
pass
def __export_source_fn(self):
# 导出媒体资源
pass
def __export_video_fn(self):
pass
# 保证我们当前的gen_data和在session里面的是一致的
def __get_gen_data(self):
if ("gen_data" in st.session_state.keys()):
self.gen_data = st.session_state.gen_data
else:
st.session_state.gen_data = self.gen_data
return self.gen_data
def __current_delete(self,index):
# print("删除-当前元素",index)
pass
def __current_add(self):
pass
def __batch_gen_fn(self):
pass
def __current_gen_batch(self,index,condition:list):
pass
def __current_gen(self,index):
pass
def __gen_model_fn(self):
pass
def page(self):
self.col1,self.col2 = st.columns([1,2])
with self.col1:
gen_data = self.__get_gen_data()
self.novel_text = st.text_area(label="文本输入",placeholder="请输入小说文本🎈",
height=380,value=gen_data.get("novel_text"))
self.temperature = st.slider("temperature",min_value=0.2,max_value=1.0,step=0.1,
value=gen_data.get("temperature"),)
self.b_c0,self.b_c1 = st.columns([1,2])
with self.b_c0:
self.template = st.button("模板生成",type="primary")
if(self.template):
self.__gen_model_fn()
with self.col2:
st.markdown("当前版本可直接生成视频,也可导出素材至剪映等剪辑软件ヾ(≧▽≦*)o")
c1,c2,c3,c4,c5,c6 = st.columns(6)
with c1:
self.batch_gen = st.button("批量生成",type="primary",on_click=self.__batch_gen_fn)
with c2:
# self.export_button_jianying = st.button("导出剪映",type="primary",on_click=self.__export_jianying_fn)
self.export_button_jianying = st.button("导出素材",type="primary",on_click=self.__export_source_fn)
with c3:
self.export_button_video = st.button("导出视频",type="primary",on_click=self.__export_video_fn)
with c4:
self.audio_select = st.selectbox("音频选择",("小艺","云建","云溪","云霞","云阳","小北","小妮"))
if self.audio_select:
self.gen_data["audio_select"] = self.audio_select
st.session_state.gen_data = self.gen_data
with c5:
self.language_select = st.selectbox("语言选择",("中文","英文"))
if self.language_select:
self.gen_data["language_select"] = self.language_select
st.session_state.gen_data = self.gen_data
with c6:
self.add_button = st.button("添加",type="primary",on_click=self.__current_add)
# 展示数据的容器
st.markdown("----------------->生成内容👻🦅👇")
self.data_container = st.container(height=400)
data = self.gen_data
for index in range(len(data.get("data"))):
with self.data_container:
# 创建一行多列的布局,现在拿到当前行的数据
c01, c02, c03, c04,c06,c07 = st.columns([4, 3, 2, 2, 2,2])
current_line_data = data.get("data")[index]
with c01:
# 加载图片
if(current_line_data["图片"] != self.default_img):
if(current_line_data["图片"]!=-1):
st.image(current_line_data["图片"] ,caption="生成-成功",)
else:
image = Image.open(self.default_img)
st.image(image, caption="生成-失败")
else:
image = Image.open(self.default_img)
st.image(image, caption="示例")
with c02:
# 加载音频
if (current_line_data["音频"] != self.default_audio):
if(current_line_data["音频"]!=-1):
st.text("生成-成功")
st.audio(current_line_data["音频"])
else:
st.text("生成-失败")
st.audio(self.default_audio)
else:
st.text("示例")
st.audio(self.default_audio)
with c03:
# 查看文本-提示词
st.button("提示"+str(index),on_click=self.c03_button_click,args=(index,current_line_data,))
with c04:
# 查看文本-分段
st.button("分段" + str(index), on_click=self.c04_button_click,args=(index,current_line_data,))
# with c05:
# st.selectbox("音频" + str(index),
# ("小艺", "云建", "云溪", "云霞", "云阳", "小北", "小妮"))
with c06:
if st.button("删除"+str(index)):
self.__current_delete(index)
with c07:
if st.button("生成"+str(index),type="primary"):
self.__current_gen(index)
def c03_button_click(self,index,current_line_data):
pass
def c04_button_click(self,index,current_line_data):
pass
总结
最后,这里还需要注意一点,那就是在项目当中: webui有两个实现,一个是gradio,一个是streamlit。对应gradio是先前的废弃方案,所以请不要关注那个部分😑