| import streamlit as st |
| from huggingface_hub import hf_hub_download |
| from llama_cpp import Llama |
| import time |
|
|
| |
| st.set_page_config( |
| page_title="Llama 3.2 AI Assistant", |
| page_icon="🤖", |
| layout="wide", |
| initial_sidebar_state="expanded" |
| ) |
|
|
| |
| st.markdown(""" |
| <style> |
| /* 隐藏 Streamlit 默认的汉堡菜单和页脚 */ |
| #MainMenu {visibility: hidden;} |
| footer {visibility: hidden;} |
| header {visibility: hidden;} |
| |
| /* 调整主容器的顶部 padding,让内容更紧凑 */ |
| .block-container { |
| padding-top: 2rem; |
| padding-bottom: 2rem; |
| } |
| |
| /* 美化侧边栏 */ |
| section[data-testid="stSidebar"] { |
| background-color: #f7f9fc; /* 浅灰蓝背景 */ |
| } |
| |
| /* 自定义标题样式 */ |
| .title-text { |
| font-family: 'Helvetica Neue', sans-serif; |
| font-weight: 700; |
| font-size: 2.5rem; |
| color: #1E88E5; /* 科技蓝 */ |
| text-align: center; |
| margin-bottom: 20px; |
| } |
| |
| .subtitle-text { |
| font-family: 'Helvetica Neue', sans-serif; |
| font-weight: 400; |
| font-size: 1.1rem; |
| color: #666; |
| text-align: center; |
| margin-bottom: 40px; |
| } |
| </style> |
| """, unsafe_allow_html=True) |
|
|
| |
| st.markdown('<div class="title-text">🤖 Llama 3.2-3B AI Assistant</div>', unsafe_allow_html=True) |
| st.markdown('<div class="subtitle-text">Powered by Marcus719/Llama-3.2-3B-changedata-Lab2-GGUF</div>', unsafe_allow_html=True) |
|
|
| |
| with st.sidebar: |
| st.image("https://huggingface.co/front/assets/huggingface_logo-noborder.svg", width=50) |
| st.header("⚙️ 控制面板") |
| |
| |
| temperature = st.slider("Temperature (创造性)", min_value=0.1, max_value=1.5, value=0.7, step=0.1, help="值越高,回答越随机;值越低,回答越严谨。") |
| max_tokens = st.slider("Max Tokens (最大长度)", min_value=64, max_value=2048, value=512, step=64) |
| |
| st.divider() |
| |
| |
| system_prompt = st.text_area( |
| "系统设定 (System Prompt)", |
| value="You are a helpful and polite AI assistant.", |
| height=100 |
| ) |
| |
| st.divider() |
| |
| |
| if st.button("🗑️ 清除对话历史", use_container_width=True): |
| st.session_state.messages = [] |
| st.rerun() |
|
|
| st.markdown("---") |
| st.markdown("Optimization: **Unsloth Q4_K_M**") |
|
|
| |
| REPO_ID = "Marcus719/Llama-3.2-3B-changedata-Lab2-GGUF" |
| FILENAME = "unsloth.Q4_K_M.gguf" |
|
|
| @st.cache_resource |
| def load_model(): |
| model_path = hf_hub_download(repo_id=REPO_ID, filename=FILENAME) |
| llm = Llama( |
| model_path=model_path, |
| n_ctx=4096, |
| n_threads=2, |
| verbose=False |
| ) |
| return llm |
|
|
| try: |
| if "llm" not in st.session_state: |
| with st.spinner("🚀 正在启动 AI 引擎,请稍候..."): |
| st.session_state.llm = load_model() |
| except Exception as e: |
| st.error(f"模型加载失败: {e}") |
|
|
| |
|
|
| |
| if "messages" not in st.session_state: |
| st.session_state.messages = [] |
|
|
| |
| for message in st.session_state.messages: |
| |
| avatar = "🧑💻" if message["role"] == "user" else "🤖" |
| with st.chat_message(message["role"], avatar=avatar): |
| st.markdown(message["content"]) |
|
|
| |
| if prompt := st.chat_input("在此输入您的问题..."): |
| |
| st.session_state.messages.append({"role": "user", "content": prompt}) |
| with st.chat_message("user", avatar="🧑💻"): |
| st.markdown(prompt) |
|
|
| |
| with st.chat_message("assistant", avatar="🤖"): |
| message_placeholder = st.empty() |
| full_response = "" |
| |
| |
| messages_payload = [{"role": "system", "content": system_prompt}] + [ |
| {"role": m["role"], "content": m["content"]} |
| for m in st.session_state.messages |
| ] |
| |
| stream = st.session_state.llm.create_chat_completion( |
| messages=messages_payload, |
| stream=True, |
| max_tokens=max_tokens, |
| temperature=temperature |
| ) |
| |
| for chunk in stream: |
| if "content" in chunk["choices"][0]["delta"]: |
| token = chunk["choices"][0]["delta"]["content"] |
| full_response += token |
| |
| message_placeholder.markdown(full_response + "▌") |
| |
| message_placeholder.markdown(full_response) |
| |
| |
| st.session_state.messages.append({"role": "assistant", "content": full_response}) |