如何为Streamlit的st.chat_input()添加类似谷歌搜索的自动补全建议
如何为Streamlit的st.chat_input()添加类似谷歌搜索的自动补全建议
没问题!要给Streamlit的st.chat_input()加上类似谷歌的实时自动补全,确实得借助一点JavaScript或者自定义组件,我给你两种实用的方案,你可以按需选择:
方案一:直接注入JavaScript(简单快捷,无额外依赖)
这种方式不需要安装其他包,直接通过st.markdown注入自定义JS代码,就能给原生的st.chat_input()加上补全功能。
完整代码示例
import streamlit as st # 准备你的自动补全候选词库,可以根据需求动态调整 autocomplete_suggestions = [ "how it work", "how to do data analysis", "how to deploy Streamlit app", "how to use pandas", "how to debug Python code" ] # 初始化会话状态的消息列表(如果还没初始化的话) if "sales_messages" not in st.session_state: st.session_state.sales_messages = [] # 原生的聊天输入框 if query1 := st.chat_input("Ask Here", key="chat1"): with st.spinner("AI is analyzing ..."): try: st.chat_message("user").markdown(query1) st.session_state.sales_messages.append({"role": "user", "content": query1}) # 这里放你的AI响应生成逻辑,比如调用LLM接口 # 示例:st.chat_message("assistant").markdown("这是AI的回复内容") except Exception as e: st.error(f"出错了: {str(e)}") # 注入实现自动补全的JavaScript代码 st.markdown(""" <script> // 等待页面所有元素渲染完成 document.addEventListener('DOMContentLoaded', function() { // 定位到chat_input对应的输入框(通过Streamlit的测试ID和key关联的元素) const inputField = document.querySelector('div[data-testid="stChatInput"][data-key="chat1"] input'); if (!inputField) return; // 补全候选词,和Python端的列表保持同步 const suggestions = """ + str(autocomplete_suggestions).replace("'", "\"") + """; // 创建存放补全建议的下拉容器 const suggestionBox = document.createElement('div'); Object.assign(suggestionBox.style, { position: 'absolute', top: `${inputField.offsetTop + inputField.offsetHeight + 4}px`, left: `${inputField.offsetLeft}px`, width: `${inputField.offsetWidth}px`, backgroundColor: 'white', border: '1px solid #e0e0e0', borderRadius: '4px', boxShadow: '0 2px 8px rgba(0,0,0,0.1)', zIndex: '9999', display: 'none' }); inputField.parentElement.style.position = 'relative'; inputField.parentElement.appendChild(suggestionBox); // 监听输入框的输入事件,实时生成补全建议 inputField.addEventListener('input', function() { const inputText = this.value.trim().toLowerCase(); // 输入为空时隐藏建议框 if (!inputText) { suggestionBox.style.display = 'none'; return; } // 过滤出包含输入文本的候选词 const matchedSuggestions = suggestions.filter(s => s.toLowerCase().includes(inputText)); if (matchedSuggestions.length === 0) { suggestionBox.style.display = 'none'; return; } // 清空并重新渲染建议项 suggestionBox.innerHTML = ''; matchedSuggestions.forEach(suggestion => { const suggestionItem = document.createElement('div'); Object.assign(suggestionItem.style, { padding: '8px 12px', cursor: 'pointer', fontSize: '14px' }); // 鼠标 hover 时的样式 suggestionItem.addEventListener('mouseover', () => { suggestionItem.style.backgroundColor = '#f0f2f6'; }); suggestionItem.addEventListener('mouseout', () => { suggestionItem.style.backgroundColor = 'white'; }); // 点击建议项时填充到输入框并隐藏建议框 suggestionItem.addEventListener('click', () => { inputField.value = suggestion; suggestionBox.style.display = 'none'; // 可选:自动触发回车提交 inputField.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' })); }); suggestionItem.textContent = suggestion; suggestionBox.appendChild(suggestionItem); }); suggestionBox.style.display = 'block'; }); // 点击页面其他区域时关闭建议框 document.addEventListener('click', (e) => { if (!inputField.contains(e.target) && !suggestionBox.contains(e.target)) { suggestionBox.style.display = 'none'; } }); }); </script> """, unsafe_allow_html=True)
方案要点说明
- 我们通过
document.querySelector精准定位到指定key的st.chat_input输入框,避免影响页面其他输入元素 - JS中的候选词和Python端的列表保持同步,你也可以从
st.session_state动态传递更新后的候选词 - 实时监听输入事件,过滤匹配的建议项,点击建议即可快速填充内容,还支持自动提交
- 加入了点击页面其他区域关闭建议框的交互,提升用户体验
方案二:用自定义组件实现(更灵活,适合复杂场景)
如果你的补全逻辑比较复杂(比如需要从后端异步获取建议、自定义样式需求高),可以用streamlit.components.v1创建专属的带补全功能的聊天输入组件。
完整代码示例
import streamlit as st import streamlit.components.v1 as components def chat_input_with_autocomplete(placeholder: str, key: str, suggestions: list): """自定义带自动补全的聊天输入框组件""" component_html = f""" <div style="position: relative; width: 100%;"> <input type="text" id="{key}-input" placeholder="{placeholder}" style="width: 100%; padding: 10px; border-radius: 8px; border: 1px solid #ddd; font-size: 14px;" > <div id="{key}-suggestions" style="position: absolute; top: 42px; left: 0; width: 100%; background: white; border: 1px solid #e0e0e0; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); display: none; z-index: 999;"></div> </div> <script> const input = document.getElementById('{key}-input'); const suggestionsBox = document.getElementById('{key}-suggestions'); const suggestions = {str(suggestions).replace("'", "\"")}; // 实时生成补全建议 input.addEventListener('input', function() {{ const inputText = this.value.trim().toLowerCase(); if (!inputText) {{ suggestionsBox.style.display = 'none'; return; }} // 过滤匹配的建议 const matchedSuggestions = suggestions.filter(s => s.toLowerCase().includes(inputText)); if (matchedSuggestions.length === 0) {{ suggestionsBox.style.display = 'none'; return; }} // 渲染建议项 suggestionsBox.innerHTML = matchedSuggestions.map(suggestion => ` <div style="padding: 10px; cursor: pointer; font-size: 14px;" onmouseover="this.style.backgroundColor='#f0f2f6'" onmouseout="this.style.backgroundColor='white'" onclick="selectSuggestion('${suggestion}')"> ${suggestion} </div> `).join(''); suggestionsBox.style.display = 'block'; }}); // 选择建议项并传递值回Streamlit function selectSuggestion(selectedText) {{ input.value = selectedText; suggestionsBox.style.display = 'none'; // 把选中的值发送给Streamlit window.parent.postMessage({{ type: 'streamlit:setComponentValue', value: selectedText }}, '*'); }} // 监听回车提交 input.addEventListener('keydown', function(e) {{ if (e.key === 'Enter' && this.value.trim()) {{ window.parent.postMessage({{ type: 'streamlit:setComponentValue', value: this.value.trim() }}, '*'); this.value = ''; }} }}); </script> """ # 渲染组件并获取返回值 return components.html(component_html, height=60, key=key) # 初始化消息列表 if "sales_messages" not in st.session_state: st.session_state.sales_messages = [] # 补全候选词库 autocomplete_suggestions = [ "how it work", "how to do data analysis", "how to deploy Streamlit app", "how to use pandas" ] # 使用自定义输入组件 user_query = chat_input_with_autocomplete("Ask Here", key="custom-chat-input", suggestions=autocomplete_suggestions) # 处理用户输入 if user_query: with st.spinner("AI is analyzing ..."): st.chat_message("user").markdown(user_query) st.session_state.sales_messages.append({"role": "user", "content": user_query}) # 这里添加你的AI响应逻辑 # st.chat_message("assistant").markdown("AI的回复内容")
方案要点说明
- 自定义组件完全掌控输入框和补全框的样式、交互逻辑,适配复杂需求
- 通过
window.parent.postMessage把用户输入或选中的建议值传递回Streamlit - 支持回车提交选中的内容,和原生
st.chat_input的使用体验保持一致
注意事项
- Streamlit的DOM结构可能会在版本更新时微调,如果发现输入框定位失效,需要调整
querySelector的选择器 - 如果候选词需要动态生成(比如基于用户历史输入、AI的常见问题),可以把候选词存在
st.session_state中,再传递给JS或自定义组件 - 测试时建议开启Streamlit的自动刷新,确保代码修改后能实时看到效果
内容来源于stack exchange
相关产品推荐
相关产品推荐

