附源代码:
# -*- coding: utf-8 -*-
import streamlit as st
import pandas as pd
import sqlite3
from jinja2 import Template
import os
import base64
# Initialize session state for questions and answers
if 'questions' not in st.session_state:
st.session_state.questions = []
if 'answers' not in st.session_state:
st.session_state.answers = {}
# Database initialization
def init_db():
conn = sqlite3.connect('poll.db')
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS questions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question TEXT NOT NULL
)
''')
c.execute('''
CREATE TABLE IF NOT EXISTS options (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question_id INTEGER,
option_text TEXT NOT NULL,
votes INTEGER DEFAULT 0,
FOREIGN KEY(question_id) REFERENCES questions(id)
)
''')
conn.commit()
conn.close()
init_db()
# Save questions and options to the database
def save_to_db(question, options):
conn = sqlite3.connect('poll.db')
c = conn.cursor()
c.execute("INSERT INTO questions (question) VALUES (?)", (question,))
question_id = c.lastrowid
for option in options:
c.execute("INSERT INTO options (question_id, option_text) VALUES (?, ?)", (question_id, option))
conn.commit()
conn.close()
# Load questions and options from the database
def load_from_db():
conn = sqlite3.connect('poll.db')
c = conn.cursor()
c.execute("SELECT * FROM questions")
questions = c.fetchall()
st.session_state.questions = [q[1] for q in questions]
for q in questions:
question_id = q[0]
c.execute("SELECT option_text, votes FROM options WHERE question_id=?", (question_id,))
options = c.fetchall()
if q[1] not in st.session_state.answers:
st.session_state.answers[q[1]] = {}
for opt in options:
st.session_state.answers[q[1]][opt[0]] = opt[1]
conn.close()
# Delete a question from the database
def delete_from_db(question):
conn = sqlite3.connect('poll.db')
c = conn.cursor()
c.execute("SELECT id FROM questions WHERE question=?", (question,))
question_id = c.fetchone()[0]
c.execute("DELETE FROM options WHERE question_id=?", (question_id,))
c.execute("DELETE FROM questions WHERE id=?", (question_id,))
conn.commit()
conn.close()
# Add a question
def add_question():
question = st.text_input("输入题目:", key="new_question")
options = []
for i in range(4):
option = st.text_input(f"Option {i+1}:", key=f"option_{i}")
options.append(option)
if st.button("Add Question"):
if question and all(options):
st.session_state.questions.append(question)
st.session_state.answers[question] = {opt: 0 for opt in options}
save_to_db(question, options)
st.success("题目添加成功!")
else:
st.warning("请填写问题和所有选项。")
# Display questions and allow voting
def display_questions():
for idx, q in enumerate(st.session_state.questions):
st.subheader(f"Question {idx + 1}: {q}")
cols = st.columns(len(st.session_state.answers[q]))
for i, (option, count) in enumerate(st.session_state.answers[q].items()):
with cols[i]:
new_count = st.number_input(f"{option}", min_value=0, value=count, step=1, key=f"count_{q}_{option}")
st.session_state.answers[q][option] = new_count
total_votes = sum(st.session_state.answers[q].values())
if total_votes > 0:
st.write("投票分布:")
data = {
"Option": list(st.session_state.answers[q].keys()),
"Votes": list(st.session_state.answers[q].values()),
"Percentage": [f"{(v / total_votes * 100):.2f}%" for v in st.session_state.answers[q].values()]
}
df = pd.DataFrame(data)
st.table(df)
# Export to HTML button
if st.button(f"导出为HTML {idx + 1}", key=f"export_html_{idx}"):
html_content = export_to_html(q, st.session_state.answers[q])
b64 = base64.b64encode(html_content.encode()).decode()
href = f'<a href="data:text/html;base64,{b64}" download="{q.replace(" ", "_")}.html">下载 HTML 文件</a>'
st.markdown(href, unsafe_allow_html=True)
# Export data to HTML
def export_to_html(question, answers):
template = Template("""
<html>
<head>
<title>{{ question }}</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
font-family: Arial, sans-serif;
}
h1 {
color: red;
text-align: center;
}
table {
width: 1000px;
margin: auto;
border-collapse: collapse;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: center;
}
</style>
</head>
<body>
<div style="text-align: center;">
<h1>{{ question }}</h1>
<table>
<tr>
<th>选项</th>
<th>票数</th>
<th>百分比</th>
</tr>
{% for option, votes in answers.items() %}
<tr>
<td>{{ option }}</td>
<td>{{ votes }}</td>
<td>{% if total_votes > 0 %}{{ "%.2f"|format((votes / total_votes * 100)) }}%{% else %}0.00%{% endif %}</td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
""")
total_votes = sum(answers.values())
html_content = template.render(question=question, answers=answers, total_votes=total_votes)
return html_content
# Delete a question
def delete_question():
if st.session_state.questions:
question_index = st.selectbox("选择要删除的问题序号:", list(range(1, len(st.session_state.questions) + 1)))
if st.button("Delete Question"):
question_to_delete = st.session_state.questions[question_index - 1]
delete_from_db(question_to_delete)
st.session_state.questions.remove(question_to_delete)
del st.session_state.answers[question_to_delete]
st.success("问题删除成功!")
load_from_db() # Refresh the session state after deletion
# Main function
def main():
st.title("实时统计系统1.0版")
menu = ["Add Question", "View Statistics", "Delete Question"]
choice = st.sidebar.selectbox("菜单", menu)
load_from_db()
if choice == "Add Question":
add_question()
elif choice == "View Statistics":
display_questions()
elif choice == "Delete Question":
delete_question()
if __name__ == "__main__":
main()