| 73 |
Streamlit基本API |
<h4 style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain md-expand" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">1、组件使用方法</span></h4>
<h5 class="md-end-block md-heading" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">1.1 运行代码</span></h5>
<pre class=""><code class="hljs language-python"># 创建第一个应用(app.py)
import streamlit as st
st.title("我的第一个Streamlit应用")
st.write("你好,世界!")
# 在终端运行
streamlit run app.py
streamlit hello</code></pre>
<p> </p>
<h5 class="md-end-block md-heading" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">1.2 文本组件</span></h5>
<pre class=""><code class="language-python hljs">st.title("主标题") # 主标题
st.header("章节标题") # 大标题
st.subheader("子标题") # 子标题
st.text("普通文本") # 普通文本
st.write("万能文本/变量") # 显示任何对象
st.markdown("**Markdown**支持") # Markdown语法</code></pre>
<p> </p>
<h5 class="md-end-block md-heading" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">1.3 数据展示组件</span></h5>
<pre class=""><code class="language-python hljs">st.dataframe(pd.DataFrame()) # 交互式表格
st.table([1,2,3]) # 静态表格
st.json({"key": "value"}) # 显示JSON格式</code></pre>
<p> </p>
<h5 class="md-end-block md-heading md-focus" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain md-expand" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">1.4 输入控件</span></h5>
<pre class=""><code class="language-python hljs">text = st.text_input("输入文本") # 文本输入
number = st.number_input("输入数字") # 数字输入
date = st.date_input("选择日期") # 日期选择
time = st.time_input("选择时间") # 时间选择
is_checked = st.checkbox("复选框") # 复选框
selected = st.radio("单选按钮", ['1', '2', '3', '4']) # 单选按钮
multi = st.multiselect("多选", ['1', '2', '3', '4']) # 多选下拉
slider = st.slider("滑块", 0, 100) # 滑块
st.button("确认") # 按钮
st.file_uploader("上传文件") # 文件上传</code></pre>
<p> </p>
<h4 class="md-end-block md-heading" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">2、布局使用</span></h4>
<h5 class="md-end-block md-heading md-focus" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">2.1 侧边栏</span></h5>
<pre class=""><code class="language-python hljs"># 所有输入组件添加sidebar前缀即可放入侧边栏
st.sidebar.selectbox("选项", ['1', '2', '3', '4'])</code></pre>
<p> </p>
<h5 class="md-end-block md-heading" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">2.2 分列布局</span></h5>
<pre class=""><code class="language-python hljs">col1, col2 = st.columns(2) # 创建两列
with col1:
st.write("第一列内容")
with col2:
st.write("第二列内容")</code></pre>
<p> </p>
<h5 class="md-end-block md-heading md-focus" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain md-expand" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">2.3 标签页</span></h5>
<pre class=""><code class="language-python hljs">tab1, tab2 = st.tabs(["主页", "分析"])
with tab1:
st.write("主页内容")
with tab2:
st.write("分析内容")</code></pre>
<p> </p>
<h5 class="md-end-block md-heading" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">2.4 容器</span></h5>
<pre class=""><code class="language-python hljs">container = st.container()
container.write("容器内的内容")</code></pre>
<p> </p>
<h4 class="md-end-block md-heading" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; white-space-collapse: preserve; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; line-height: 1.4; cursor: text; font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif;"><span class="md-plain" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000;">3、 项目页面</span></h4>
<pre class=""><code class="language-python hljs">import streamlit as st
# 页面配置
st.set_page_config(
page_title="智能文档检索助手",
page_icon="🤖",
layout="wide",
initial_sidebar_state="collapsed"
)
# 自定义CSS样式
st.markdown("""
<style>
/* 聊天容器 */
.chat-container {
background: white;
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
margin: 20px auto;
max-width: 800px;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 头部样式 */
.chat-header {
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
text-align: center;
border-radius: 12px 12px 0 0;
}
.chat-title {
font-size: 24px;
font-weight: 600;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.chat-subtitle {
font-size: 14px;
opacity: 0.9;
margin-top: 5px;
}
/* 聊天消息区域 */
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #f8f9fa;
}
/* 消息样式 */
.message {
margin-bottom: 16px;
display: flex;
align-items: flex-start;
gap: 12px;
}
.message.user {
flex-direction: row-reverse;
}
.message-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
.user-avatar {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.assistant-avatar {
background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
color: white;
}
.message-content {
max-width: 70%;
padding: 12px 16px;
border-radius: 18px;
font-size: 14px;
line-height: 1.4;
}
.user-message {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-bottom-right-radius: 4px;
}
.assistant-message {
background: white;
color: #333;
border: 1px solid #e1e5e9;
border-bottom-left-radius: 4px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
/* 流式输出动画 */
.streaming-cursor::after {
content: '▊';
animation: blink 1s infinite;
color: #667eea;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/* 文档卡片样式 */
.doc-card {
background: 000000;
border: 1px solid #e1e5e9;
border-radius: 8px;
padding: 12px;
margin: 8px 0;
}
.doc-card:hover {
border-color: #667eea;
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1);
}
/* 状态指示器 */
.status-indicator {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
}
.status-rag {
background: #e3f2fd;
color: #1976d2;
}
.status-normal {
background: #f3e5f5;
color: #7b1fa2;
}
/* 隐藏Streamlit默认元素 */
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
header {visibility: hidden;}
/* 自定义按钮样式 */
.stButton > button {
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
padding: 8px 16px;
font-weight: 500;
transition: all 0.2s;
}
.stButton > button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
/* 响应式设计 */
@media (max-width: 768px) {
.chat-container {
margin: 10px;
height: 85vh;
}
.message-content {
max-width: 85%;
}
}
</style>
""", unsafe_allow_html=True)
def display_message(role, content, docs=None):
"""显示静态消息"""
message_class = "message user" if role == "user" else "message"
avatar_class = "user-avatar" if role == "user" else "assistant-avatar"
content_class = "user-message" if role == "user" else "assistant-message"
avatar_icon = "👤" if role == "user" else "🤖"
st.markdown(f"""
<div class="{message_class}">
<div class="message-avatar {avatar_class}">
{avatar_icon}
</div>
<div class="message-content {content_class}">
{content}
</div>
</div>
""", unsafe_allow_html=True)
def main():
# 侧边栏
with st.sidebar:
st.markdown("### 📁 文档管理")
# 文档上传
uploaded_files = st.file_uploader(
"上传知识库文档",
type=['pdf', 'docx', 'txt'],
accept_multiple_files=True,
help="支持 PDF、Word 和txt文件"
)
if uploaded_files:
for uploaded_file in uploaded_files:
if st.button(f"📤 处理 {uploaded_file.name}", key=f"process_{uploaded_file.name}"):
st.rerun()
st.markdown("---")
# 已有文档
st.markdown("### 📚 知识库")
documents = [{'filename': '1.txt', 'id': 1, 'created_at': {'strftime': '1:20'}, 'chunk_count': 10},
{'filename': '2.txt', 'chunk_count': 10, 'id': 2, 'created_at': {'strftime': '1:20'}}]
if documents:
doc_options = {f"{doc['filename']}": doc['id'] for doc in documents}
selected_docs = st.multiselect(
"选择知识源",
options=list(doc_options.keys()),
help="选择后将基于文档内容回答问题"
)
selected_doc_ids = [doc_options[doc] for doc in selected_docs]
# 显示文档列表
for doc in documents:
st.markdown(f"""
<div class="doc-card">
<strong>📄 {doc['filename']}</strong><br>
<small>📅 {doc['created_at']['strftime']}</small><br>
<small>📊 {doc['chunk_count']} 个文档块</small>
</div>
""", unsafe_allow_html=True)
else:
st.info("暂无文档,请先上传")
selected_doc_ids = []
total_docs = len(documents) if documents else 0
st.metric("📊 文档数", total_docs)
if st.button("🗑️ 清空对话"):
st.rerun()
# 主聊天界面
st.markdown("""
<div class="chat-container">
<div class="chat-header">
<div class="chat-title">
🤖 智能文档检索助手
</div>
<div class="chat-subtitle">
基于知识库的智能问答系统
</div>
</div>
</div>
""", unsafe_allow_html=True)
# 状态显示
col1, col2 = st.columns([2, 1])
with col1:
if selected_doc_ids:
st.markdown(f"""
<div class="status-indicator status-rag">
🔍 知识库模式 ({len(selected_doc_ids)} 个文档)
</div>
""", unsafe_allow_html=True)
else:
st.markdown("""
<div class="status-indicator status-normal">
💭 普通对话模式
</div>
""", unsafe_allow_html=True)
# 聊天消息显示区域
chat_container = st.container()
with chat_container:
# 欢迎消息
st.markdown("""
<div class="message">
<div class="message-avatar assistant-avatar">🤖</div>
<div class="message-content assistant-message">
👋 你好!我是你的AI智能助手。<br><br>
💡 <strong>我能做什么:</strong><br>
• 📚 基于你上传的文档回答问题<br>
• 💬 进行日常对话交流<br>
• 🔍 提供准确的信息检索<br><br>
请上传文档或直接开始对话吧!
</div>
</div>
""", unsafe_allow_html=True)
# 用户输入
if prompt := st.chat_input("💬 输入你的问题..."):
# 显示用户消息
display_message("user", prompt)
print(prompt)
if __name__ == "__main__":
main()</code></pre> |
1 |
58 |
1 |
4/1/26, 4:58 PM |
4/1/26, 5:03 PM |
View Edit Delete |