|
|
|
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 |
|
self.BATCH_SIZE = 4000 |
|
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 |
|
|
|
|
|
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: |
|
|
|
encoding = tiktoken.encoding_for_model("nvidia/llama-3.1-nemotron-70b-instruct") |
|
return len(encoding.encode(text)) |
|
except Exception: |
|
|
|
return len(text.split()) * 1.3 |
|
|
|
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: |
|
|
|
remaining_tokens = self.config.MAX_TOKENS - self.count_tokens(full_response) |
|
tokens_to_generate = min(self.config.BATCH_SIZE, remaining_tokens) |
|
|
|
|
|
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) |
|
|
|
|
|
if batch_response.strip().endswith((".", "!", "?", "\n")) or \ |
|
len(batch_response.strip()) < tokens_to_generate * 0.9: |
|
break |
|
|
|
|
|
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: |
|
|
|
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:], |
|
} |
|
|
|
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 βοΈ") |
|
|
|
|
|
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.") |
|
|
|
|
|
st.sidebar.header("Model Configuration") |
|
|
|
|
|
personas = list(config.PERSONA_PROMPTS.keys()) |
|
|
|
|
|
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: |
|
|
|
config.PERSONA_PROMPTS[custom_persona_name] = custom_persona_description |
|
st.success(f"β
Custom persona '{custom_persona_name}' added successfully!") |
|
time.sleep(1) |
|
st.rerun() |
|
else: |
|
st.error("Please provide both a name and a description for the custom persona.") |
|
|
|
|
|
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" |
|
) |
|
|
|
|
|
with st.sidebar.expander("Current Persona Description", expanded=False): |
|
st.markdown(f"### {selected_persona}") |
|
st.markdown(config.PERSONA_PROMPTS[selected_persona]) |
|
|
|
|
|
temperature_style = st.sidebar.selectbox( |
|
"Response Style", |
|
list(config.TEMPERATURE_RANGES.keys()) |
|
) |
|
|
|
|
|
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) |
|
|
|
|
|
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.") |
|
|
|
|
|
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() |
|
else: |
|
st.sidebar.info("No previous conversations found.") |
|
|
|
|
|
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:"): |
|
|
|
return |
|
|
|
content = message["content"] |
|
|
|
if enable_code_highlighting and "```" in content: |
|
|
|
parts = content.split("```") |
|
formatted_parts = [] |
|
for i, part in enumerate(parts): |
|
if i % 2 == 1: |
|
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: |
|
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() |
|
|
|
|
|
settings = create_sidebar() |
|
|
|
|
|
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) |
|
|
|
|
|
for message in st.session_state.messages[1:]: |
|
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'] |
|
) |
|
|
|
|
|
if 'show_scraped_content' not in st.session_state: |
|
st.session_state.show_scraped_content = False |
|
|
|
if st.session_state.image_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: |
|
|
|
if prompt := st.chat_input("What would you like to know?"): |
|
|
|
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: |
|
|
|
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()} |
|
|
|
|
|
selected_contents = "\n\n".join([f"Content from {url}:\n{content}" |
|
for url, content in scraped_contents.items() |
|
if url_selections[url]]) |
|
|
|
|
|
st.session_state.messages.append({"role": "system", "content": f"Additional context from web scraping:{selected_contents}"}) |
|
|
|
|
|
st.session_state.scraped_contents = scraped_contents |
|
|
|
|
|
st.session_state.show_scraped_content = True |
|
|
|
|
|
if "who are you" in prompt.lower() or "how can you help" in prompt.lower(): |
|
|
|
persona_response = settings['persona'] |
|
st.session_state.messages.append({"role": "assistant", "content": persona_response}) |
|
with st.chat_message("assistant"): |
|
st.markdown(persona_response) |
|
else: |
|
|
|
selected_persona_prompt = settings['persona'] |
|
st.session_state.messages.append({"role": "system", "content": selected_persona_prompt}) |
|
|
|
|
|
with st.chat_message("assistant"): |
|
message_placeholder = st.empty() |
|
|
|
|
|
full_response = response_manager.generate_response( |
|
messages=st.session_state.messages, |
|
temperature=settings['temperature'], |
|
placeholder=message_placeholder |
|
) |
|
|
|
|
|
message_placeholder.markdown(full_response) |
|
|
|
|
|
st.session_state.messages.append({"role": "assistant", "content": full_response}) |
|
|
|
|
|
if settings['show_token_count']: |
|
token_count = response_manager.count_tokens(full_response) |
|
st.caption(f"Approximate tokens: {token_count}") |
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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:[email protected]" style="color: #D44638;">Email</a> |
|
</div> |
|
|
|
""", unsafe_allow_html=True) |