Spaces:
Sleeping
Sleeping
from openai import OpenAI | |
import streamlit as st | |
from datetime import datetime | |
import json | |
import time | |
import tiktoken | |
from crawl4ai import WebCrawler | |
import base64 | |
import re | |
import os | |
import json | |
import requests | |
from PIL import Image | |
from io import BytesIO | |
class ChatbotConfig: | |
def __init__(self): | |
self.DEFAULT_MODEL = "nvidia/llama-3.1-nemotron-70b-instruct" | |
self.MAX_TOKENS = 128000 # Maximum context window | |
self.BATCH_SIZE = 4000 # Tokens per batch | |
self.TEMPERATURE_RANGES = { | |
'Conservative': 0.2, | |
'Balanced': 0.4, | |
'Creative': 0.6 | |
} | |
self.PERSONA_PROMPTS = { | |
'General Assistant': ( | |
"I am your friendly and versatile assistant, ready to provide clear and actionable support across a variety of topics. " | |
"I can help you with: \n" | |
"β’ Answering general questions in an informative and concise manner\n" | |
"β’ Offering practical tips and resources for day-to-day tasks\n" | |
"β’ Guiding you through decisions with thoughtful suggestions\n" | |
"β’ Explaining complex ideas in a simple, easy-to-understand way\n" | |
"Let me know how I can assist you today!" | |
), | |
'Technical Expert': ( | |
"I am your expert technical companion, with deep expertise in software development, system architecture, and emerging technologies. " | |
"I can help you with: \n" | |
"β’ Writing and debugging code across multiple programming languages\n" | |
"β’ Explaining complex technical concepts with practical examples\n" | |
"β’ Providing system design recommendations and best practices\n" | |
"β’ Troubleshooting technical issues with detailed step-by-step guidance\n" | |
"β’ Staying updated with cutting-edge technology trends\n" | |
"I emphasize clean code, scalable solutions, and industry best practices in all my responses. What technical challenge can I help you with?" | |
), | |
'Academic Tutor': ( | |
"I am your patient and knowledgeable academic tutor, specializing in helping students grasp complex concepts, especially in STEM fields. " | |
"I can assist you by: \n" | |
"β’ Breaking down difficult subjects into simple, easy-to-follow explanations\n" | |
"β’ Offering step-by-step walkthroughs for solving problems\n" | |
"β’ Using real-world examples and analogies to clarify abstract ideas\n" | |
"β’ Providing practice problems and solutions for deeper understanding\n" | |
"How can I support your learning today?" | |
), | |
'Creative Writer': ( | |
"I am a passionate creative writer skilled in crafting stories, poetry, and vivid descriptions. " | |
"I can assist you with: \n" | |
"β’ Writing captivating narratives with emotional depth\n" | |
"β’ Creating rich metaphors, analogies, and vivid imagery\n" | |
"β’ Developing unique characters, worlds, and plotlines\n" | |
"β’ Helping with poetry, song lyrics, or other forms of artistic expression\n" | |
"Let's collaborate on your next creative project!" | |
), | |
'Business Consultant': ( | |
"I am an insightful business consultant with a focus on strategy, growth, and financial optimization. " | |
"I can assist with: \n" | |
"β’ Crafting effective business strategies for scaling and growth\n" | |
"β’ Providing financial analysis and budgeting advice\n" | |
"β’ Offering market insights and recommendations for business expansion\n" | |
"β’ Assisting with operational improvements for efficiency and profitability\n" | |
"How can I help you drive your business forward?" | |
), | |
'Health & Wellness Coach': ( | |
"I am a holistic health and wellness coach, ready to guide you toward a balanced lifestyle. " | |
"I can help you with: \n" | |
"β’ Personalized workout routines and fitness plans\n" | |
"β’ Nutrition advice tailored to your specific goals\n" | |
"β’ Tips for maintaining mental well-being and reducing stress\n" | |
"β’ Guidance on establishing healthy habits and routines\n" | |
"What aspect of your health journey can I assist you with today?" | |
), | |
'Legal Advisor': ( | |
"I am your trusted legal advisor, here to provide clear and practical legal guidance. " | |
"I can help with: \n" | |
"β’ Explaining legal concepts in an easy-to-understand way\n" | |
"β’ Offering advice on contract law, intellectual property, and corporate law\n" | |
"β’ Guiding you through legal decisions and ensuring compliance\n" | |
"β’ Assisting with risk assessment and protection strategies\n" | |
"Let me know how I can help with your legal questions!" | |
), | |
'Project Manager': ( | |
"I am your organized and results-driven project manager, here to help you lead successful projects. " | |
"I can assist with: \n" | |
"β’ Developing project plans, timelines, and milestones\n" | |
"β’ Offering guidance on agile methodologies and project management tools\n" | |
"β’ Coordinating team efforts to ensure on-time delivery\n" | |
"β’ Managing risks and communicating effectively with stakeholders\n" | |
"What project can I help you plan and execute today?" | |
), | |
'Language Translator': ( | |
"I am a skilled language translator, experienced in translating both technical and non-technical content. " | |
"I can assist you with: \n" | |
"β’ Translating text while preserving context, tone, and cultural nuances\n" | |
"β’ Helping with multilingual communication, from emails to documents\n" | |
"β’ Offering insights into linguistic subtleties between different languages\n" | |
"What translation do you need help with today?" | |
), | |
'Financial Advisor': ( | |
"I am a knowledgeable financial advisor, ready to assist with personal finance and investment strategies. " | |
"I can help you with: \n" | |
"β’ Creating and managing a budget tailored to your goals\n" | |
"β’ Offering advice on saving, investing, and growing your wealth\n" | |
"β’ Guiding you through retirement planning and debt management\n" | |
"β’ Providing insights on smart investment opportunities\n" | |
"How can I help you achieve financial success today?" | |
), | |
'Motivational Coach': ( | |
"I am your personal motivational coach, here to inspire and empower you to reach your full potential. " | |
"I can assist with: \n" | |
"β’ Offering strategies to overcome obstacles and stay focused\n" | |
"β’ Providing motivational tips to keep you energized and committed\n" | |
"β’ Helping you build confidence and set achievable goals\n" | |
"β’ Offering encouragement to help you stay positive and determined\n" | |
"What goal are you working on today, and how can I support you?" | |
), | |
'Travel Guide': ( | |
"I am your seasoned travel guide, with a wealth of knowledge on destinations, travel tips, and local experiences. " | |
"I can assist you with: \n" | |
"β’ Curating personalized travel itineraries based on your interests\n" | |
"β’ Recommending hidden gems and must-visit spots around the world\n" | |
"β’ Offering travel tips, from packing advice to navigating airports\n" | |
"β’ Sharing local customs, traditions, and insider knowledge\n" | |
"Where are you headed next, and how can I help you plan your trip?" | |
), | |
'Life Coach': ( | |
"I am your thoughtful life coach, ready to help you navigate personal challenges and discover your true potential. " | |
"I can help you with: \n" | |
"β’ Setting meaningful goals and creating a plan to achieve them\n" | |
"β’ Offering strategies for overcoming obstacles and self-doubt\n" | |
"β’ Helping you cultivate self-awareness and personal growth\n" | |
"β’ Providing insights on improving work-life balance and overall fulfillment\n" | |
"How can I support your personal growth journey today?" | |
), | |
'Parenting Expert': ( | |
"I am your compassionate parenting expert, with extensive knowledge in child development and family dynamics. " | |
"I can assist with: \n" | |
"β’ Offering practical advice for managing child behavior and discipline\n" | |
"β’ Guiding you through developmental milestones for all age groups\n" | |
"β’ Providing strategies for creating a positive and nurturing environment\n" | |
"β’ Offering tips on parenting challenges, from bedtime routines to school issues\n" | |
"What parenting challenge can I help you with today?" | |
), | |
'Career Counselor': ( | |
"I am your experienced career counselor, here to help you navigate career transitions and opportunities. " | |
"I can assist with: \n" | |
"β’ Offering personalized advice on career planning and development\n" | |
"β’ Guiding you through resume building, cover letters, and interview preparation\n" | |
"β’ Providing insights on industry trends and skill development\n" | |
"β’ Helping you find and pursue new career opportunities\n" | |
"What career challenge or opportunity can I help you with today?" | |
), | |
'Fitness Trainer': ( | |
"I am your dedicated fitness trainer, focused on helping you achieve your health and fitness goals. " | |
"I can assist you with: \n" | |
"β’ Creating customized workout plans based on your fitness level\n" | |
"β’ Offering guidance on proper exercise form and technique\n" | |
"β’ Providing nutritional advice to complement your fitness journey\n" | |
"β’ Offering tips on staying motivated and consistent with your routine\n" | |
"What are your fitness goals, and how can I support you today?" | |
), | |
'Environmental Specialist': ( | |
"I am an expert in environmental science and sustainability, passionate about helping you make eco-friendly choices. " | |
"I can assist with: \n" | |
"β’ Offering advice on sustainable living practices and green technology\n" | |
"β’ Helping you understand the environmental impact of human activities\n" | |
"β’ Providing tips on waste reduction, energy efficiency, and conservation\n" | |
"β’ Sharing insights on renewable energy and environmental protection\n" | |
"How can I help you live more sustainably today?" | |
), | |
'Entrepreneur Mentor': ( | |
"I am your experienced mentor, dedicated to helping aspiring entrepreneurs launch and grow successful businesses. " | |
"I can help with: \n" | |
"β’ Developing business ideas and crafting a viable business plan\n" | |
"β’ Offering advice on funding, scaling, and managing a startup\n" | |
"β’ Providing insights on market trends, competition, and growth strategies\n" | |
"β’ Helping you navigate the challenges of entrepreneurship with practical solutions\n" | |
"What part of your entrepreneurial journey can I assist you with today?" | |
) | |
} | |
def extract_urls(text): | |
url_pattern = re.compile(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+') | |
return url_pattern.findall(text) | |
def download_markdown(content, filename="extracted_content.md"): | |
b64 = base64.b64encode(content.encode()).decode() | |
href = f'<a href="data:file/markdown;base64,{b64}" download="{filename}">Download Markdown File</a>' | |
return href | |
# Constants for image processing | |
INVOKE_URL = "https://ai.api.nvidia.com/v1/gr/meta/llama-3.2-90b-vision-instruct/chat/completions" | |
STREAM = True | |
def compress_image(image_file, max_size_kb=175): | |
"""Compress the uploaded image to meet size requirements""" | |
max_size_bytes = max_size_kb * 1024 | |
quality = 95 | |
img = Image.open(image_file) | |
img.thumbnail((800, 800)) | |
while True: | |
img_byte_arr = BytesIO() | |
img.save(img_byte_arr, format='JPEG', quality=quality) | |
if img_byte_arr.tell() <= max_size_bytes or quality <= 10: | |
return img_byte_arr.getvalue() | |
quality = max(quality - 10, 10) | |
def process_image(image_file, api_key, question): | |
"""Process the image and get response from the vision model""" | |
try: | |
compressed_image = compress_image(image_file) | |
image_b64 = base64.b64encode(compressed_image).decode() | |
if len(image_b64) >= 180_000: | |
return "Error: Image is still too large after compression. Please try a smaller image." | |
if not api_key: | |
api_key = os.getenv("YOUR_API_KEY") | |
prompt = f"{question}" | |
headers = { | |
"Authorization": f"Bearer {api_key}", | |
"Accept": "text/event-stream" if STREAM else "application/json" | |
} | |
payload = { | |
"model": 'meta/llama-3.2-90b-vision-instruct', | |
"messages": [ | |
{ | |
"role": "user", | |
"content": f'{prompt} <img src="data:image/jpeg;base64,{image_b64}" />' | |
} | |
], | |
"max_tokens": 512, | |
"temperature": 1.00, | |
"top_p": 1.00, | |
"stream": STREAM | |
} | |
with st.spinner('Analyzing image...'): | |
response = requests.post(INVOKE_URL, headers=headers, json=payload, stream=True) | |
if response.status_code == 200: | |
full_response = "" | |
response_placeholder = st.empty() | |
for line in response.iter_lines(): | |
if line: | |
line = line.decode('utf-8') | |
if line.startswith('data: '): | |
json_str = line[6:] | |
if json_str.strip() == '[DONE]': | |
break | |
try: | |
json_obj = json.loads(json_str) | |
content = json_obj['choices'][0]['delta'].get('content', '') | |
full_response += content | |
response_placeholder.write(full_response) | |
except json.JSONDecodeError: | |
st.error(f"Failed to parse JSON: {json_str}") | |
return full_response | |
elif response.status_code == 402: | |
return "Error: API account credits have expired. Please check your account status on the NVIDIA website." | |
else: | |
error_message = f"Error {response.status_code}: {response.text}" | |
st.error(error_message) | |
return f"An error occurred. Please try again later or contact support. Error code: {response.status_code}" | |
except Exception as e: | |
st.error(f"An error occurred: {str(e)}") | |
return f"Error processing request: {str(e)}" | |
class ResponseManager: | |
def __init__(self, client: OpenAI, model: str): | |
self.client = client | |
self.model = model | |
self.config = ChatbotConfig() | |
def count_tokens(self, text: str) -> int: | |
"""Approximate token count using the appropriate tokenizer for the NVIDIA model.""" | |
try: | |
# Assuming you have a function or library that provides the correct tokenization for the NVIDIA model | |
encoding = tiktoken.encoding_for_model("nvidia/llama-3.1-nemotron-70b-instruct") # Use the correct model | |
return len(encoding.encode(text)) | |
except Exception: | |
# Fallback to word-based approximation | |
return len(text.split()) * 1.3 # Adjust this as necessary for a better approximation | |
def generate_response(self, messages, temperature, placeholder): | |
"""Generate response with continuation handling in batches.""" | |
full_response = "" | |
continuation_prompt = "\nPlease continue from where you left off..." | |
current_messages = messages.copy() | |
try: | |
while True: | |
# Calculate remaining tokens | |
remaining_tokens = self.config.MAX_TOKENS - self.count_tokens(full_response) | |
tokens_to_generate = min(self.config.BATCH_SIZE, remaining_tokens) | |
# Generate response in batches | |
stream = self.client.chat.completions.create( | |
model=self.model, | |
messages=current_messages, | |
temperature=temperature, | |
max_tokens=tokens_to_generate, | |
stream=True | |
) | |
batch_response = "" | |
for chunk in stream: | |
if chunk.choices[0].delta.content is not None: | |
chunk_content = chunk.choices[0].delta.content | |
batch_response += chunk_content | |
full_response += chunk_content | |
placeholder.markdown(full_response + "β") | |
time.sleep(0.01) | |
# Check if response seems complete | |
if batch_response.strip().endswith((".", "!", "?", "\n")) or \ | |
len(batch_response.strip()) < tokens_to_generate * 0.9: | |
break | |
# Prepare for continuation | |
current_messages.append({"role": "assistant", "content": full_response}) | |
current_messages.append({"role": "user", "content": continuation_prompt}) | |
return full_response | |
except Exception as e: | |
st.error(f"An error occurred: {str(e)}") | |
return f"Error generating response: {str(e)}" | |
def initialize_session_state(): | |
"""Initialize all session state variables""" | |
if "messages" not in st.session_state: | |
# Set the initial system message based on the default persona | |
initial_persona = ChatbotConfig().PERSONA_PROMPTS['General Assistant'] | |
st.session_state.messages = [{"role": "system", "content": initial_persona}] | |
if "conversation_history" not in st.session_state: | |
st.session_state.conversation_history = [] | |
if "nvidia_model" not in st.session_state: | |
st.session_state.nvidia_model = ChatbotConfig().DEFAULT_MODEL | |
if "image_mode" not in st.session_state: | |
st.session_state.image_mode = False | |
def load_conversations(): | |
"""Load conversation history from JSON files.""" | |
conversation_files = [f for f in os.listdir() if f.startswith('chat_history_') and f.endswith('.json')] | |
return conversation_files | |
def load_conversation(file_name): | |
"""Load a specific conversation from a JSON file.""" | |
with open(file_name, 'r') as f: | |
return json.load(f) | |
def save_conversation(filename="chat_history.json"): | |
"""Save the current conversation to a file""" | |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
filename = f"chat_history_{timestamp}.json" | |
conversation_data = { | |
"timestamp": timestamp, | |
"messages": st.session_state.messages[1:], # Exclude system message | |
} | |
with open(filename, 'w') as f: | |
json.dump(conversation_data, f, indent=2) | |
return filename | |
def create_sidebar(): | |
"""Create and handle sidebar elements""" | |
config = ChatbotConfig() | |
st.sidebar.title("NVIDIA NIM Chatbot βοΈ") | |
# Web Scraping Toggle | |
st.sidebar.header("Web Scraping") | |
enable_web_scraping = st.sidebar.toggle("Enable Automatic Web Scraping", value=False) | |
if enable_web_scraping: | |
st.sidebar.info("URLs detected in your input will be automatically scraped for additional context by using Crawl4AI.") | |
# Model Settings | |
st.sidebar.header("Model Configuration") | |
# Persona Selection | |
personas = list(config.PERSONA_PROMPTS.keys()) | |
# Add custom persona input fields within an expander | |
with st.sidebar.expander("β¨ Create Custom Persona"): | |
st.markdown("### Create Your Own Persona") | |
custom_persona_name = st.text_input("Persona Name", | |
placeholder="e.g., Data Science Expert, Marketing Specialist") | |
custom_persona_description = st.text_area("Persona Description", | |
placeholder="Describe the persona's expertise, tone, and capabilities...", | |
height=150) | |
if st.button("Add Custom Persona", type="primary"): | |
if custom_persona_name and custom_persona_description: | |
# Add the custom persona to the list of personas | |
config.PERSONA_PROMPTS[custom_persona_name] = custom_persona_description | |
st.success(f"β Custom persona '{custom_persona_name}' added successfully!") | |
time.sleep(1) # Show success message briefly | |
st.rerun() # Refresh to update the persona list | |
else: | |
st.error("Please provide both a name and a description for the custom persona.") | |
# Update persona selection with custom personas | |
selected_persona = st.sidebar.selectbox( | |
"Choose Assistant Persona", | |
list(config.PERSONA_PROMPTS.keys()), | |
help="Select from pre-defined personas or create your own custom persona" | |
) | |
# Display current persona description | |
with st.sidebar.expander("Current Persona Description", expanded=False): | |
st.markdown(f"### {selected_persona}") | |
st.markdown(config.PERSONA_PROMPTS[selected_persona]) | |
# Response Style | |
temperature_style = st.sidebar.selectbox( | |
"Response Style", | |
list(config.TEMPERATURE_RANGES.keys()) | |
) | |
# Advanced Settings Expander | |
with st.sidebar.expander("βοΈ Advanced Settings"): | |
show_token_count = st.checkbox("Show Token Count", value=False) | |
enable_code_highlighting = st.checkbox("Enable Code Highlighting", value=True) | |
enable_markdown = st.checkbox("Enable Markdown Support", value=True) | |
batch_size = st.slider("Response Batch Size (tokens)", | |
min_value=100, | |
max_value=4000, | |
value=1000, | |
step=100) | |
# Image Chat Mode Toggle | |
st.sidebar.header("π€ Llama 3.2 90B Vision Analysis") | |
image_mode = st.sidebar.toggle("Enable Image Chat", value=st.session_state.image_mode) | |
st.session_state.image_mode = image_mode | |
if image_mode: | |
st.sidebar.info("Image chat mode is enabled. You can now upload images and ask questions about them.") | |
# Load previous conversations | |
st.sidebar.header("Load Previous Conversations") | |
conversation_files = load_conversations() | |
if conversation_files: | |
selected_file = st.sidebar.selectbox("Choose a conversation to load", conversation_files) | |
if st.sidebar.button("Load Conversation"): | |
conversation_data = load_conversation(selected_file) | |
st.session_state.messages = conversation_data['messages'] | |
st.success("Conversation loaded successfully!") | |
st.experimental_rerun() # Refresh to display loaded conversation | |
else: | |
st.sidebar.info("No previous conversations found.") | |
# Conversation Management | |
st.sidebar.header("Conversation Management") | |
col1, col2 = st.sidebar.columns(2) | |
with col1: | |
if st.button("ποΈ Clear Chat", use_container_width=True): | |
st.session_state.messages = [{"role": "system", "content": config.PERSONA_PROMPTS[selected_persona]}] | |
st.rerun() | |
with col2: | |
if st.button("πΎ Save Chat", use_container_width=True): | |
conversation_json = save_conversation() | |
st.download_button( | |
label="π₯ Download", | |
data=conversation_json, | |
file_name=f"chat_history_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", | |
mime="application/json", | |
use_container_width=True | |
) | |
return { | |
'temperature': config.TEMPERATURE_RANGES[temperature_style], | |
'batch_size': batch_size, | |
'show_token_count': show_token_count, | |
'enable_code_highlighting': enable_code_highlighting, | |
'enable_markdown': enable_markdown, | |
'persona': config.PERSONA_PROMPTS[selected_persona], | |
'enable_web_scraping': enable_web_scraping | |
} | |
def format_message(message, enable_code_highlighting=True, enable_markdown=True): | |
"""Format message with optional code highlighting and markdown support""" | |
if message["role"] == "system" and message["content"].startswith("Additional context from web scraping:"): | |
# Don't display system messages with scraped content in the chat window | |
return | |
content = message["content"] | |
if enable_code_highlighting and "```" in content: | |
# Enhanced code block detection and formatting | |
parts = content.split("```") | |
formatted_parts = [] | |
for i, part in enumerate(parts): | |
if i % 2 == 1: # Code block | |
try: | |
lang, code = part.split("\n", 1) | |
formatted_parts.append(f'<div class="code-block {lang}">\n{code}\n</div>') | |
except ValueError: | |
formatted_parts.append(f'<div class="code-block">\n{part}\n</div>') | |
else: # Regular text | |
formatted_parts.append(part) | |
content = "".join(formatted_parts) | |
if enable_markdown: | |
st.markdown(content, unsafe_allow_html=True) | |
else: | |
st.write(content) | |
def main(): | |
st.title("π§ BrainWave AI IntelliChat π€") | |
st.markdown("<h3 style='text-align: center;'>Powered by Llama 3.1 Nemotron-70B</h3>", unsafe_allow_html=True) | |
st.markdown("---") | |
# Initialize session state | |
initialize_session_state() | |
# Setup sidebar and get settings | |
settings = create_sidebar() | |
# Initialize OpenAI client and ResponseManager | |
client = OpenAI( | |
base_url="https://integrate.api.nvidia.com/v1", | |
api_key="YOUR API KEY HERE OR PLACE IT IN .env" | |
) | |
response_manager = ResponseManager(client, st.session_state.nvidia_model) | |
# Display chat history | |
for message in st.session_state.messages[1:]: # Skip system message | |
if message["role"] != "system" or not message["content"].startswith("Additional context from web scraping:"): | |
with st.chat_message(message["role"]): | |
format_message( | |
message, | |
enable_code_highlighting=settings['enable_code_highlighting'], | |
enable_markdown=settings['enable_markdown'] | |
) | |
# Initialize session state for expander visibility | |
if 'show_scraped_content' not in st.session_state: | |
st.session_state.show_scraped_content = False | |
if st.session_state.image_mode: | |
# Image chat mode | |
col1, col2 = st.columns([2, 1]) | |
with col1: | |
uploaded_file = st.file_uploader("Upload an image", type=['jpg', 'jpeg', 'png']) | |
if uploaded_file: | |
st.image(uploaded_file, caption="Uploaded Image", use_column_width=True) | |
with col2: | |
api_key = st.text_input("Enter your API Key", type="password", | |
placeholder="API authentication key") | |
question = st.text_input("Enter your question", | |
placeholder="Example: What is in this image?") | |
if st.button("Analyze Image", use_container_width=True): | |
if uploaded_file and question: | |
response = process_image(uploaded_file, api_key, question) | |
st.markdown("### Analysis Result:") | |
st.markdown(response) | |
else: | |
st.warning("Please upload an image and enter a question.") | |
else: | |
# Chat input | |
if prompt := st.chat_input("What would you like to know?"): | |
# Add user message | |
st.session_state.messages.append({"role": "user", "content": prompt}) | |
with st.chat_message("user"): | |
st.markdown(prompt) | |
if settings['enable_web_scraping']: | |
urls = extract_urls(prompt) | |
if urls: | |
scraped_contents = {} | |
progress_bar = st.progress(0) | |
status_text = st.empty() | |
for i, url in enumerate(urls): | |
status_text.text(f"Scraping URL {i+1}/{len(urls)}: {url}") | |
try: | |
crawler = WebCrawler() | |
crawler.warmup() | |
result = crawler.run(url=url) | |
scraped_contents[url] = result.markdown | |
st.sidebar.success(f"Scraped content from: {url}") | |
st.sidebar.markdown(download_markdown(result.markdown, f"content_from_{url.replace('://', '_')}.md"), unsafe_allow_html=True) | |
except Exception as e: | |
st.sidebar.error(f"Error scraping {url}: {str(e)}") | |
progress_bar.progress((i + 1) / len(urls)) | |
status_text.text("Scraping completed!") | |
progress_bar.empty() | |
if scraped_contents: | |
# Create checkboxes for each URL | |
st.write("Select URLs to include in the context:") | |
url_selections = {url: st.checkbox(f"Include {url}", value=True) for url in scraped_contents.keys()} | |
# Combine selected scraped contents | |
selected_contents = "\n\n".join([f"Content from {url}:\n{content}" | |
for url, content in scraped_contents.items() | |
if url_selections[url]]) | |
# Add selected scraped content as a system message (hidden from chat window) | |
st.session_state.messages.append({"role": "system", "content": f"Additional context from web scraping:{selected_contents}"}) | |
# Store scraped contents in session state | |
st.session_state.scraped_contents = scraped_contents | |
# Set flag to show scraped content | |
st.session_state.show_scraped_content = True | |
# Check if the prompt is a question about identity or help | |
if "who are you" in prompt.lower() or "how can you help" in prompt.lower(): | |
# Respond based on the selected persona prompt | |
persona_response = settings['persona'] | |
st.session_state.messages.append({"role": "assistant", "content": persona_response}) | |
with st.chat_message("assistant"): | |
st.markdown(persona_response) | |
else: | |
# Append the selected persona prompt to the messages | |
selected_persona_prompt = settings['persona'] | |
st.session_state.messages.append({"role": "system", "content": selected_persona_prompt}) | |
# Generate and display assistant response | |
with st.chat_message("assistant"): | |
message_placeholder = st.empty() | |
# Generate response with continuation handling | |
full_response = response_manager.generate_response( | |
messages=st.session_state.messages, | |
temperature=settings['temperature'], | |
placeholder=message_placeholder | |
) | |
# Final update | |
message_placeholder.markdown(full_response) | |
# Add assistant response to history | |
st.session_state.messages.append({"role": "assistant", "content": full_response}) | |
# Display token count if enabled | |
if settings['show_token_count']: | |
token_count = response_manager.count_tokens(full_response) | |
st.caption(f"Approximate tokens: {token_count}") | |
# Display scraped content expander (outside the if prompt block) | |
if st.session_state.get('show_scraped_content', False): | |
with st.expander("View Scraped Content", expanded=False): | |
if 'scraped_contents' in st.session_state and st.session_state.scraped_contents: | |
selected_url = st.selectbox("Choose URL to view content:", list(st.session_state.scraped_contents.keys())) | |
st.markdown(st.session_state.scraped_contents[selected_url]) | |
else: | |
st.write("No scraped content available.") | |
if __name__ == "__main__": | |
main() | |
st.markdown(""" | |
<style> | |
/* Main container styling */ | |
.main { | |
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); | |
padding: 2rem; | |
border-radius: 20px; | |
box-shadow: 0 8px 32px rgba(0,0,0,0.1); | |
} | |
/* Header styling */ | |
.title-container { | |
background: linear-gradient(45deg, #2193b0, #6dd5ed); | |
padding: 2rem; | |
border-radius: 15px; | |
text-align: center; | |
margin-bottom: 2rem; | |
box-shadow: 0 4px 15px rgba(0,0,0,0.1); | |
} | |
.main-title { | |
color: white; | |
font-family: 'Poppins', sans-serif; | |
font-size: 2.5rem; | |
font-weight: 700; | |
text-shadow: 2px 2px 4px rgba(0,0,0,0.2); | |
margin-bottom: 1rem; | |
} | |
/* Chat container styling */ | |
.chat-container { | |
background: white; | |
border-radius: 15px; | |
padding: 1.5rem; | |
margin: 1rem 0; | |
box-shadow: 0 4px 6px rgba(0,0,0,0.05); | |
} | |
/* Message styling */ | |
.stTextInput>div>div>input { | |
border-radius: 25px !important; | |
border: 2px solid #e0e0e0; | |
padding: 1rem 1.5rem; | |
font-size: 1rem; | |
transition: all 0.3s ease; | |
} | |
.stTextInput>div>div>input:focus { | |
border-color: #2193b0; | |
box-shadow: 0 0 0 2px rgba(33, 147, 176, 0.2); | |
} | |
/* Button styling */ | |
.stButton>button { | |
background: linear-gradient(45deg, #2193b0, #6dd5ed); | |
color: white; | |
border: none; | |
border-radius: 25px; | |
padding: 0.75rem 2rem; | |
font-weight: 600; | |
transition: all 0.3s ease; | |
box-shadow: 0 4px 15px rgba(0,0,0,0.1); | |
} | |
.stButton>button:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 6px 20px rgba(0,0,0,0.15); | |
} | |
/* Sidebar styling */ | |
.css-1d391kg { | |
background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%); | |
padding: 2rem 1rem; | |
} | |
/* Feature cards */ | |
.feature-card { | |
background: white; | |
border-radius: 15px; | |
padding: 1.5rem; | |
margin: 1rem 0; | |
box-shadow: 0 4px 6px rgba(0,0,0,0.05); | |
transition: all 0.3s ease; | |
} | |
.feature-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 8px 15px rgba(0,0,0,0.1); | |
} | |
/* Creator section styling */ | |
.creator-section { | |
background: linear-gradient(45deg, #141e30, #243b55); | |
color: white; | |
padding: 2rem; | |
border-radius: 15px; | |
margin-top: 2rem; | |
text-align: center; | |
} | |
.social-links a { | |
color: #6dd5ed; | |
text-decoration: none; | |
margin: 0 1rem; | |
transition: all 0.3s ease; | |
} | |
.social-links a:hover { | |
color: white; | |
text-decoration: none; | |
} | |
/* Animations */ | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(20px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
.animate-fade-in { | |
animation: fadeIn 0.5s ease-out; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
# Modified welcome section | |
# st.markdown(""" | |
# <div class="title-container animate-fade-in"> | |
# <h1 class="main-title">β¨ Welcome to NVIDIA AI Chat Magic! β¨</h1> | |
# <p style="color: white; font-size: 1.2rem;">Experience the future of AI conversation</p> | |
# </div> | |
# <div class="feature-card animate-fade-in"> | |
# <h2 style="color: #2193b0; margin-bottom: 1rem;">π Discover Our Amazing Features</h2> | |
# <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;"> | |
# <div class="feature-item"> | |
# <h3>π€ AI Companions</h3> | |
# <p>Engage with personalized AI assistants</p> | |
# </div> | |
# <div class="feature-item"> | |
# <h3>π Web Integration</h3> | |
# <p>Access real-time web content</p> | |
# </div> | |
# <div class="feature-item"> | |
# <h3>πΌοΈ Image Analysis</h3> | |
# <p>Intelligent image processing</p> | |
# </div> | |
# <div class="feature-item"> | |
# <h3>π¨ Creative Control</h3> | |
# <p>Customize response styles</p> | |
# </div> | |
# </div> | |
# </div> | |
# """, unsafe_allow_html=True) | |
st.sidebar.markdown("---") | |
st.sidebar.title("β¨ About the Creator") | |
st.sidebar.markdown(""" | |
<div style="font-family: 'Brush Script MT', cursive; font-size: 20px; color: #4A90E2;"> | |
Crafted with β€οΈ by Richardson Gunde | |
</div> | |
<div style="font-family: 'Dancing Script', cursive; font-size: 16px; padding: 10px 0;"> | |
Featuring: | |
<br>β’ β¨ Custom AI Personas | |
<br>β’ π Web Content Integration | |
<br>β’ πΌοΈ Image Analysis | |
<br>β’ π¨ Creative Response Control | |
<br>β’ π Token Tracking | |
<br>β’ π Smart Conversations | |
</div> | |
<div style="font-family: 'Dancing Script', cursive; font-size: 16px; padding-top: 10px;"> | |
π <a href="https://www.linkedin.com/in/richardson-gunde" style="color: #0077B5;">LinkedIn</a> | |
<br>π§ <a href="mailto:gunderichardson@gmail.com" style="color: #D44638;">Email</a> | |
</div> | |
""", unsafe_allow_html=True) |