Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Server #36

Merged
merged 11 commits into from
Oct 17, 2024
190 changes: 190 additions & 0 deletions app/src/content/api_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
"""
Copyright (c) 2023, 2024, Oracle and/or its affiliates.
Licensed under the Universal Permissive License v1.0 as shown at http://oss.oracle.com/licenses/upl.
"""

# spell-checker:ignore streamlit
import inspect
import threading
import time

# Streamlit
import streamlit as st
from streamlit import session_state as state

# Utilities
import modules.st_common as st_common
import modules.api_server as api_server

import modules.logging_config as logging_config

logger = logging_config.logging.getLogger("api_server")


#############################################################################
# Functions
#############################################################################
def initialize_streamlit():
"""initialize Streamlit Session State"""
if "api_server_config" not in state:
state.api_server_config = api_server.config()
logger.info("initialized API Server Config")


def display_logs():
log_placeholder = st.empty() # A placeholder to update logs
logs = [] # Store logs for display

try:
while "server_thread" in st.session_state:
try:
# Retrieve log from queue (non-blocking)
log_item = api_server.log_queue.get_nowait()
logs.append(log_item)
# Update the placeholder with new logs
log_placeholder.text("\n".join(logs))
except api_server.queue.Empty:
time.sleep(0.1) # Avoid busy-waiting
finally:
logger.info("API Server events display has stopped.")


def api_server_start():
state.api_server_config["port"] = state.user_api_server_port
state.api_server_config["key"] = state.user_api_server_key
if "initialized" in state and state.initialized:
if "server_thread" not in state:
state.httpd = api_server.run_server(
state.api_server_config["port"],
state.chat_manager,
state.rag_params,
state.lm_instr,
state.context_instr,
state.api_server_config["key"],
)

# Start the server in the thread
def api_server_process(httpd):
httpd.serve_forever()

state.server_thread = threading.Thread(
target=api_server_process,
# Trailing , ensures tuple is passed
args=(state.httpd,),
daemon=True,
)
state.server_thread.start()
logger.info("Started API Server on port: %i", state.api_server_config["port"])
else:
st.warning("API Server is already running.")
else:
logger.warning("Unable to start API Server; ChatMgr not configured")
st.warning("Failed to start API Server: Chatbot not initialized.")


def api_server_stop():
if "server_thread" in state:
if state.server_thread.is_alive():
state.httpd.shutdown() # Shut down the server
state.server_thread.join() # Wait for the thread to exit

del state.server_thread # Clean up the thread reference
del state.httpd # Clean up the server reference

logger.info("API Server stopped successfully.")
st.success("API Server stopped successfully.")
else:
logger.warning("API Server thread is not running - cleaning up.")
st.warning("API Server thread is not running.")
del state.server_thread
else:
logger.info("Unable to stop API Server - not running.")


#############################################################################
# MAIN
#############################################################################
def main():
"""Streamlit GUI"""
initialize_streamlit()
st.header("API Server")

# LLM Params
ll_model = st_common.lm_sidebar()

# Initialize RAG
st_common.initialize_rag()

# RAG
st_common.rag_sidebar()

#########################################################################
# Initialize the Client
#########################################################################
if "initialized" not in state:
if not state.rag_params["enable"] or all(
state.rag_params[key] for key in ["model", "chunk_size", "chunk_overlap", "distance_metric"]
):
try:
state.chat_manager = st_common.initialize_chatbot(ll_model)
state.initialized = True
st_common.update_rag()
logger.debug("Force rerun to save state")
if "server_thread" in state:
logger.info("Restarting API Server")
api_server_stop()
api_server_start()
st.rerun()
except Exception as ex:
logger.exception(ex, exc_info=False)
st.error(f"Failed to initialize the chat client: {ex}")
st_common.clear_initialized()
if st.button("Retry", key="retry_initialize"):
st.rerun()
st.stop()
else:
# RAG Enabled but not configured
if "server_thread" in state:
logger.info("Stopping API Server")
api_server_stop()

#########################################################################
# API Server
#########################################################################
server_running = False
if "server_thread" in state:
server_running = True
st.success("API Server is Running")

left, right = st.columns([0.2, 0.8])
left.number_input(
"API Server Port:",
value=state.api_server_config["port"],
min_value=1,
max_value=65535,
key="user_api_server_port",
disabled=server_running,
)
right.text_input(
"API Server Key:",
type="password",
value=state.api_server_config["key"],
key="user_api_server_key",
disabled=server_running,
)

if "server_thread" in state:
st.button("Stop Server", type="primary", on_click=api_server_stop)
elif "initialized" in state and state.initialized:
st.button("Start Server", type="primary", on_click=api_server_start)
else:
st.error("Not all required RAG options are set, please review or disable RAG.")

st.subheader("Activity")
if "server_thread" in state:
with st.container(border=True):
display_logs()


if __name__ == "__main__" or "page.py" in inspect.stack()[1].filename:
main()
4 changes: 0 additions & 4 deletions app/src/content/chatbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import modules.st_common as st_common
import modules.logging_config as logging_config
import modules.chatbot as chatbot
import modules.chatbot_server as chatbot_server

# History
from langchain_community.chat_message_histories import StreamlitChatMessageHistory
Expand Down Expand Up @@ -100,9 +99,6 @@ def main():
# RAG
st_common.rag_sidebar()

# Chatbot
chatbot_server.chatbot_sidebar()

# Save
st_common.save_settings_sidebar()
#########################################################################
Expand Down
2 changes: 1 addition & 1 deletion app/src/content/model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def main():
"""Streamlit GUI"""
css = """
<style>
div[data-testid="element-container"] .stCheckbox {
div[data-testid="stElementContainer"] .stCheckbox {
min-height: 2.5em !important;
}
</style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# Utilities
import modules.logging_config as logging_config

logger = logging_config.logging.getLogger("import_settings")
logger = logging_config.logging.getLogger("settings")


#############################################################################
Expand Down
1 change: 1 addition & 0 deletions app/src/content/split_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ def main():
st.header("Load and Split Documents", divider="rainbow")
file_source = st.radio("File Source:", file_sources, key="radio_file_source", horizontal=True)
populate_button_disabled = True
button_help = None

######################################
# Local Source
Expand Down
Loading