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 275a2fc..0000000 Binary files a/__pycache__/api_handlers.cpython-310.pyc and /dev/null differ diff --git a/__pycache__/utils.cpython-310.pyc b/__pycache__/utils.cpython-310.pyc deleted file mode 100644 index b607340..0000000 Binary files a/__pycache__/utils.cpython-310.pyc and /dev/null differ 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); +}