From 527598587368c25465a63476811eff3f340f6266 Mon Sep 17 00:00:00 2001 From: tcsenpai Date: Tue, 17 Sep 2024 12:35:52 +0200 Subject: [PATCH] added logging and some smooooooth animations --- .gitignore | 3 ++ README.md | 15 +++--- __pycache__/api_handlers.cpython-310.pyc | Bin 4789 -> 0 bytes __pycache__/utils.cpython-310.pyc | Bin 2421 -> 0 bytes app/logger.py | 27 ++++++++++ app/main.py | 31 ++++++++---- static/styles.css | 61 +++++++++++++++++++++++ 7 files changed, 121 insertions(+), 16 deletions(-) delete mode 100644 __pycache__/api_handlers.cpython-310.pyc delete mode 100644 __pycache__/utils.cpython-310.pyc create mode 100644 app/logger.py diff --git a/.gitignore b/.gitignore index 3dab6f8..24a487b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ env/ venv/ ENV/ +# Logs +logs/ + # Streamlit .streamlit/ diff --git a/README.md b/README.md index 502c276..a803dc2 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,18 @@ ## Features -- [x] Using Llama-3.1 70b on Groq to create o1-like reasoning chains -- [x] Using Ollama to create o1-like reasoning chains -- [x] Using Perplexity to create o1-like reasoning chains - [x] Using an unified interface to try out different providers +- [x] Configuring the app from the sidebar + +## Providers + +- [x] Ollama (local) +- [x] Perplexity (remote, requires API key) +- [x] Groq (remote, requires API key) ## Work in progress - [ ] Add more providers -- [ ] Use something like LiteLLM to unify models code and avoid repeating code for each provider ## Example @@ -61,12 +64,12 @@ To use the launcher, follow these instructions: cp example.env .env ``` -3. Edit the .env file with your API keys / models preferences. +3. Edit the .env file with your API keys / models preferences (or do it from the app's configuration menu) 4. Run the main interface ``` - streamlit run main.py + streamlit run app/main.py ``` --- diff --git a/__pycache__/api_handlers.cpython-310.pyc b/__pycache__/api_handlers.cpython-310.pyc deleted file mode 100644 index 275a2fc1169a2c01387f911a6ae07a6989fcea0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4789 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 diff --git a/__pycache__/utils.cpython-310.pyc b/__pycache__/utils.cpython-310.pyc deleted file mode 100644 index b6073407a01c0d299cd3e8dc21063d13b863c3fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2421 zcmaJ@TW{Mo6sBm&w>W8f3tC_g>~5X`$7$9A9kQXAny8IB*)nXoX|e}HF&RgVEP0}w zG=U6k*dF$>U(gPSANNo88}z!T>?aJ{x5niX?DGsb;1&d}UgrTMW|KruQ+6Ew~y%BhlITAbi< zZbr)|`6PP_jSGpE6ds_lmSj#bolDeLh?bHZoxhD+#K`_>PB}M4RGM1QA_oq*;EWPk2BGb6MBIoGHz4fg zkVP@kP2zIy@z@Pw67RdQVEC>VaB>`uA`&r|hk+OL34jdA?y;O}tTY2D~!ZrlCOdf~kx^trFJ{fp+A@`#@!+7X~p4;u_gt zJ%Q@&31t#6M#1$EM53uX;KYn@(6Uc^p-*F z$7I{?w1{QaO-FZ3yCJpo2C=L<(Hk3NYZDYfhO7fo5MXZD4%x74#B5Bp&+S%$v~G1a z3}QTQT6Rk!3M0DZ7_A0;J_E~*_Lk9V*T_0pGdGNugs!t`P__XeH08xZ_MmDC7$`n9Mgdx4zY}xwyCUI;C5otq|U=jg)+5wOL z3w@Ty^AwS~;cVI)Z3$zvMA!g+7P_hMBeBC~3%oMdVNVsDs!`~(G&ifPR2^{^rG@jh zJ4u{go9yWbAJftOgHeBvVvI|^F!r<~rkhqc&-MK@>kfx3psD%-j;~asqrs4;+A#8hIMpDA zkO2+C=M5`!X%=EJ7{=+G(1uh{AGrAev0&nephA)0@{@x zfB>Xmx-Ljz>c(!G2REj~`AhQCT?wIIP()z2f4sLMzE*l61=N+$UtQ_1u8d;O=e6N+ zdbQ627P&F&M)D}*EDK8f84UPaoWY9vcV5L<%<3O%NmWz@>fDh!%b>Ij>35@LK7gWF zUj6j5gXJ*ry?|BJ=mXe8^r09&62r$ZK(peIr`bM(`{z*R JGnXlS{tttLt3m(( diff --git a/app/logger.py b/app/logger.py new file mode 100644 index 0000000..52eeeec --- /dev/null +++ b/app/logger.py @@ -0,0 +1,27 @@ +import logging +import os +from datetime import datetime + +def setup_logger(): + # Create a logs directory if it doesn't exist + log_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs') + os.makedirs(log_dir, exist_ok=True) + + # Create a unique log file name based on the current timestamp + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + log_file = os.path.join(log_dir, f"multi1_{timestamp}.log") + + # Configure the logger + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler(log_file), + logging.StreamHandler() # This will also print logs to console + ] + ) + + return logging.getLogger('multi1') + +# Create a global logger instance +logger = setup_logger() \ No newline at end of file diff --git a/app/main.py b/app/main.py index 696268a..b460c6e 100644 --- a/app/main.py +++ b/app/main.py @@ -3,6 +3,7 @@ from dotenv import load_dotenv from api_handlers import OllamaHandler, PerplexityHandler, GroqHandler from utils import generate_response from config_menu import config_menu, display_config +from logger import logger import os # Load environment variables @@ -36,6 +37,7 @@ def get_api_handler(backend, config): return GroqHandler(config['GROQ_API_KEY'], config['GROQ_MODEL']) def main(): + logger.info("Starting the application") setup_page() st.sidebar.markdown('', unsafe_allow_html=True) @@ -44,26 +46,35 @@ def main(): backend = st.sidebar.selectbox("Choose AI Backend", ["Ollama", "Perplexity AI", "Groq"]) display_config(backend, config) api_handler = get_api_handler(backend, config) + logger.info(f"Selected backend: {backend}") user_query = st.text_input("💬 Enter your query:", placeholder="e.g., How many 'R's are in the word strawberry?") if user_query: + logger.info(f"Received user query: {user_query}") st.write("🔍 Generating response...") response_container = st.empty() time_container = st.empty() - for steps, total_thinking_time in generate_response(user_query, api_handler): - with response_container.container(): - for title, content, _ in steps: - if title.startswith("Final Answer"): - st.markdown(f'

🎯 {title}

', unsafe_allow_html=True) - st.markdown(f'
{content}
', unsafe_allow_html=True) - else: - with st.expander(f"📝 {title}", expanded=True): + try: + for steps, total_thinking_time in generate_response(user_query, api_handler): + with response_container.container(): + for title, content, _ in steps: + if title.startswith("Final Answer"): + st.markdown(f'

🎯 {title}

', unsafe_allow_html=True) st.markdown(f'
{content}
', unsafe_allow_html=True) + logger.info(f"Final answer generated: {content}") + else: + with st.expander(f"📝 {title}", expanded=True): + st.markdown(f'
{content}
', unsafe_allow_html=True) + logger.debug(f"Step completed: {title}") - if total_thinking_time is not None: - time_container.markdown(f'

⏱️ Total thinking time: {total_thinking_time:.2f} seconds

', unsafe_allow_html=True) + if total_thinking_time is not None: + time_container.markdown(f'

⏱️ Total thinking time: {total_thinking_time:.2f} seconds

', unsafe_allow_html=True) + logger.info(f"Total thinking time: {total_thinking_time:.2f} seconds") + except Exception as e: + logger.error(f"Error generating response: {str(e)}", exc_info=True) + st.error("An error occurred while generating the response. Please try again.") if __name__ == "__main__": main() \ No newline at end of file diff --git a/static/styles.css b/static/styles.css index d2ee572..e77fd67 100644 --- a/static/styles.css +++ b/static/styles.css @@ -27,3 +27,64 @@ h1, h2, h3, h4, h5, h6 { font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-weight: bold; } + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes slideIn { + from { transform: translateY(20px); opacity: 0; } + to { transform: translateY(0); opacity: 1; } +} + +@keyframes pulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } +} + +/* Apply fade-in animation to main content */ +.main .block-container { + animation: fadeIn 0.5s ease-out; +} + +/* Apply slide-in animation to expanders */ +.streamlit-expanderHeader { + animation: slideIn 0.3s ease-out; + transition: background-color 0.3s ease; +} + +/* Smooth transition for expander content */ +.streamlit-expanderContent { + transition: max-height 0.3s ease-out, opacity 0.3s ease-out; +} + +/* Pulse animation for thinking time */ +.thinking-time { + animation: pulse 2s infinite; +} + +/* Hover effect for buttons */ +.stButton > button { + transition: all 0.3s ease; +} + +.stButton > button:hover { + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0,0,0,0.1); +} + +/* Smooth transition for selectbox */ +.stSelectbox { + transition: all 0.3s ease; +} + +/* Subtle hover effect for text input */ +.stTextInput > div > div > input { + transition: all 0.3s ease; +} + +.stTextInput > div > div > input:hover { + box-shadow: 0 0 0 1px rgba(49, 51, 63, 0.2); +}