├── .github
└── workflows
│ └── main_rag-llm-app.yml
├── .gitignore
├── app.py
├── docs
├── test_rag.docx
└── test_rag.pdf
├── rag_langchain.ipynb
├── rag_methods.py
├── readme.md
└── requirements.txt
/.github/workflows/main_rag-llm-app.yml:
--------------------------------------------------------------------------------
1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
2 | # More GitHub Actions for Azure: https://github.com/Azure/actions
3 | # More info on Python, GitHub Actions, and Azure App Service: https://aka.ms/python-webapps-actions
4 |
5 | name: Build and deploy Python app to Azure Web App - rag-llm-app
6 |
7 | on:
8 | push:
9 | branches:
10 | - main
11 | workflow_dispatch:
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 |
20 | - name: Set up Python version
21 | uses: actions/setup-python@v5
22 | with:
23 | python-version: '3.11'
24 |
25 | - name: Create and start virtual environment
26 | run: |
27 | python -m venv venv
28 | source venv/bin/activate
29 |
30 | - name: Install dependencies
31 | run: pip install -r requirements.txt
32 |
33 | # Optional: Add step to run tests here (PyTest, Django test suites, etc.)
34 |
35 | - name: Zip artifact for deployment
36 | run: zip release.zip ./* -r
37 |
38 | - name: Upload artifact for deployment jobs
39 | uses: actions/upload-artifact@v4
40 | with:
41 | name: python-app
42 | path: |
43 | release.zip
44 | !venv/
45 |
46 | deploy:
47 | runs-on: ubuntu-latest
48 | needs: build
49 | environment:
50 | name: 'Production'
51 | url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
52 | permissions:
53 | id-token: write #This is required for requesting the JWT
54 |
55 | steps:
56 | - name: Download artifact from build job
57 | uses: actions/download-artifact@v4
58 | with:
59 | name: python-app
60 |
61 | - name: Unzip artifact for deployment
62 | run: unzip release.zip
63 |
64 |
65 | - name: Login to Azure
66 | uses: azure/login@v2
67 | with:
68 | client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_DADA0F825468491B91414F048ED75E1B }}
69 | tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_CD485A2DB50940FAAAF527825D4B219A }}
70 | subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_445C0D64490F418BA1DC65D345764FE5 }}
71 |
72 | - name: 'Deploy to Azure Web App'
73 | uses: azure/webapps-deploy@v3
74 | id: deploy-to-webapp
75 | with:
76 | app-name: 'rag-llm-app'
77 | slot-name: 'Production'
78 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | venv*/
2 | .env
3 | __pycache__
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import os
3 | import dotenv
4 | import uuid
5 |
6 | # check if it's linux so it works on Streamlit Cloud
7 | if os.name == 'posix':
8 | __import__('pysqlite3')
9 | import sys
10 | sys.modules['sqlite3'] = sys.modules.pop('pysqlite3')
11 |
12 | from langchain_openai import ChatOpenAI, AzureChatOpenAI
13 | from langchain_anthropic import ChatAnthropic
14 | from langchain.schema import HumanMessage, AIMessage
15 |
16 | from rag_methods import (
17 | load_doc_to_db,
18 | load_url_to_db,
19 | stream_llm_response,
20 | stream_llm_rag_response,
21 | )
22 |
23 | dotenv.load_dotenv()
24 |
25 | if "AZ_OPENAI_API_KEY" not in os.environ:
26 | MODELS = [
27 | # "openai/o1-mini",
28 | "openai/gpt-4o",
29 | "openai/gpt-4o-mini",
30 | "anthropic/claude-3-5-sonnet-20240620",
31 | ]
32 | else:
33 | MODELS = ["azure-openai/gpt-4o"]
34 |
35 |
36 | st.set_page_config(
37 | page_title="RAG LLM app?",
38 | page_icon="📚",
39 | layout="centered",
40 | initial_sidebar_state="expanded"
41 | )
42 |
43 |
44 | # --- Header ---
45 | st.html("""
📚🔍 Do your LLM even RAG bro? 🤖💬
""")
46 |
47 |
48 | # --- Initial Setup ---
49 | if "session_id" not in st.session_state:
50 | st.session_state.session_id = str(uuid.uuid4())
51 |
52 | if "rag_sources" not in st.session_state:
53 | st.session_state.rag_sources = []
54 |
55 | if "messages" not in st.session_state:
56 | st.session_state.messages = [
57 | {"role": "user", "content": "Hello"},
58 | {"role": "assistant", "content": "Hi there! How can I assist you today?"}
59 | ]
60 |
61 |
62 | # --- Side Bar LLM API Tokens ---
63 | with st.sidebar:
64 | if "AZ_OPENAI_API_KEY" not in os.environ:
65 | default_openai_api_key = os.getenv("OPENAI_API_KEY") if os.getenv("OPENAI_API_KEY") is not None else "" # only for development environment, otherwise it should return None
66 | with st.popover("🔐 OpenAI"):
67 | openai_api_key = st.text_input(
68 | "Introduce your OpenAI API Key (https://platform.openai.com/)",
69 | value=default_openai_api_key,
70 | type="password",
71 | key="openai_api_key",
72 | )
73 |
74 | default_anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") if os.getenv("ANTHROPIC_API_KEY") is not None else ""
75 | with st.popover("🔐 Anthropic"):
76 | anthropic_api_key = st.text_input(
77 | "Introduce your Anthropic API Key (https://console.anthropic.com/)",
78 | value=default_anthropic_api_key,
79 | type="password",
80 | key="anthropic_api_key",
81 | )
82 | else:
83 | openai_api_key, anthropic_api_key = None, None
84 | st.session_state.openai_api_key = None
85 | az_openai_api_key = os.getenv("AZ_OPENAI_API_KEY")
86 | st.session_state.az_openai_api_key = az_openai_api_key
87 |
88 |
89 | # --- Main Content ---
90 | # Checking if the user has introduced the OpenAI API Key, if not, a warning is displayed
91 | missing_openai = openai_api_key == "" or openai_api_key is None or "sk-" not in openai_api_key
92 | missing_anthropic = anthropic_api_key == "" or anthropic_api_key is None
93 | if missing_openai and missing_anthropic and ("AZ_OPENAI_API_KEY" not in os.environ):
94 | st.write("#")
95 | st.warning("⬅️ Please introduce an API Key to continue...")
96 |
97 | else:
98 | # Sidebar
99 | with st.sidebar:
100 | st.divider()
101 | models = []
102 | for model in MODELS:
103 | if "openai" in model and not missing_openai:
104 | models.append(model)
105 | elif "anthropic" in model and not missing_anthropic:
106 | models.append(model)
107 | elif "azure-openai" in model:
108 | models.append(model)
109 |
110 | st.selectbox(
111 | "🤖 Select a Model",
112 | options=models,
113 | key="model",
114 | )
115 |
116 | cols0 = st.columns(2)
117 | with cols0[0]:
118 | is_vector_db_loaded = ("vector_db" in st.session_state and st.session_state.vector_db is not None)
119 | st.toggle(
120 | "Use RAG",
121 | value=is_vector_db_loaded,
122 | key="use_rag",
123 | disabled=not is_vector_db_loaded,
124 | )
125 |
126 | with cols0[1]:
127 | st.button("Clear Chat", on_click=lambda: st.session_state.messages.clear(), type="primary")
128 |
129 | st.header("RAG Sources:")
130 |
131 | # File upload input for RAG with documents
132 | st.file_uploader(
133 | "📄 Upload a document",
134 | type=["pdf", "txt", "docx", "md"],
135 | accept_multiple_files=True,
136 | on_change=load_doc_to_db,
137 | key="rag_docs",
138 | )
139 |
140 | # URL input for RAG with websites
141 | st.text_input(
142 | "🌐 Introduce a URL",
143 | placeholder="https://example.com",
144 | on_change=load_url_to_db,
145 | key="rag_url",
146 | )
147 |
148 | with st.expander(f"📚 Documents in DB ({0 if not is_vector_db_loaded else len(st.session_state.rag_sources)})"):
149 | st.write([] if not is_vector_db_loaded else [source for source in st.session_state.rag_sources])
150 |
151 |
152 | # Main chat app
153 | model_provider = st.session_state.model.split("/")[0]
154 | if model_provider == "openai":
155 | llm_stream = ChatOpenAI(
156 | api_key=openai_api_key,
157 | model_name=st.session_state.model.split("/")[-1],
158 | temperature=0.3,
159 | streaming=True,
160 | )
161 | elif model_provider == "anthropic":
162 | llm_stream = ChatAnthropic(
163 | api_key=anthropic_api_key,
164 | model=st.session_state.model.split("/")[-1],
165 | temperature=0.3,
166 | streaming=True,
167 | )
168 | elif model_provider == "azure-openai":
169 | llm_stream = AzureChatOpenAI(
170 | azure_endpoint=os.getenv("AZ_OPENAI_ENDPOINT"),
171 | openai_api_version="2024-02-15-preview",
172 | model_name=st.session_state.model.split("/")[-1],
173 | openai_api_key=os.getenv("AZ_OPENAI_API_KEY"),
174 | openai_api_type="azure",
175 | temperature=0.3,
176 | streaming=True,
177 | )
178 |
179 | for message in st.session_state.messages:
180 | with st.chat_message(message["role"]):
181 | st.markdown(message["content"])
182 |
183 | if prompt := st.chat_input("Your message"):
184 | st.session_state.messages.append({"role": "user", "content": prompt})
185 | with st.chat_message("user"):
186 | st.markdown(prompt)
187 |
188 | with st.chat_message("assistant"):
189 | message_placeholder = st.empty()
190 | full_response = ""
191 |
192 | messages = [HumanMessage(content=m["content"]) if m["role"] == "user" else AIMessage(content=m["content"]) for m in st.session_state.messages]
193 |
194 | if not st.session_state.use_rag:
195 | st.write_stream(stream_llm_response(llm_stream, messages))
196 | else:
197 | st.write_stream(stream_llm_rag_response(llm_stream, messages))
198 |
199 |
200 | with st.sidebar:
201 | st.divider()
202 | st.video("https://youtu.be/abMwFViFFhI")
203 | st.write("📋[Medium Blog](https://medium.com/@enricdomingo/program-a-rag-llm-chat-app-with-langchain-streamlit-o1-gtp-4o-and-claude-3-5-529f0f164a5e)")
204 | st.write("📋[GitHub Repo](https://github.com/enricd/rag_llm_app)")
205 |
206 |
207 |
--------------------------------------------------------------------------------
/docs/test_rag.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enricd/rag_llm_app/660b044cec7eeb0755791cfe5c81771a96b0a142/docs/test_rag.docx
--------------------------------------------------------------------------------
/docs/test_rag.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enricd/rag_llm_app/660b044cec7eeb0755791cfe5c81771a96b0a142/docs/test_rag.pdf
--------------------------------------------------------------------------------
/rag_langchain.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stderr",
10 | "output_type": "stream",
11 | "text": [
12 | "USER_AGENT environment variable not set, consider setting it to identify your requests.\n"
13 | ]
14 | },
15 | {
16 | "data": {
17 | "text/plain": [
18 | "True"
19 | ]
20 | },
21 | "execution_count": 1,
22 | "metadata": {},
23 | "output_type": "execute_result"
24 | }
25 | ],
26 | "source": [
27 | "import os\n",
28 | "import dotenv\n",
29 | "from pathlib import Path\n",
30 | "\n",
31 | "from langchain_core.messages import AIMessage, HumanMessage\n",
32 | "from langchain_community.document_loaders.text import TextLoader\n",
33 | "from langchain_community.document_loaders import (\n",
34 | " WebBaseLoader, \n",
35 | " PyPDFLoader, \n",
36 | " Docx2txtLoader,\n",
37 | ")\n",
38 | "from langchain_community.vectorstores import Chroma\n",
39 | "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
40 | "from langchain_openai import OpenAIEmbeddings, ChatOpenAI\n",
41 | "from langchain_anthropic import ChatAnthropic\n",
42 | "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
43 | "from langchain.chains import create_history_aware_retriever, create_retrieval_chain\n",
44 | "from langchain.chains.combine_documents import create_stuff_documents_chain\n",
45 | "\n",
46 | "dotenv.load_dotenv()"
47 | ]
48 | },
49 | {
50 | "cell_type": "code",
51 | "execution_count": 2,
52 | "metadata": {},
53 | "outputs": [],
54 | "source": [
55 | "# Load docs\n",
56 | "\n",
57 | "doc_paths = [\n",
58 | " \"docs/test_rag.pdf\",\n",
59 | " \"docs/test_rag.docx\",\n",
60 | "]\n",
61 | "\n",
62 | "docs = [] \n",
63 | "for doc_file in doc_paths:\n",
64 | " file_path = Path(doc_file)\n",
65 | "\n",
66 | " try:\n",
67 | " if doc_file.endswith(\".pdf\"):\n",
68 | " loader = PyPDFLoader(file_path)\n",
69 | " elif doc_file.endswith(\".docx\"):\n",
70 | " loader = Docx2txtLoader(file_path)\n",
71 | " elif doc_file.endswith(\".txt\") or doc_file.name.endswith(\".md\"):\n",
72 | " loader = TextLoader(file_path)\n",
73 | " else:\n",
74 | " print(f\"Document type {doc_file.type} not supported.\")\n",
75 | " continue\n",
76 | "\n",
77 | " docs.extend(loader.load())\n",
78 | "\n",
79 | " except Exception as e:\n",
80 | " print(f\"Error loading document {doc_file.name}: {e}\")\n",
81 | "\n",
82 | "\n",
83 | "# Load URLs\n",
84 | "\n",
85 | "url = \"https://docs.streamlit.io/develop/quick-reference/release-notes\"\n",
86 | "try:\n",
87 | " loader = WebBaseLoader(url)\n",
88 | " docs.extend(loader.load())\n",
89 | "\n",
90 | "except Exception as e:\n",
91 | " print(f\"Error loading document from {url}: {e}\")"
92 | ]
93 | },
94 | {
95 | "cell_type": "code",
96 | "execution_count": 3,
97 | "metadata": {},
98 | "outputs": [
99 | {
100 | "data": {
101 | "text/plain": [
102 | "[Document(metadata={'source': 'docs\\\\test_rag.pdf', 'page': 0}, page_content='My favorite food is margarita pizza. \\nThere are 47588 bottles in the tr uck. '),\n",
103 | " Document(metadata={'source': 'docs\\\\test_rag.docx'}, page_content='My favorite food is margarita pizza.\\n\\nThere are 47588 bottles in the truck.'),\n",
104 | " Document(metadata={'source': 'https://docs.streamlit.io/develop/quick-reference/release-notes', 'title': 'Release notes - Streamlit Docs', 'description': 'A changelog of highlights and fixes for each version of Streamlit.', 'language': 'No language found.'}, page_content='Release notes - Streamlit DocsDocumentationsearchSearchrocket_launchGet startedInstallationaddFundamentalsaddFirst stepsaddcodeDevelopConceptsaddAPI referenceaddTutorialsaddQuick referenceremoveCheat sheetRelease notesPre-release featuresRoadmapopen_in_newweb_assetDeployConceptsaddStreamlit Community CloudaddStreamlit in Snowflakeopen_in_newOther platformsaddschoolKnowledge baseFAQInstalling dependenciesDeployment issuesHome/Develop/Quick reference/Release notesRelease notes\\nThis page lists highlights, bug fixes, and known issues for official Streamlit releases. If you\\'re looking for information about nightly releases, beta features, or experimental features, see Try pre-release features.\\nstarTipTo upgrade to the latest version of Streamlit, run:pip install --upgrade streamlit\\n\\nVersion 1.38.0\\nRelease date: August 27, 2024\\nHighlights\\n\\n📈\\xa0Streamlit natively supports more dataframe formats! Use dataframe and series objects from popular libraries like Dask, Modin, Numpy, pandas, Polars, PyArrow, Snowpark, Xarray, and more. Use database cursors compliant with the Python Database API Specification 2.0. Use anything that supports the Python dataframe interchange protocol. See the docs.\\n\\nNotable Changes\\n\\n↔️\\xa0You can control the initial expansion state of st.json elements.\\n🧑\\u200d💻\\xa0You can choose to wrap lines in st.code.\\n🕵️\\xa0Streamlit supports Kubernetes style secrets so you can use Snowflake Snowpark Container Services secret format (#9078).\\n⤴️\\xa0Breaking change: We removed a patch that allows custom validators in pydantic<2.0 (#9257).\\n💔\\xa0Breaking change: We removed the experimental cache replay feature from caching decorators (#9305).\\n\\nOther Changes\\n\\n🌐\\xa0For better app efficiency, a WebSocket reconnect will not trigger a rerun unless a script run was interrupted (#9083).\\n👋\\xa0We updated our streamlit hello app to use Google Material icons.\\n⌨️\\xa0st.number_input, st.selectbox, st.slider, st.select_slider, and st.radio provide more precise type hinting for their return values (#9048, #9296, #8717). Thanks, Asaurus1!\\n⭐\\xa0st.feedback provides more precise type hinting for its return value (#9216). Thanks, wyattscarpenter!\\n💅\\xa0We improved theme management for embedded apps via\\xa0postMessage\\xa0(#9103).\\n🌱\\xa0Bug fix: Within the sidebar, the image for st.logo resizes along with the sidebar width (#9298, #8707).\\n🪹\\xa0Bug fix: When a parent fragment updates, Streamlit cleans up child fragments correctly (#9246, #9233, #9267).\\n💩\\xa0Bug fix: Elements unstale within a fragment rerun as they are updated instead of all together at the end of the fragment rerun (#9285).\\n🪱\\xa0Bug fix: If a block type changes during a rerun, Streamlit discards the child elements of that block to prevent improper visual artifacts, like st.tabs causing a blank page (#9276, #9259, #8676).\\n☠️\\xa0Bug fix: Widget state is preserved when page reruns are interrupted with another rerun (#9187, #9163). Thanks, dannyopts!\\n👽\\xa0Bug fix: options\\xa0in\\xa0st.selectbox,\\xa0st.multiselect,\\xa0st.radio, and\\xa0st.select_slider correctly use dict_items (#9241, #9237, #5377).\\n👻\\xa0Bug fix: A SelectboxColumn index will show with the correct, grayed-out styling in a dataframe (#9231, #8772).\\n🦀\\xa0Bug fix: st.write_stream will not immediately fail when receiving an empty chunk (#9234, #9227).\\n🦋\\xa0Bug fix: Streamlit won\\'t auto-scroll to an empty anchor, if present (#9206, #9203).\\n🦎\\xa0Bug fix: We changed the handling of scriptRunId to prevent st.tabs from showing extra, empty tabs in fragments (#9186, #9158, #9215).\\n🐌\\xa0Bug fix: Automatically rerunning fragments don\\'t raise FragmentStorageKeyError to prevent a possible race condition (#9183, #9080).\\n🕸️\\xa0Bug fix: We improved st.plotly_chart\\'s handling of the pass-through keyword argument config (#9190, #9134).\\n🦗\\xa0Bug fix: Markdown in all label parameters correctly ignores headers (#9189, #9141).\\n🦂\\xa0Bug fix: We reverted a change to fragments which caused some widgets to lose state in some circumstances (#9178, #9171).\\n🦟\\xa0Bug fix: The deprecation warnings for st.experimental_fragment and st.experimental_dialog only show when the commands are called. This prevents custom components which use them from raising premature warnings on import (#9170, #9143).\\n🦠\\xa0Bug fix: st.code shows syntax highlighting for diff code when language=\"diff\" (#9172, #8687).\\n🪰\\xa0Bug fix: Streamlit commands that raise ScriptControlException execute as expected in try-except blocks (#9167, #9155, #9182).\\n🪳\\xa0Bug fix: The value for st.date_input has the correct type for linting (#9149). Thanks, wyattscarpenter!\\n🕷️\\xa0Bug fix: We updated plotly.js to support hoversubplots=\"axis\" (#9144, #9118).\\n🐞\\xa0Bug fix: We stabilized the identity of st.map instances so the command doesn\\'t create multiple maps when its parameters are updated (#9092, #8329).\\n🐝\\xa0Bug fix: You can now clear the cache for cached class instance methods (#9101, #8638).\\n🐜\\xa0Bug fix: Copy buttons work correctly in dialogs (#9130, #9112).\\n🪲\\xa0Bug fix: Streamlit magic works consistently in for-else, while-else, try-else, try-except, and match blocks (#9110, #9109). Thanks, whitphx!\\n🐛\\xa0Bug fix: When printing an app, the bottom container will always print at the end without overlapping other content (#9129).\\n\\nVersion 1.37.0\\nRelease date: July 25, 2024\\nHighlights\\n\\n🍪 Introducing st.context to read headers and cookies!\\n⭐ Introducing st.feedback to collect ratings and sentiment from your users!\\n👟\\xa0Announcing the general availability of st.fragment, a decorator that lets you rerun functions independently of the whole page.\\n🍿\\xa0Announcing the general availability of st.dialog, a decorator that lets you create modal dialogs.\\n\\nNotable Changes\\n\\nℹ️ You can use icons from the Material Symbols library in Markdown!\\n📈\\xa0You can pass graphviz.Source objects to st.graphviz_chart.\\n📊 You can modify the stacking behavior for st.bar_chart and st.area_chart.\\n🔭\\xa0Within a fragment, you can scope st.rerun to the fragment.\\n🪺\\xa0Streamlit supports nested fragments (#8931, #8635).\\n📞\\xa0Fragments can be used in callback functions (#8916, #8591).\\n\\nOther Changes\\n\\n⭕ Material Symbols are rounded instead of outlined (#8998).\\n🔢\\xa0Streamlit supports Numpy version 2.0 (#8940).\\n😄\\xa0We\\'ve updated emoji validation for new emojis (#8923).\\n👻\\xa0We\\'ve removed several experimental commands with new, generally available versions (#8943).\\n☠️\\xa0We\\'ve removed deprecated configuration options per their announced expiration date (#9005, #9013, #9018).\\n🦎\\xa0Bug fix: Nested fragments rerun correctly when a child fragment precedes a widget in the parent fragment (#9114).\\n🐌\\xa0Bug fix: Streamlit validates file paths before performing additional checks when using static file serving for improved security (#8990).\\n🕸️\\xa0Bug fix: st.map displays at the correct width inside st.expander (#9070, #8004).\\n🦗\\xa0Bug fix: Streamlit displays the correct (Windows) path for secrets.toml in an error message (#9061, #6147).\\n🦂\\xa0Bug fix: st.switch_page correctly clears non-embed query parameters when the user switches pages (#9059, #9050).\\n🦟\\xa0Bug fix: Custom themes display correctly for multipage elements like st.page_link (#8994, #8978).\\n🦠\\xa0Bug fix: st.snow and st.balloons don\\'t show in prints (#9053, #7790).\\n🪰\\xa0Bug fix: We\\'ve improved the default formatting for st.number_input (#9035, #7163).\\n🪳\\xa0Bug fix: An st.navigation example was corrected (#9027, #9026). Thanks, mahotd!\\n🕷️\\xa0Bug fix: Dialogs no longer have a brief delay when closing (#9023, #8747).\\n🦀\\xa0Bug fix: Streamlit correctly raises a KeyError when encountered in a fragment instead of a misleading, fragment-related error (#9011, #8494).\\n🐞\\xa0Bug fix: Streamlit doesn\\'t clear MediaFileManager on fragment reruns to prevent invalid references (#9010, #8932).\\n🐝\\xa0Bug fix: Custom themes are correctly removed when deleted (#8989, #8962).\\n🐜\\xa0Bug fix: Streamlit supports non-unix style paths for correct multipage routing in Windows (#8988, #8958).\\n🪲\\xa0Bug fix: Using st.rerun in a fragment will not cause the app\\'s main body content to render in the fragment in rare events (#8798).\\n🐛\\xa0Bug fix: When an exception is raised within a fragment, Streamlit shows the error message within the fragment (#8868).\\n\\nVersion 1.36.0\\nRelease date: June 20, 2024\\nHighlights\\n\\n🧭 Introducing st.navigation and st.Page for a new way to define multipage apps! Check out the docs to learn more.\\n\\nNotable Changes\\n\\n📊\\xa0st.bar_chart can render charts horizontally.\\nℹ️\\xa0st.expander supports adding an icon next to its label.\\n🏗️\\xa0st.columns lets you set vertical alignment.\\n📲 Custom components support callback functions (#8633, #3977).\\n📥 Fragments no longer support rendering widgets outside of their main body (#8756).\\n🏷️ You can now customize axis labels for st.area_chart, st.bar_chart, st.line_chart, and st.scatter_chart.\\n⌛ The caching parameter experimental_allow_widgets is deprecated (#8817).\\n❌ Streamlit no longer supports legacy caching. st.cache is now an alias for st.cache_data and st.cache_resource (#8737).\\n⬆️ Streamlit supports protobuf version 5 (#8627).\\n\\nOther Changes\\n\\n✨\\xa0Streamlit Hello uses st.navigation and st.Page, the new, preferred method for declaring multipage apps (#8806).\\n🧹\\xa0Streamlit no longer appends \"· Streamlit\" to the page title of apps, unless running on Community Cloud (#8900).\\n🦋\\xa0Streamlit magic and st.write use st.json to display st.secrets (#8659, #2905).\\n🔍\\xa0Streamlit doesn\\'t automatically check for newer version on PyPi (#8841, #8453).\\n🐌\\xa0Bug fix: Custom component functions require importing streamlit.components.v1 (#8666, #8644).\\n🕸️\\xa0Bug fix: Reverted change to handle Altairs resolve_scale method since it caused a regression (#8845, #8642).\\n🦗\\xa0Bug fix: Images in Markdown do not overflow the Markdown container (#8794).\\n🦂\\xa0Bug fix: Clarified the error message for st.selectbox when index is larger than the size of options (#8775, #8771).\\n🦟\\xa0Bug fix: Streamlit correctly handles non-widget elements with IDs (#8770, #8768).\\n🦠\\xa0Bug fix: Docstrings correctly identify when use_container_width=True is the default (#8809).\\n🪰\\xa0Bug fix: Streamlit has a consistent minimum element height for better vertical alignment (#8797, #8835, #8027, #8706).\\n🪳\\xa0Bug fix: Added check to ensure SessionInfo is initialized before performing actions (#8779, #8321, #7549).\\n🕷️\\xa0Bug fix: Dataframe use raw numbers without formatting by default (#8708, #8695).\\n🐞\\xa0Bug fix: Updated the error message for disallowed writes to Session State (#8720, #8715).\\n🐝\\xa0Bug fix: Streamlit doesn\\'t initialize LocalSourcesWatcher if file watching is disabled (#8741, #8738).\\n🐜\\xa0Bug fix: st.experimental_dialog no longer has an invalid default value for title (#8729).\\n🪲\\xa0Bug fix: Removed deprecated kwargs in ast.Call to prevent type error (#8711). Thanks, JelleZijlstra!\\n🐛\\xa0Bug fix: st.experimental_dialog is explicitly exported to avoid a type checking error (#8728, #8712).\\n\\nVersion 1.35.0\\nRelease date: May 23, 2024\\nHighlights\\n\\n📈\\xa0Announcing user selections for charts! Use st.plotly_chart, st.altair_chart, and st.vega_lite_chart to make chart widgets for even more interactive apps.\\n🚣\\u200d♂️ Announcing user selections for dataframes. Get row and column selections from users with st.dataframe.\\n💼\\xa0Introducing st.logo to add an image in the sidebar, above navigation.\\n\\nNotable Changes\\n\\n🔗\\xa0st.page_link supports Material icons (#8593).\\n⚓\\xa0Anchor button for headers display inline at the end of headers for a more beautiful and consistent appearance (#8587).\\n🈂️\\xa0SQLConnection accepts query as a sqlalchemy.URL.create parameter so you can specify character sets (#8581). Thanks, LucianLiu6!\\n\\nOther Changes\\n\\n🕸️\\xa0Bug fix: A fallback method was added for CSV downloads to increase browser compatibility (#8452, #8210).\\n🦗\\xa0Bug fix: Column config is deep-copied when cloned to prevent unintentional modifications (#8677).\\n🦂\\xa0Bug fix: st.data_editor renders correctly when using num_rows=dynamic with null values in added rows (#8640, #7458).\\n🦟\\xa0Bug fix: streamlit run will display the localhost address when initializing Streamlit with server.headless=true (#8647, #8629).\\n🦠\\xa0Bug fix: Scroll margin matches the new toolbar (app chrome) height (#8641, #8554).\\n🪰\\xa0Bug fix: Enum coercion is compatible with StrEnum (#8622, #8500). Thanks, 97k!\\n🪳\\xa0Bug fix: Focus is returned to chat input after clicking submit for a better mobile experience (#8637).\\n🕷️\\xa0Bug fix: Internal parameter and view names for Altair charts are stabilized for better performance (#8628).\\n🐞\\xa0Bug fix: Typing was improved for st.query_params.update() and st.query_params.from_dict() (#8614, #8613). Thanks, Asaurus1!\\n🐝\\xa0Bug fix: The fullscreen button no longer appears for st.table to prevent unwanted side scrolling (#8621, #2358).\\n🐜\\xa0Bug fix: Streamlit correctly clears stale elements when using st.rerun (#8599, #8360).\\n🪲\\xa0Bug fix: Custom components can be executed standalone for testing and scripting (#8620, #8606).\\n👻\\xa0Bug fix: Plotly charts no longer render cached data when updated (#8191, #5902)\\n👽\\xa0Plotly chart widths will not overflow its parent container when rendered in a bordered container (#8191, #8244).\\n🦀\\xa0Plotly charts using webgl render correctly on M1/M2 chipsets for macOS (#8191, #8169).\\n🦋\\xa0Plotly charts are sized correctly when rendered vertically adjacent (#8191, #7597).\\n🦎\\xa0Bug fix: Plotly charts retain their state when the app window is resized (#8191, #6324).\\n🐛\\xa0Bug fix: Plotly charts in st.tabs no longer flicker when changing tabs (#8191, #8575).\\n🐌\\xa0Bug fix: Plotly charts respect use_container_width if this parameter is changed between reruns (#8191, #8576).\\n\\nVersion 1.34.0\\nRelease date: May 2, 2024\\nHighlights\\n\\n🍿\\xa0Introducing st.experimental_dialog! Create a modal overlay that can also rerun independently from the rest of your app. Check out the docs to learn how.\\n\\nNotable Changes\\n\\n🔣\\xa0st.toast, st.chat_message, st.set_page_config, st.info, st.success, st.error, and st.warning can use Google Material Symbols for their icons.\\n🌈\\xa0Markdown supports background colors for text. Check out the feature demo app.\\n🎥\\xa0st.audio and st.video can now be set to autoplay. st.video can be muted.\\n🗃️\\xa0You can clear specific cached values for a cached function. Thanks, OscarSaharoy!\\n❓\\xa0You can now set all query parameters with a single call to st.query_params.from_dict. Thanks, Asaurus1!\\n\\nOther Changes\\n\\n🔲\\xa0Streamlit supports Modin and Snowpark pandas DataFrames and Series (#8506).\\n⏱️\\xa0Improved support for period data types in st.dataframe and st.data_editor (#7987).\\n🗺️\\xa0Streamlit supports using pydeck-carto with st.pydeck_chart (#8422).\\n❄️\\xa0Additional snowflake requirements were updated to allow Python versions 3.8 to 3.11 (#8538).\\n🍞\\xa0st.toast received visual improvements and now appears in the top right (#8433).\\n🦋\\xa0Visual tweaks for dialogs and modals.\\n🦀\\xa0Bug fix: st.write_stream returns an empty string when passed a generator with no yield (#8560).\\n🦎\\xa0Bug fix: Widgets that support None values can be correctly set to None through Session State (#8529, #7649).\\n🐌\\xa0Bug fix: If the initial value for st.date_input is not set and today\\'s date falls outside the declared minimum or maximum, then the minimum or maximum will be used instead, whichever is closer (#8519, #6167).\\n🕸️\\xa0Bug fix: Altair\\'s resolve_scale method is handled correctly (#8497, #1667).\\n🦗\\xa0Bug fix: st.multiselects correctly handles sets when passed to options or default (#8471, #8466).\\n🦂\\xa0Bug fix: st.status does not show the expander toggle when empty (#8369).\\n🦟\\xa0Bug fix: The width of vconcat charts in Vega and Altair is set correctly (#8498, #2751).\\n🦠\\xa0Bug fix: Apps print beautifully and no longer show excessive whitespace (#8502, #7815).\\n🪰\\xa0Bug fix: Invalid escape sequences were removed to avoid warnings from pytest (#8510, #8501).\\n🪳\\xa0Bug fix: st.file_uploader callback is correctly executed once per file selection after the first selection (#8493, #4877).\\n🕷️\\xa0Bug fix: Streamlit is compatible down to pillow version 7.1.0 instead of 9.1.0 (#8492, #8486).\\n🐞\\xa0Bug fix: Widget values are correctly dropped when a script run is interrupted by switching pages (#8425, #7338).\\n🐝\\xa0Bug fix: Apps in dark mode will return to dark mode after printing (#8469, #7879).\\n🐜\\xa0Bug fix: Component ready state is dynamic to avoid race conditions that caused blank apps in Safari (#8434, #8362).\\n🪲\\xa0Bug fix: st.slider yields a Python error when min_value is less than or equal to max_value (#8413, #8342).\\n🐛\\xa0Bug fix: Time is offset correctly for Vega and Altair (#8278, #4342).\\n\\nVersion 1.33.0\\nRelease date: April 4, 2024\\nHighlights\\n\\n👟\\xa0Introducing st.experimental_fragment to decorate functions and rerun them independently of the whole page. Check out the docs and give your apps a speed boost!\\n🌐\\xa0Introducing st.html to insert custom HTML into your app! Check out the docs for how to use it.\\n\\nNotable Changes\\n\\n📺\\xa0st.audio and st.video allow looping and setting an end time (#8203, #8348).\\n🔁\\xa0AppTest allows switching pages with AppTest.switch_page (#8280).\\n🧪 format_func is accessible in AppTest for widgets that use it (#8189, #8019, #7679).\\n📈 Column configuration now includes AreaChartColumn. LineChartColumn no longer shows area (#8237).\\n🚧 Breaking change: st.write will no longer set unsafe_allow_html=True when passed an object containing a _repr_html_ method. For more information, see PR #8238.\\n\\nOther Changes\\n\\n🖱️Users can click on the widget label to focus on input for st.number_input, st.text_input, and st.text_area (#8155). Thanks, filiptammergard!\\n⬆️ Streamlit supports packaging version 24.x (#8338, #8328).\\n🕸️\\xa0Bug fix: Streamlit now watches for changes to imported modules in addition to pages (#8372). Thanks, zyxue!\\n🦗\\xa0Bug fix: Overflowing toast messages are correctly truncated (#8337, #8330).\\n🦂\\xa0Bug fix: st.status correctly updates to complete when using LangChain\\'s StreamlitCallbackHandler (#8331).\\n🦟 Bug fix: Custom components no longer show white backgrounds in dark themes (#8242, #8156, #7813).\\n🦠 Bug fix: Content area width is reduced when a fullscreen icon would otherwise cause horizontal overflow (#8279, #6990).\\n🪰 Bug fix: Custom components with undefined frame heights will render with a height of 0 (#8290, #8285).\\n🪳\\xa0Bug fix: Restored a check for active sessions to prevent apps from needlessly running when no users are connected (#8294).\\n🕷️ Bug fix: Custom themes have precedence over embedding options (#8021, #7118).\\n🐞\\xa0Bug fix: Reverted the async timer to expire session storage cache to address computational efficiency (#8281).\\n🐝\\xa0Bug fix: When using st.popover with use_container_width=True, the popover container\\'s minimum width will match the popover button (#8266, #8261).\\n🐜 Bug fix: Using st.rerun with a triggering widget in AppTest no longer creates an infinite loop (#8264, #7768).\\n🪲\\xa0Bug fix: URLs are correctly decoded in LinkColumn if regex is used or if not using fully qualified URLs (#8258, #7064).\\n🐛\\xa0Bug fix: st.query_params only sends one ForwardMsg when updating multiple parameters (#8205, #8199). Thanks, Asaurus1!\\n\\nVersion 1.32.0\\nRelease date: March 7, 2024\\nHighlights\\n\\n🍿\\xa0Introducing st.popover to create popover elements in your Streamlit apps. Check out the docs to see how to use it!\\n\\nNotable Changes\\n\\n📺\\xa0You can now pass subtitles to st.video! Check out our feature demo.\\n⚗️\\xa0AppTest includes support for st.expander and st.status.\\n🧪\\xa0AppTest.from_function accepts a function that takes arguments and/or returns a value.\\n🧩\\xa0The timeout warning for custom components was replaced with an element skeleton to improve the UX for slow-loading components, especially in some cloud-hosted platforms (#8179, #7046).\\n📄 st.switch_page and st.page_link received significant improvements to path handling, performance, and visual appearance (see below for details).\\n🦀\\xa0Bug fix: Streamlit uses glide-data-grid version 6.0.4 to fix a variety of dataframe issues (#7779, #6900, #7032, #7727, #6810, #7930, #7949, #7831, #8168).\\n💦 Bug fix: We\\'ve plugged a significant memory leak in the coroutine loop. Apps that generate a large number of small messages between client and server will benefit greatly (#8068, #7989, #6510).\\n\\nOther Changes\\n\\n💪 Multiple modules are now lazy-loaded to speed up Streamlit\\'s import time (#8150, #8143, #8134, #8113, #8125, #8111, #8109, #6066).\\n🖼️\\xa0st.write supports PIL images (#8039).\\n🔗\\xa0st.radio allows markdown links within the items passed to options (#8028, #7992).\\n💀\\xa0The\\xa0deprecation.showPyplotGlobalUse config option is deprecated and will be removed in the subsequent release (#8133).\\n🤖\\xa0Streamlit supports AzureOpenAI chat stream (#8107, #8084).\\n🌐\\xa0The /healthz endpoint supports the HTTP HEAD method (#8145, #8144). Thanks, rahulmistri1997!\\n🌀\\xa0The cache parameter for\\xa0st.spinner is now private (_cache) since it\\'s for internal use (#8118).\\n🏃\\xa0Session storage is checked and expired asynchronously to improve performance and efficiency of apps with lower traffic (#8083).\\n🐜\\xa0st.write_stream raises a descriptive Exception when the message cannot be parsed (#8036).\\n📘\\xa0Fixed a typo in the examples for st.switch_page and st.page_link (#8162). Thanks, t1emp0!\\n👻\\xa0Bug fix:\\xa0st.help correctly displays conditional members (#8228).\\n🦋\\xa0Bug fix: App State fully clears on page change to prevent lingering stale elements (#8208).\\n🦎\\xa0Bug fix: st.info, st.success, st.warning, and st.error don\\'t overflow with long markdown strings (#8194, #6394).\\n🐌\\xa0Bug fix: Streamlit shows a warning that port 3000 is reserved for development when the server port is set to 3000 (#8152, #8149).\\n🕸️\\xa0Bug fix: st.page_link and st.switch_page have improved path calculation for consistency (#8127).\\n🦗\\xa0Bug fix: st.page_link shows the correct path in browser on hover (#8086, #8080).\\n🦂\\xa0Bug fix: st.page_link and st.switch_page normalize paths for correct handling in Windows (#8103, #8070).\\n🦟\\xa0Bug fix: Script runner uses a while loop instead of recursion to avoid stack overflows (#8100).\\n🦠 Bug fix: st.page_link and st.switch_page correctly handle relative paths prefixed with \"/\" (#8085, #8081).\\n🪰\\xa0Bug fix: st.image parses paths in Windows correctly (#8092, #7271, #6066).\\n🪳\\xa0Bug fix: st.switch_page no longer waits for the current page to finish running before switching pages (#8054, #7954).\\n🕷️\\xa0Bug fix: st.map and other simple charts correctly handle color when data is not indexed starting from 0 (#8158, #8079, #8077). Thanks, awhazell!\\n🐞\\xa0Bug fix: st.selectbox, st.multiselect, st.select_slider, and st.radio use shallow copies of their options to prevent unexpected mutations (#8064, #7534).\\n🐝\\xa0Bug fix: The selected time in st.time_input displays correctly in dark mode (#8056, #7436).\\n🪲\\xa0Bug fix: Dataframe scrollbars display correctly in the latest version of Chrome (#8034).\\n🐛\\xa0Bug fix: Casting st.query_params to str will print the content of the query parameters instead of the class description (#8030).\\n\\nVersion 1.31.0\\nRelease date: February 1, 2024\\nRelease videos\\n\\nWhat\\'s new?\\n\\nHighlights\\n\\n🔗\\xa0Introducing st.page_link! Now, you can build custom navigation menus for your multipage apps. Check out our docs to see how.\\n💦\\xa0Announcing st.write_stream to conveniently handle generators and streamed responses. Check out our docs to see how making chat apps just got easier.\\n\\nNotable Changes\\n\\n📝\\xa0st.chat_input can be used inline and placed anywhere in the app. You can also have multiple st.chat_input widgets on a page (#7896).\\n\\nOther Changes\\n\\n🧹\\xa0Internal refactoring and cleanup (#7980). Thanks, whitphx!\\n❄️\\xa0Bug fix: Snowpark is now an optional dependency for SnowflakeConnection (#7919).\\n🕷️\\xa0Bug fix: The watchdog suggestion is disabled when server.fileWatcherType is set to none or poll (#8024, #7999).\\n🐞\\xa0Bug fix: Required columns can be hidden when not using st.data_editor with dynamic rows (#7996, #7991).\\n🐝\\xa0Bug fix: New period types are supported for pandas 2.2.0 (#7988).\\n🐜\\xa0Bug fix: Custom components receive only the app\\'s origin and path to avoid reloading components when query parameters change (#7951, #7503). Thanks, eric-skydio!\\n🪲\\xa0Bug fix: st.progress won\\'t raise an exception when given a value above 1.0 due to float precision (#7953, #5517). Thanks, notiona!\\n📚 Streamlit supportsimportlib-metadata version 7 (#7925). Thanks, elgalu!\\n🐛\\xa0Bug fix: AppTest correctly sees widgets inside containers (#7923, #7711).\\n💿 Custom components no longer accumulate style elements when re-rendered for better performance (#7914). Thanks, Tom-Julux!\\n\\nVersion 1.30.0\\nRelease date: January 11, 2024\\nRelease videos\\n\\nWhat\\'s new?\\n\\nHighlights\\n\\n🔄\\xa0Announcing st.switch_page to programmatically switch pages in multipage apps! Check out our docs to learn about this highly anticipated feature!\\n❓Introducing st.query_params to handle variables passed through your app\\'s URL. Check out our docs to understand this feature and how it\\'s been upgraded and improved from our experimental version!\\n\\nNotable Changes\\n\\n📐\\xa0st.container can be configured with a height to create grids or scrolling containers (#7697, #2169, #2447).\\n🔗\\xa0For dataframes,\\xa0LinkColumn\\xa0has a simplified UI and can be configured with display text, including programmatically defined text through regular expressions (#7784, #7741, #6787).\\n🧭\\xa0Sidebar navigation for multipage apps can be hidden via configuration (#7852).\\n⏩\\xa0Plotly figures can load even faster when used in combination with orjson (#7860). Thanks, eric-skydio!\\n♻️ Behavior change: Query parameters are removed when changing pages (#7817,\\xa0#6725,\\xa0#5505).\\n\\nOther Changes\\n\\n🛠️\\xa0showFooter is no longer an embed option since the footer no longer exists (#7902, #7785).\\n🕵️ All security concerns should be reported through HackerOne (#7783).\\n🕷️\\xa0Bug fix: Tabs are not disabled when stale to prevent flickering (#7905, #7820).\\n🛡️\\xa0Bug fix: The full file path is used instead of a prefix to prevent custom components from reaching beyond their own folders (#7901).\\n🪱\\xa0Bug fix: Widgets raise an exception if its values aren\\'t Python comparable (#7840, #3714).\\n🐞\\xa0Bug fix: The down-arrow icons on expanders maintain a consistent size (#7596). Thanks, matiboux!\\n🐝\\xa0Bug fix: Tabs no longer flicker when switching between them (#7904).\\n🐜\\xa0Bug fix: Enter-to-submit is automatically disabled when the associated st.form_submit_button is disabled (#7827, #7822).\\n🪲\\xa0Bug fix: Required columns cannot be hidden with column configuration (#7888, #7559).\\n🐛\\xa0Bug fix: Using nan as a value in SelectboxColumn will raise an error instead of silently failing (#7887, #7558).\\n🌙\\xa0Bug fix: Custom component iframes allow dark mode (#7821, #7813).\\n🪰\\xa0Bug fix: The command to start Streamlit is not sent to the frontend (#7787).\\n💅\\xa0Bug fix: The background color of st.toggle is enhanced for better visibility (#7788).\\n🪳\\xa0Bug fix: Built-in charts can handle ordered categorical columns (#7771, #7776).\\n\\nVersion 1.29.0\\nRelease date: November 30, 2023\\nHighlights\\n\\n🔲\\xa0st.container and st.form now have a border parameter to show or hide a border.\\n🐍\\xa0Streamlit supports Python 3.12!\\n\\nNotable Changes\\n\\n⌛ st.dataframe, st.data_editor, and st.table support datetime.timedelta values (#7689, #4489).\\n💀\\xa0Streamlit apps preload skeleton elements for a smoother appearance when initializing (#7598).\\n🏃\\xa0Reduced the overhead of running AppTest-simulated apps, especially for fast-running apps (#7691).\\n🛁\\xa0String representations of AppTest data are improved for a better testing and debugging experience (#7658).\\n🔢 Apps can be configured to identify Enum classes as the same if they have matching member names (#7408, #4909). Thanks, Asaurus1!\\n❌ The \"Made with Streamlit\" footer no longer appears at the bottom of apps (#7583).\\n🧹 Unused config options have been deprecated (#7584).\\n🕳️ Query parameters can be empty (#7601, #7416).\\n💅\\xa0Visual tweaks (#7592, #7630).\\n\\nOther Changes\\n\\n🦗\\xa0Bug fix: Convert floats to bytes instead of hashing to avoid hashing instability (#7754). Thanks, BlackHC!\\n🦎\\xa0Bug fix: Corrected broken URLs and typos in error messages (#7746, #7764, #7770). Thanks, ObservedObserver!\\n🐌\\xa0Bug fix: st.connection correctly caches results when using two connections of the same type (#7730, #7709).\\n🕸️\\xa0Bug fix: Using context managers with multithreading now displays content in the expected order (#7715, #7668). Thanks, eric-skydio!\\n🦂\\xa0Bug fix: Added https fallback when obtaining the host machine\\'s address (#7712, #7703). Thanks, LarsHill!\\n🛡️\\xa0Bug fix: Added security patch for pyarrow vulnerability. Custom components using pyarrow table deserialization should require pyarrow>=14.0.1 (#7695, #7700).\\n🦟\\xa0Bug fix: Improved typing for st.connection (#7671). Thanks, thezanke!\\n🪰\\xa0Bug fix: Retries of SnowflakeConnection methods are narrowed to only occur with transient errors to avoid unnecessary repeated errors (#7645, #7637).\\n🏗️ Removed the v0 testing framework which was undocumented (#7657).\\n🪳\\xa0Bug fix: The navigation expander arrow no longer disappears (#7634, #7547).\\n❄️ Improved the error message for SnowflakeConnection when a configuration is not found (#7652).\\n🕷️\\xa0Bug fix: st.rerun no longer causes a RecursionError when used with st.chat_input (#7643, #7629).\\n🐞\\xa0Bug fix: st.file_uploader no longer causes an extra rerun and therefore doesn\\'t conflict with st.chat_input (#7641, #7556).\\n🐝\\xa0Bug fix: AppTest no longer raises an error when encountering st.container (#7644, #7636).\\n🪲 Bug fix: Graphviz charts scale correctly when exiting fullscreen view (#7398, #7527).\\n🎥\\xa0Bug fix: \"Record a screencast\" is hidden when known to be unsupported in a browser (#7604).\\n🐛\\xa0Bug fix: Increased the top padding of embedded apps to better display the dataframe toolbar (#7681, #7609, #7607).\\n🐜\\xa0Bug fix: st.rerun uses NoReturn for improved type checking (#7422) Thanks, kongzii.\\n\\nVersion 1.28.0\\nRelease date: October 26, 2023\\nRelease videos\\n\\nIntroducing AppTest\\n\\nHighlights\\n\\n🧪 Introducing a new testing framework for Streamlit apps! Check out our documentation to learn how to build automated tests for your apps.\\n💻 Announcing the general availability of st.connection, a command to conveniently manage connections in Streamlit apps. Check out the docs to learn more.\\n❄️ SnowparkConnection has been upgraded to the new and improved SnowflakeConnection — the same, great functionality plus more! Check out our built-in connections.\\n🛠️ st.dataframe and st.data_editor have a new toolbar! Users can search and download data in addition to enjoying improved UI for row additions and deletions. See our updated guide on Dataframes.\\n\\nNotable Changes\\n\\n🌀 When using a spinner with cached functions, the spinner will be overlaid instead of pushing content down (#7488).\\n📅 st.data_editor now supports datetime index editing (#7483).\\n🔢 Improved support for decimal.Decimal in st.dataframe and st.data_editor (#7475).\\n🥸 Global kwargs were added for hashlib (#7527, #7526). Thanks, DueViktor!\\n📋 st.components.v1.iframe now permits writing to clipboard (#7487). Thanks, dilipthakkar!\\n📝 SafeSessionState disconnect was replaced with script runner yield points for improved efficiency and clarity (#7373).\\n🤖 The Langchain callback handler will show the full input string inside the body of a st.status when the input string is too long to show as a label (#7478). Thanks, pokidyshev!\\n📈 st.graphviz_chart now supports using different Graphviz layout engines (#7505, #4089).\\n🦋\\xa0Assorted visual tweaks (#7486, #7592).\\n📊 plotly.js was upgraded to version 2.26.1 (#7449, #7476, #7045).\\n💽 Legacy serialization for DataFrames was removed. All DataFrames will be serialized by Apache Arrow (#7429).\\n🖼️ Compatibility for Pillow 10.x was added (#7442).\\n📬 Migrated _stcore/allowed-message-origins endpoint to\\xa0_stcore/host-config\\xa0(#7342).\\n💬 Added\\xa0post_parent_message\\xa0platform command to send\\xa0custom\\xa0messages from a Streamlit app to its parent window (#7522).\\n\\nOther Changes\\n\\n⌨️ Improved string dtype handling for DataFrames (#7479).\\n✒️ st.write will avoid using unsafe_allow_html=True if possible (#7432).\\n🐛\\xa0Bug fix: Implementation of st.expander was simplified for improved behavior and consistency (#7247, #2839, #4111, #4651, #5604).\\n🪲\\xa0Bug fix: Multipage links in the sidebar are now aligned with other sidebar elements (#7531).\\n🐜\\xa0Bug fix: st.chat_input won\\'t incorrectly prompt for label parameter in IDEs (#7560).\\n🐝\\xa0Bug fix: Scroll bars correctly overlay st.dataframe and st.data_editor without adding empty space (#7090, #6888).\\n🐞\\xa0Bug fix: st.chat_message behaves correctly with the removal of AutoSizer (#7504, #7473).\\n🕷️\\xa0Bug fix: Anchor links are reliably produced for non-English headers (#7454, #5291).\\n☃️\\xa0Bug fix: st.connections.SnowparkConnection more accurately detects when it\\'s running within Streamlit in Snowflake (#7502).\\n🪳\\xa0Bug fix: A user-friendly warning is shown when exceeding the size limitations of a pandas Styler object (#7497, #5953).\\n🪰\\xa0Bug fix: st.data_editor automatically converts non-string column names to strings (#7485, #6950).\\n🦠\\xa0Bug fix: st.data_editor correctly identifies non-range indices as a required column (#7481, #6995).\\n🦟\\xa0Bug fix: st.file_uploader displays compound file extensions like csv.gz correctly (#7362). Thanks, mo42!\\n🦂\\xa0Bug fix: Column Configuration no longer uses deprecated type checks (#7496, #7477, #7550). Thanks, c-bik!\\n🦗\\xa0Bug fix: Additional toolbar items no longer stack vertically (#7470, #7471).\\n🕸️\\xa0Bug fix: Column Configuration no longer causes a type warning in Mypy (#7457). Thanks, kopp!\\n🐌\\xa0Bug fix: Bokeh Sliders no longer cause JavaScript errors (#7441, #7171).\\n🦎\\xa0Bug fix: Caching now recognizes DataFrames with the same values but different column names as different (#7331, #7086).\\n\\nVersion 1.27.0\\nRelease date: September 21, 2023\\nHighlights\\n\\n✨\\xa0Introducing st.scatter_chart — a new, simple chart element to build scatter charts Streamlit-y fast and easy! See our documentation.\\n🔗\\xa0Introducing st.link_button! Want to open an external link in a new tab with a bit more pizazz than a plain-text link? Check out our documentation to see how.\\n🏃\\xa0Announcing the general availability of st.rerun, a command to interrupt your script and trigger an immediate rerun.\\n\\nNotable Changes\\n\\n👻\\xa0You can initialize widgets with an empty state by setting\\xa0None\\xa0as an initial value for\\xa0st.number_input, st.selectbox, st.date_input, st.time_input, st.radio, st.text_input, and st.text_area!\\n📤\\xa0st.download_button now uses target=\"_self\" instead of opening a new tab (#7151, #7132).\\n🧟\\xa0Removed unmaintained pympler dependency (#7193, #7131). Thanks, rudyardrichter!\\n\\nOther Changes\\n\\n🐛\\xa0Bug fix: st.multiselect now shows a correct message when no result matches a user\\'s search (#7205, #7116).\\n🪲\\xa0Bug fix: st.experimental_user now defaults to test@example.com (#7219, #7215).\\n🐜\\xa0Bug fix: st.slider labels don\\'t overlap when small ranges are selected (#7221, #3385).\\n🐝\\xa0Bug fix: Type-checking correctly identifies all string types to avoid hashing errors (#7255, #6455).\\n🐞\\xa0Bug fix: JSON is parsed with JSON5 to avoid errors from null values when using st.pydeck_chart (#7256, #5799).\\n🕷️\\xa0Bug fix: Identical widgets on different pages are correctly interpreted by Streamlit as distinct (#7264, #6146).\\n🦋\\xa0Bug fix: Visual tweaks to widgets for responsive behavior (#7145).\\n🪳\\xa0Bug fix: SVGs are accurately displayed (#7183, #3882).\\n🪰\\xa0Bug fix: st.video correctly updates with changes to start_time (#7257, #7126).\\n🦠\\xa0Bug fix: Additional error handling was added to st.session_state (#7280, #7206).\\n🦟\\xa0Bug fix: st.map correctly refreshes with new data (#7307, #7294).\\n🦂\\xa0Bug fix: The decorative app header line is no longer covered by the sidebar (#7297, #6264).\\n🦗\\xa0Bug fix: st.code no longer triggers a CachedStFunctionWarning (#7306, #7055).\\n🕸️\\xa0Bug fix: st.download_button no longer resets with different data (#7316, #7308).\\n🐌\\xa0Bug fix: Widgets consistently recognize user interaction while a page is still running, with or without fastRerun enabled (#7283, #6643).\\n🦎\\xa0Bug fix: st.tabs was improved to better handle and render conditionally appearing tabs (#7287, #7310, #5454, #7040).\\n\\nVersion 1.26.0\\nRelease date: August 24, 2023\\nHighlights\\n\\n🤖 Introducing st.status to display output from long-running processes and external API calls (#7140). Works great with st.chat_message! See our documentation for how to use this feature.\\n🚥\\xa0Introducing st.toggle — an alternative to st.checkbox when you need an on/off switch.\\n\\nNotable Changes\\n\\n🎨 Simple chart elements have a color parameter to set the color of your data points or series (#7022).\\n🌈\\xa0Markdown supports rainbow and gray colors (#7106, #7179).\\n📏 st.header and st.subheader have optional, colored dividers (#7133).\\n🚀 Deploying to Community Cloud is even easier—locally running apps have a deploy button in their toolbars (#7085, #6935).\\n🖌️ st.download_button has a new parameter type for theming (#7056, #7038).\\n🤖 st.chat_message has ai and human presets for messages (#7094).\\n💅 st.radio options support markdown and have captions (#7018, #7105, #6085).\\n🧼\\xa0Assorted visual tweaks (#7050, #894).\\n🛏️ Replaced deprecated imghdr dependency with pillow (#7081, #7027).\\n🔢 st.number_input\\'s step buttons (+/-) are ignored during tabbing navigation (#7154). Thanks @denck007!\\n\\nOther Changes\\n\\n🍞 Bug fix: Toast messages are no longer blocked by st.chat_input (#7204, #7115).\\n🕸️\\xa0Bug fix: Widget IDs are now stable to prevent inconsistent statefulness (#7003).\\n🦟\\xa0Bug fix: Browser autofill is correctly recognized within forms now (#7150, #7101, #7084).\\n🪱 Bug fix: st.file_uploader no longer causes session state to reset when a websocket connection is dropped and reconnected (#7149, #7025).\\n🏎️ Bug fix: Pydeck JSON data is cached for improved performance (#7113, #5532).\\n🦋 Bug fix: st.chat_input no longer submits prematurely while typing with an input method editor (#6993).\\n🐞 Bug fix: Label backgrounds for st.tabs are now transparent (#7070, #5707).\\n🐝 Bug fix: Page width is no longer ignored when using the help parameter in st.button (#7033, #6161).\\n🐜 Bug fix: Tweaked Altair color specification for improved visibility in dark mode (#7061, #3343).\\n🪲\\xa0Bug fix: st.chat_message can correctly use local images as avatars (#7130).\\n🐛 Bug fix: Specified that MD5 is not used for security (#7122, #7120).\\n🪄 Bug fix: Async function docstrings are ignored by Streamlit magic (#7143, #7137).\\n\\nVersion 1.25.0\\nRelease date: July 20, 2023\\nHighlights\\n\\n🍞\\xa0Introducing st.toast — a command to briefly show toast messages to users in the bottom-right corner of apps. See our documentation on how to use this feature.\\n\\nNotable Changes\\n\\n🗺️\\xa0st.map now has parameters for latitude, longitude, color, and size to customize data points (#6896).\\n🚩\\xa0st.multiselect supports setting placeholders and specifying the maximum number of selections via the placeholder and max_selections keyword-only arguments, respectively (#6901, #4750). Thanks, @fhiroki!\\n📅\\xa0Customize the date format for st.date_input with the format parameter (#6974, #5234).\\n↩️ Forms can now be submitted with Enter/Return while inside st.text_input, st.number_input, or st.text_area (#6911, #3790).\\n🍢\\xa0The app menu icon in the upper-right corner of apps has been changed from \"☰\" to \"⋮\" (#6947).\\n\\nOther Changes\\n\\n⛓️ Minimum required versions increased for multiple Python dependencies, including numpy>=1.19.3 and pandas>=1.3.0 (#6802).\\n🛡️\\xa0protobufjs was bumped from 7.2.1 to 7.2.4 (#6959).\\n✨\\xa0Visual design tweaks to Streamlit\\'s input widgets (#6944).\\n🦋 Bug Fix: st.slider now accepts general number types like numpy.int64 instead of just int and float (#6816, #6815). Thanks, @milliams!\\n🐜\\xa0Bug Fix: Data labels for st.slider and st.select_slider no longer overflow when inside st.expander (#6828, #6297).\\n🐛\\xa0Bug Fix: Elements no longer re-render from scratch with each rerun (#6923, #6920).\\n🐞\\xa0Bug Fix: st.data_editor hashes styler objects correctly for stability across reruns (#6815, #6898).\\n🐝\\xa0Bug Fix: Fixed the padding for embedded apps using st.chat_input to prevent messages being cutoff (#6979).\\n\\nVersion 1.24.0\\nRelease date: June 27, 2023\\nHighlights\\n\\n💬 Introducing st.chat_message and st.chat_input — two new chat elements that let you build conversational apps. Learn how to use these features in your LLM-powered chat apps in our tutorial.\\n💾\\xa0Streamlit\\'s caching decorators now allow you to customize Streamlit\\'s hashing of input parameters with the keyword-only argument hash_funcs.\\n\\nNotable Changes\\n\\n🐍\\xa0We\\'ve deprecated support for Python 3.7 in the core library and Streamlit Community Cloud (#6868).\\n📅\\xa0st.cache_data and st.cache_resource can hash timezone-aware datetime objects (#6812, #6690, #5110).\\n\\nOther Changes\\n\\n✨\\xa0Visual design tweaks to Streamlit\\'s input widgets (#6817).\\n🐛\\xa0Bug fix: st.write pretty-prints dataclasses using st.help (#6750).\\n🪲\\xa0Bug fix: st.button\\'s height is consistent with that of other widgets (#6738).\\n🐜\\xa0Bug fix: Upgraded the react-range frontend dependency to fix the memory usage of sliders (#6764, #5436). Thanks @wolfd!\\n🐝\\xa0Bug fix: Pydantic validators no longer result in exceptions on app reruns (#6664, #3218).\\n🐞\\xa0Bug fix: streamlit config show honors newlines (#6758, #2868).\\n🪰\\xa0Bug fix: Fixed a race condition to ensure Streamlit reruns the latest code when the file changes (#6884).\\n🦋\\xa0Bug fix: Apps no longer rerun when users click anchor links (#6834, #6500).\\n🕸️\\xa0Bug fix: Added robust out-of-bounds checks for min_value and max_value in st.number_input (#6847, #6797).\\n\\nVersion 1.23.0\\nRelease date: June 1, 2023\\nHighlights\\n\\n✂️ Announcing the general availability of st.data_editor, a widget that allows you to edit DataFrames and many other data structures in a table-like UI. Breaking change: the data editor\\'s representation used in st.session_state was altered. Find out more about the new format in Access edited data.\\n⚙️ Introducing the Column configuration API with a suite of methods to configure the display and editing behavior of st.dataframe and st.data_editor columns (e.g. their title, visibility, type, or format). Keep an eye out for a detailed blog post and in-depth documentation upcoming in the next two weeks.\\n🔌 Learn to use st.experimental_connection to create and manage data connections in your apps with the new Connecting to data docs and video tutorial.\\n\\nNotable Changes\\n\\n📊\\xa0Streamlit now supports Protobuf 4 and Altair 5 (#6215, #6618, #5626, #6622).\\n☎️ st.dataframe and st.data_editor can hide index columns with hide_index, specify the display order of columns with column_order, and disable editing for individual columns with the disabled parameter.\\n⏱️ The ttl parameter in st.cache_data and st.cache_resource accepts formatted strings, so you can simply say ttl=\"30d\", ttl=\"1h30m\" and any other combination of w, d, h, m, s supported by Pandas\\'s Timedelta constructor (#6560).\\n📂 st.file_uploader now interprets the type parameter more accurately. For example, \"jpg\" or \".jpg\" now accept both \"jpg\" and \"jpeg\" extensions. This functionality has also been extended to \"mpeg/mpg\", \"tiff/tif\", \"html/htm\", and \"mpeg4/mp4\".\\n🤫\\xa0The new global.disableWidgetStateDuplicationWarning configuration option allows the silencing of warnings triggered by setting widget default values and keyed session state values concurrently (#3605, #6640). Thanks, @antonAce!\\n\\nOther Changes\\n\\n🏃\\u200d♀️Improved startup time by lazy loading some dependencies (#6531).\\n👋 Removed st.beta_* and st.experimental_show due to deprecation and low-use (#6558)\\n🚀\\xa0Further improvements to st.dataframe and st.data_editor:\\n\\nImproved editing on mobile devices for the data editor (#6548).\\nAll editable columns have an icon in their column header and support tooltips (#6550, #6561).\\nEnable editing for columns containing datetime, date, or time values (#6025).\\nNew input validation options for columns in the data editor, such as max_chars and validate for text columns, and min_value, max_value and step for number columns (#6563).\\nImproved type parsing capabilities in the data editor (#6551).\\nUnified missing values to None in returned data structures (#6544).\\nA warning is shown in cells when integers exceed the maximum safe value of (2^53) -1 (#6311, #6549).\\nPrevented editing the sessions state by showing a warning (#6634).\\nFixed issues with list columns sometimes breaking the frontend (#6644).\\nFixed a display issue with index columns using category dtype (#6680, #6598).\\nFixed an issue that prevented a rerun when adding empty rows (#6598).\\nUnified the behavior between st.data_editor and st.dataframe related to auto-hiding the index column(s) based on the input data (#6659, #6598)\\n\\n\\n🛡️\\xa0Streamlit\\'s Security Policy can be found in its GitHub repository (#6666).\\n🤏 Documented the integer size limit for st.number_input and st.slider (#6724).\\n🐍\\xa0The majority of Streamlit\\'s Python dependencies have set a maximum allowable version, with the standard upper limit set to the next major version, but not inclusive of it (#6691).\\n💅\\xa0UI design improvements to in-app modals (#6688).\\n🐞\\xa0Bug fix: st.date_input\\'s date selector is equally visible in dark mode (#6072, #6630).\\n🐜\\xa0Bug fix: the sidebar navigation expansion indicator in multipage apps is restored (#6731).\\n🐛\\xa0Bug fix: The docstring and exception message for st.set_page_config have been updated to clarify that this command can be invoked once for each page within a multipage app, rather than once per entire app (#6594).\\n🐝\\xa0Bug fix: st.json\\xa0no longer collapses multiple spaces in both keys and values with single space when rendered (#6657, #6663).\\n\\nVersion 1.22.0\\nRelease date: April 27, 2023\\nHighlights\\n\\n🔌\\xa0Introducing st.experimental_connection: Easily connect your app to data sources and APIs using our new connection feature. Find more details in the API reference, and stay tuned for an upcoming blog post and in-depth documentation! In the meantime, explore our updated MySQL and Snowflake connection tutorials for examples of this feature.\\n\\nNotable Changes\\n\\n🐼\\xa0Streamlit now supports Pandas 2.0 (#6413, #6378, #6507). Thanks, connortann!\\n🍔\\xa0Customize the visibility of items in the toolbar, options menu, and the settings dialog using the client.toolbarMode config option (#6174).\\n🪵\\xa0Streamlit logs now reside in the \"streamlit\" namespace instead of the root logger, enabling app developers to better manage log handling (#3978, #6377).\\n\\nOther Changes\\n\\n🔏\\xa0CLI parameters can no longer be used to set sensitive configuration values (#6376).\\n🤖\\xa0Improved the debugging experience by reducing log noise (#6391).\\n🐞\\xa0Bug fix:\\xa0@st.cache_data decorated functions support UUID objects as parameters (#6440, #6459).\\n🐛\\xa0Bug fix: Tabbing through buttons and other elements now displays a red border only when focused, not when clicked (#6373).\\n🪲\\xa0Bug fix: st.multiselect\\'s clear icon is larger and includes a hover effect (#6471).\\n🐜\\xa0Bug fix: Custom theme font settings no longer apply to code blocks (#6484, #6535).\\n©️\\xa0Bug fix: st.code\\'s copy-to-clipboard button appears when you hover on code blocks (#6490, #6498).\\n\\nOlder versions\\nAre you curious about older versions? To see older release notes, see Release notes (historical).Previous: Cheat sheetNext: Release notes (historical)forumStill have questions?Our forums are full of helpful information and Streamlit experts.HomeContact UsCommunity© 2024 Snowflake Inc.Cookie policyforum Ask AI')]"
105 | ]
106 | },
107 | "execution_count": 3,
108 | "metadata": {},
109 | "output_type": "execute_result"
110 | }
111 | ],
112 | "source": [
113 | "docs"
114 | ]
115 | },
116 | {
117 | "cell_type": "code",
118 | "execution_count": 4,
119 | "metadata": {},
120 | "outputs": [],
121 | "source": [
122 | "# Split docs\n",
123 | "\n",
124 | "text_splitter = RecursiveCharacterTextSplitter(\n",
125 | " chunk_size=5000,\n",
126 | " chunk_overlap=1000,\n",
127 | ")\n",
128 | "\n",
129 | "document_chunks = text_splitter.split_documents(docs)"
130 | ]
131 | },
132 | {
133 | "cell_type": "code",
134 | "execution_count": 5,
135 | "metadata": {},
136 | "outputs": [],
137 | "source": [
138 | "# Tokenize and load the documents to the vector store\n",
139 | "\n",
140 | "vector_db = Chroma.from_documents(\n",
141 | " documents=document_chunks,\n",
142 | " embedding=OpenAIEmbeddings(),\n",
143 | ")"
144 | ]
145 | },
146 | {
147 | "cell_type": "code",
148 | "execution_count": 6,
149 | "metadata": {},
150 | "outputs": [],
151 | "source": [
152 | "# Retrieve\n",
153 | "\n",
154 | "def _get_context_retriever_chain(vector_db, llm):\n",
155 | " retriever = vector_db.as_retriever()\n",
156 | " prompt = ChatPromptTemplate.from_messages([\n",
157 | " MessagesPlaceholder(variable_name=\"messages\"),\n",
158 | " (\"user\", \"{input}\"),\n",
159 | " (\"user\", \"Given the above conversation, generate a search query to look up in order to get inforamtion relevant to the conversation, focusing on the most recent messages.\"),\n",
160 | " ])\n",
161 | " retriever_chain = create_history_aware_retriever(llm, retriever, prompt)\n",
162 | "\n",
163 | " return retriever_chain"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": 7,
169 | "metadata": {},
170 | "outputs": [],
171 | "source": [
172 | "def get_conversational_rag_chain(llm):\n",
173 | " retriever_chain = _get_context_retriever_chain(vector_db, llm)\n",
174 | "\n",
175 | " prompt = ChatPromptTemplate.from_messages([\n",
176 | " (\"system\",\n",
177 | " \"\"\"You are a helpful assistant. You will have to answer to user's queries.\n",
178 | " You will have some context to help with your answers, but now always would be completely related or helpful.\n",
179 | " You can also use your knowledge to assist answering the user's queries.\\n\n",
180 | " {context}\"\"\"),\n",
181 | " MessagesPlaceholder(variable_name=\"messages\"),\n",
182 | " (\"user\", \"{input}\"),\n",
183 | " ])\n",
184 | " stuff_documents_chain = create_stuff_documents_chain(llm, prompt)\n",
185 | "\n",
186 | " return create_retrieval_chain(retriever_chain, stuff_documents_chain)"
187 | ]
188 | },
189 | {
190 | "cell_type": "code",
191 | "execution_count": 10,
192 | "metadata": {},
193 | "outputs": [
194 | {
195 | "name": "stdout",
196 | "output_type": "stream",
197 | "text": [
198 | "The latest version of Streamlit is 1.38.0, released on August 27, 2024. Would you like to know more about the highlights or changes in this version?"
199 | ]
200 | }
201 | ],
202 | "source": [
203 | "# Augmented Generation\n",
204 | "\n",
205 | "llm_stream_openai = ChatOpenAI(\n",
206 | " model=\"gpt-4o\", # Here you could use \"o1-preview\" or \"o1-mini\" if you already have access to them\n",
207 | " temperature=0.3,\n",
208 | " streaming=True,\n",
209 | ")\n",
210 | "\n",
211 | "llm_stream_anthropic = ChatAnthropic(\n",
212 | " model=\"claude-3-5-sonnet-20240620\",\n",
213 | " temperature=0.3,\n",
214 | " streaming=True,\n",
215 | ")\n",
216 | "\n",
217 | "llm_stream = llm_stream_openai # Select between OpenAI and Anthropic models for the response\n",
218 | "\n",
219 | "messages = [\n",
220 | " {\"role\": \"user\", \"content\": \"Hi\"},\n",
221 | " {\"role\": \"assistant\", \"content\": \"Hi there! How can I assist you today?\"},\n",
222 | " {\"role\": \"user\", \"content\": \"What is the latest version of Streamlit?\"},\n",
223 | "]\n",
224 | "messages = [HumanMessage(content=m[\"content\"]) if m[\"role\"] == \"user\" else AIMessage(content=m[\"content\"]) for m in messages]\n",
225 | "\n",
226 | "conversation_rag_chain = get_conversational_rag_chain(llm_stream)\n",
227 | "response_message = \"*(RAG Response)*\\n\"\n",
228 | "for chunk in conversation_rag_chain.pick(\"answer\").stream({\"messages\": messages[:-1], \"input\": messages[-1].content}):\n",
229 | " response_message += chunk\n",
230 | " print(chunk, end=\"\", flush=True)\n",
231 | "\n",
232 | "messages.append({\"role\": \"assistant\", \"content\": response_message})"
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": null,
238 | "metadata": {},
239 | "outputs": [],
240 | "source": []
241 | },
242 | {
243 | "cell_type": "code",
244 | "execution_count": 2,
245 | "metadata": {},
246 | "outputs": [
247 | {
248 | "name": "stdout",
249 | "output_type": "stream",
250 | "text": [
251 | "Sure! Microsoft Azure, commonly referred to as Azure, is a cloud computing platform and service created by Microsoft. It provides a wide range of cloud services, including those for computing, analytics, storage, and networking. Users can choose and configure these services to develop and scale new applications or run existing applications in the public cloud.\n",
252 | "\n",
253 | "Here are some key aspects of Azure:\n",
254 | "\n",
255 | "1. **Compute Services**: Azure offers virtual machines, containers, and serverless computing options. This includes Azure Virtual Machines, Azure Kubernetes Service (AKS), and Azure Functions.\n",
256 | "\n",
257 | "2. **Storage Solutions**: Azure provides scalable cloud storage solutions such as Azure Blob Storage, Azure Disk Storage, and Azure File Storage. These services cater to different data storage needs, from unstructured data to persistent disk storage.\n",
258 | "\n",
259 | "3. **Networking**: Azure offers a variety of networking services, including Azure Virtual Network, Azure Load Balancer, and Azure Application Gateway. These services help in building secure and high-performance network architectures.\n",
260 | "\n",
261 | "4. **Databases**: Azure supports multiple database services, including Azure SQL Database, Azure Cosmos DB, and Azure Database for MySQL, PostgreSQL, and MariaDB. These managed database services offer high availability, scalability, and security.\n",
262 | "\n",
263 | "5. **AI and Machine Learning**: Azure provides a suite of AI and machine learning services, such as Azure Machine Learning, Azure Cognitive Services, and Azure Bot Service. These tools help developers build intelligent applications.\n",
264 | "\n",
265 | "6. **Analytics**: Azure offers a range of analytics services, including Azure Synapse Analytics, Azure HDInsight, and Azure Data Lake Analytics. These services enable big data processing and advanced analytics.\n",
266 | "\n",
267 | "7. **DevOps**: Azure DevOps provides development tools for continuous integration and continuous delivery (CI/CD). It includes services like Azure Pipelines, Azure Repos, and Azure Artifacts.\n",
268 | "\n",
269 | "8. **Security and Compliance**: Azure emphasizes security with services like Azure Security Center, Azure Active Directory, and Azure Key Vault. It also complies with numerous international and industry-specific standards.\n",
270 | "\n",
271 | "9. **IoT**: Azure IoT Hub and Azure IoT Central are services designed to connect, monitor, and manage IoT devices at scale.\n",
272 | "\n",
273 | "10. **Hybrid Cloud**: Azure supports hybrid cloud environments with services like Azure Arc and Azure Stack, allowing businesses to run Azure services on-premises or in other cloud environments.\n",
274 | "\n",
275 | "11. **Management and Governance**: Azure provides tools for managing and governing cloud resources, such as Azure Policy, Azure Cost Management, and Azure Monitor.\n",
276 | "\n",
277 | "Azure is known for its global reach, with data centers in numerous regions worldwide, providing low-latency access and data residency options. It supports a wide range of programming languages, frameworks, and operating systems, making it a versatile choice for developers and enterprises.\n",
278 | "\n",
279 | "Overall, Azure is a comprehensive cloud platform that helps organizations innovate, scale, and manage their IT resources efficiently."
280 | ]
281 | }
282 | ],
283 | "source": [
284 | "import os\n",
285 | "from langchain_openai import AzureChatOpenAI\n",
286 | "import dotenv\n",
287 | "\n",
288 | "dotenv.load_dotenv()\n",
289 | "\n",
290 | "llm_stream = AzureChatOpenAI(\n",
291 | " azure_endpoint=os.getenv(\"AZ_OPENAI_ENDPOINT\"),\n",
292 | " openai_api_version=\"2024-02-15-preview\",\n",
293 | " model_name=\"gpt-4o\",\n",
294 | " openai_api_key=os.getenv(\"AZ_OPENAI_API_KEY\"),\n",
295 | " openai_api_type=\"azure\",\n",
296 | " temperature=0.3,\n",
297 | " streaming=True,\n",
298 | ")\n",
299 | "\n",
300 | "prompt = \"Tell me something about Azure\"\n",
301 | "\n",
302 | "for chunk in llm_stream.stream(prompt):\n",
303 | " print(chunk.content, end=\"\", flush=True)"
304 | ]
305 | }
306 | ],
307 | "metadata": {
308 | "kernelspec": {
309 | "display_name": "venv",
310 | "language": "python",
311 | "name": "python3"
312 | },
313 | "language_info": {
314 | "codemirror_mode": {
315 | "name": "ipython",
316 | "version": 3
317 | },
318 | "file_extension": ".py",
319 | "mimetype": "text/x-python",
320 | "name": "python",
321 | "nbconvert_exporter": "python",
322 | "pygments_lexer": "ipython3",
323 | "version": "3.11.5"
324 | }
325 | },
326 | "nbformat": 4,
327 | "nbformat_minor": 2
328 | }
329 |
--------------------------------------------------------------------------------
/rag_methods.py:
--------------------------------------------------------------------------------
1 | import os
2 | import dotenv
3 | from time import time
4 | import streamlit as st
5 |
6 | from langchain_community.document_loaders.text import TextLoader
7 | from langchain_community.document_loaders import (
8 | WebBaseLoader,
9 | PyPDFLoader,
10 | Docx2txtLoader,
11 | )
12 | # pip install docx2txt, pypdf
13 | from langchain_community.vectorstores import Chroma
14 | from langchain.text_splitter import RecursiveCharacterTextSplitter
15 | from langchain_openai import OpenAIEmbeddings, AzureOpenAIEmbeddings
16 | from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
17 | from langchain.chains import create_history_aware_retriever, create_retrieval_chain
18 | from langchain.chains.combine_documents import create_stuff_documents_chain
19 |
20 | dotenv.load_dotenv()
21 |
22 | os.environ["USER_AGENT"] = "myagent"
23 | DB_DOCS_LIMIT = 10
24 |
25 | # Function to stream the response of the LLM
26 | def stream_llm_response(llm_stream, messages):
27 | response_message = ""
28 |
29 | for chunk in llm_stream.stream(messages):
30 | response_message += chunk.content
31 | yield chunk
32 |
33 | st.session_state.messages.append({"role": "assistant", "content": response_message})
34 |
35 |
36 | # --- Indexing Phase ---
37 |
38 | def load_doc_to_db():
39 | # Use loader according to doc type
40 | if "rag_docs" in st.session_state and st.session_state.rag_docs:
41 | docs = []
42 | for doc_file in st.session_state.rag_docs:
43 | if doc_file.name not in st.session_state.rag_sources:
44 | if len(st.session_state.rag_sources) < DB_DOCS_LIMIT:
45 | os.makedirs("source_files", exist_ok=True)
46 | file_path = f"./source_files/{doc_file.name}"
47 | with open(file_path, "wb") as file:
48 | file.write(doc_file.read())
49 |
50 | try:
51 | if doc_file.type == "application/pdf":
52 | loader = PyPDFLoader(file_path)
53 | elif doc_file.name.endswith(".docx"):
54 | loader = Docx2txtLoader(file_path)
55 | elif doc_file.type in ["text/plain", "text/markdown"]:
56 | loader = TextLoader(file_path)
57 | else:
58 | st.warning(f"Document type {doc_file.type} not supported.")
59 | continue
60 |
61 | docs.extend(loader.load())
62 | st.session_state.rag_sources.append(doc_file.name)
63 |
64 | except Exception as e:
65 | st.toast(f"Error loading document {doc_file.name}: {e}", icon="⚠️")
66 | print(f"Error loading document {doc_file.name}: {e}")
67 |
68 | finally:
69 | os.remove(file_path)
70 |
71 | else:
72 | st.error(F"Maximum number of documents reached ({DB_DOCS_LIMIT}).")
73 |
74 | if docs:
75 | _split_and_load_docs(docs)
76 | st.toast(f"Document *{str([doc_file.name for doc_file in st.session_state.rag_docs])[1:-1]}* loaded successfully.", icon="✅")
77 |
78 |
79 | def load_url_to_db():
80 | if "rag_url" in st.session_state and st.session_state.rag_url:
81 | url = st.session_state.rag_url
82 | docs = []
83 | if url not in st.session_state.rag_sources:
84 | if len(st.session_state.rag_sources) < 10:
85 | try:
86 | loader = WebBaseLoader(url)
87 | docs.extend(loader.load())
88 | st.session_state.rag_sources.append(url)
89 |
90 | except Exception as e:
91 | st.error(f"Error loading document from {url}: {e}")
92 |
93 | if docs:
94 | _split_and_load_docs(docs)
95 | st.toast(f"Document from URL *{url}* loaded successfully.", icon="✅")
96 |
97 | else:
98 | st.error("Maximum number of documents reached (10).")
99 |
100 |
101 | def initialize_vector_db(docs):
102 | if "AZ_OPENAI_API_KEY" not in os.environ:
103 | embedding = OpenAIEmbeddings(api_key=st.session_state.openai_api_key)
104 | else:
105 | embedding = AzureOpenAIEmbeddings(
106 | api_key=os.getenv("AZ_OPENAI_API_KEY"),
107 | azure_endpoint=os.getenv("AZ_OPENAI_ENDPOINT"),
108 | model="text-embedding-3-large",
109 | openai_api_version="2024-02-15-preview",
110 | )
111 |
112 | vector_db = Chroma.from_documents(
113 | documents=docs,
114 | embedding=embedding,
115 | collection_name=f"{str(time()).replace('.', '')[:14]}_" + st.session_state['session_id'],
116 | )
117 |
118 | # We need to manage the number of collections that we have in memory, we will keep the last 20
119 | chroma_client = vector_db._client
120 | collection_names = sorted([collection.name for collection in chroma_client.list_collections()])
121 | print("Number of collections:", len(collection_names))
122 | while len(collection_names) > 20:
123 | chroma_client.delete_collection(collection_names[0])
124 | collection_names.pop(0)
125 |
126 | return vector_db
127 |
128 |
129 | def _split_and_load_docs(docs):
130 | text_splitter = RecursiveCharacterTextSplitter(
131 | chunk_size=5000,
132 | chunk_overlap=1000,
133 | )
134 |
135 | document_chunks = text_splitter.split_documents(docs)
136 |
137 | if "vector_db" not in st.session_state:
138 | st.session_state.vector_db = initialize_vector_db(docs)
139 | else:
140 | st.session_state.vector_db.add_documents(document_chunks)
141 |
142 |
143 | # --- Retrieval Augmented Generation (RAG) Phase ---
144 |
145 | def _get_context_retriever_chain(vector_db, llm):
146 | retriever = vector_db.as_retriever()
147 | prompt = ChatPromptTemplate.from_messages([
148 | MessagesPlaceholder(variable_name="messages"),
149 | ("user", "{input}"),
150 | ("user", "Given the above conversation, generate a search query to look up in order to get inforamtion relevant to the conversation, focusing on the most recent messages."),
151 | ])
152 | retriever_chain = create_history_aware_retriever(llm, retriever, prompt)
153 |
154 | return retriever_chain
155 |
156 |
157 | def get_conversational_rag_chain(llm):
158 | retriever_chain = _get_context_retriever_chain(st.session_state.vector_db, llm)
159 |
160 | prompt = ChatPromptTemplate.from_messages([
161 | ("system",
162 | """You are a helpful assistant. You will have to answer to user's queries.
163 | You will have some context to help with your answers, but now always would be completely related or helpful.
164 | You can also use your knowledge to assist answering the user's queries.\n
165 | {context}"""),
166 | MessagesPlaceholder(variable_name="messages"),
167 | ("user", "{input}"),
168 | ])
169 | stuff_documents_chain = create_stuff_documents_chain(llm, prompt)
170 |
171 | return create_retrieval_chain(retriever_chain, stuff_documents_chain)
172 |
173 |
174 | def stream_llm_rag_response(llm_stream, messages):
175 | conversation_rag_chain = get_conversational_rag_chain(llm_stream)
176 | response_message = "*(RAG Response)*\n"
177 | for chunk in conversation_rag_chain.pick("answer").stream({"messages": messages[:-1], "input": messages[-1].content}):
178 | response_message += chunk
179 | yield chunk
180 |
181 | st.session_state.messages.append({"role": "assistant", "content": response_message})
182 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Do your LLM even RAG bro?
2 |
3 | RAG web application using Python, Streamlit and LangChain, so you can chat with Documents, Websites and other custom data.
4 |
5 | To run it locally:
6 |
7 | ```bash
8 | $ git clone
9 |
10 | $ cd
11 |
12 | $ python -m venv venv
13 |
14 | $ venv\Scripts\activate # or source venv/bin/activate in Linux/Mac
15 |
16 | $ pip install -r requirements.txt
17 |
18 | $ streamlit run app.py
19 | ```
20 |
21 | Video: https://youtu.be/abMwFViFFhI
22 | Blog: https://medium.com/@enricdomingo
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enricd/rag_llm_app/660b044cec7eeb0755791cfe5c81771a96b0a142/requirements.txt
--------------------------------------------------------------------------------