ChatStreamlitMultiplayer / multiuser.app.py
awacke1's picture
Rename app.py to multiuser.app.py
33d71c0 verified
raw
history blame
15.4 kB
import streamlit as st
import time
import random
import json
from datetime import datetime
import pytz
import platform
import uuid
import extra_streamlit_components as stx
from io import BytesIO
from PIL import Image
import base64
import cv2
import requests
from moviepy.editor import VideoFileClip
from gradio_client import Client
from openai import OpenAI
import openai
import os
from collections import deque
import numpy as np
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Set page config
st.set_page_config(page_title="Personalized Real-Time Chat", page_icon="💬", layout="wide")
# Initialize cookie manager
cookie_manager = stx.CookieManager()
# File to store chat history and user data
CHAT_FILE = "chat_history.txt"
# Function to save chat history and user data to file
def save_data():
with open(CHAT_FILE, 'w') as f:
json.dump({
'messages': st.session_state.messages,
'users': st.session_state.users
}, f)
# Function to load chat history and user data from file
def load_data():
try:
with open(CHAT_FILE, 'r') as f:
data = json.load(f)
st.session_state.messages = data['messages']
st.session_state.users = data['users']
except FileNotFoundError:
st.session_state.messages = []
st.session_state.users = []
# Load data at the start
load_data()
# Function to get or create user
def get_or_create_user():
user_id = cookie_manager.get(cookie='user_id')
if not user_id:
user_id = str(uuid.uuid4())
cookie_manager.set('user_id', user_id)
user = next((u for u in st.session_state.users if u['id'] == user_id), None)
if not user:
user = {
'id': user_id,
'name': random.choice(['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank', 'Grace', 'Henry']),
'browser': f"{platform.system()} - {st.session_state.get('browser_info', 'Unknown')}"
}
st.session_state.users.append(user)
save_data()
return user
# Initialize session state
if 'messages' not in st.session_state:
st.session_state.messages = []
if 'users' not in st.session_state:
st.session_state.users = []
if 'current_user' not in st.session_state:
st.session_state.current_user = get_or_create_user()
# Initialize OpenAI client
openai.api_key = os.getenv('OPENAI_API_KEY')
openai.organization = os.getenv('OPENAI_ORG_ID')
client = OpenAI(api_key=openai.api_key, organization=openai.organization)
GPT4O_MODEL = "gpt-4o-2024-05-13"
# Initialize HuggingFace client
hf_client = OpenAI(
base_url="https://api-inference.huggingface.co/v1",
api_key=os.environ.get('API_KEY')
)
# Create supported models
model_links = {
"GPT-4o": GPT4O_MODEL,
"Meta-Llama-3.1-70B-Instruct": "meta-llama/Meta-Llama-3.1-70B-Instruct",
"Meta-Llama-3.1-405B-Instruct-FP8": "meta-llama/Meta-Llama-3.1-405B-Instruct-FP8",
"Meta-Llama-3.1-405B-Instruct": "meta-llama/Meta-Llama-3.1-405B-Instruct",
"Meta-Llama-3.1-8B-Instruct": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"Meta-Llama-3-70B-Instruct": "meta-llama/Meta-Llama-3-70B-Instruct",
"Meta-Llama-3-8B-Instruct": "meta-llama/Meta-Llama-3-8B-Instruct",
"C4ai-command-r-plus": "CohereForAI/c4ai-command-r-plus",
"Aya-23-35B": "CohereForAI/aya-23-35B",
"Zephyr-orpo-141b-A35b-v0.1": "HuggingFaceH4/zephyr-orpo-141b-A35b-v0.1",
"Mixtral-8x7B-Instruct-v0.1": "mistralai/Mixtral-8x7B-Instruct-v0.1",
"Codestral-22B-v0.1": "mistralai/Codestral-22B-v0.1",
"Nous-Hermes-2-Mixtral-8x7B-DPO": "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
"Yi-1.5-34B-Chat": "01-ai/Yi-1.5-34B-Chat",
"Gemma-2-27b-it": "google/gemma-2-27b-it",
"Meta-Llama-2-70B-Chat-HF": "meta-llama/Llama-2-70b-chat-hf",
"Meta-Llama-2-7B-Chat-HF": "meta-llama/Llama-2-7b-chat-hf",
"Meta-Llama-2-13B-Chat-HF": "meta-llama/Llama-2-13b-chat-hf",
"Mistral-7B-Instruct-v0.1": "mistralai/Mistral-7B-Instruct-v0.1",
"Mistral-7B-Instruct-v0.2": "mistralai/Mistral-7B-Instruct-v0.2",
"Mistral-7B-Instruct-v0.3": "mistralai/Mistral-7B-Instruct-v0.3",
"Gemma-1.1-7b-it": "google/gemma-1.1-7b-it",
"Gemma-1.1-2b-it": "google/gemma-1.1-2b-it",
"Zephyr-7B-Beta": "HuggingFaceH4/zephyr-7b-beta",
"Zephyr-7B-Alpha": "HuggingFaceH4/zephyr-7b-alpha",
"Phi-3-mini-128k-instruct": "microsoft/Phi-3-mini-128k-instruct",
"Phi-3-mini-4k-instruct": "microsoft/Phi-3-mini-4k-instruct",
}
# Function to reset conversation
def reset_conversation():
st.session_state.conversation = []
st.session_state.messages = []
# Function to generate filenames
def generate_filename(prompt, file_type):
central = pytz.timezone('US/Central')
safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
replaced_prompt = prompt.replace(" ", "_").replace("\n", "_")
safe_prompt = "".join(x for x in replaced_prompt if x.isalnum() or x == "_")[:90]
return f"{safe_date_time}_{safe_prompt}.{file_type}"
# Function to create files
def create_file(filename, prompt, response, user_name, timestamp):
with open(filename, "w", encoding="utf-8") as f:
f.write(f"User: {user_name}\nTimestamp: {timestamp}\n\nPrompt:\n{prompt}\n\nResponse:\n{response}")
# Function to extract video frames
def extract_video_frames(video_path, seconds_per_frame=2):
base64Frames = []
video = cv2.VideoCapture(video_path)
total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
fps = video.get(cv2.CAP_PROP_FPS)
frames_to_skip = int(fps * seconds_per_frame)
curr_frame = 0
while curr_frame < total_frames - 1:
video.set(cv2.CAP_PROP_POS_FRAMES, curr_frame)
success, frame = video.read()
if not success:
break
_, buffer = cv2.imencode(".jpg", frame)
base64Frames.append(base64.b64encode(buffer).decode("utf-8"))
curr_frame += frames_to_skip
video.release()
return base64Frames, None
# Function to process audio for video
def process_audio_for_video(video_input):
try:
transcription = client.audio.transcriptions.create(
model="whisper-1",
file=video_input,
)
return transcription.text
except:
return ''
# Function to process text with selected model
def process_text(user_name, text_input, selected_model, temp_values):
timestamp = datetime.now(pytz.utc).strftime('%Y-%m-%d %H:%M:%S %Z')
st.session_state.messages.append({"user": user_name, "message": text_input, "timestamp": timestamp})
with st.chat_message(user_name):
st.markdown(f"{user_name} ({timestamp}): {text_input}")
with st.chat_message("Assistant"):
if selected_model == "GPT-4o":
completion = client.chat.completions.create(
model=GPT4O_MODEL,
messages=[
{"role": "user", "content": m["message"]}
for m in st.session_state.messages
],
stream=True,
temperature=temp_values
)
return_text = st.write_stream(completion)
else:
try:
stream = hf_client.chat.completions.create(
model=model_links[selected_model],
messages=[
#{"role": m["role"], "content": m["content"]}
#{"role": "user", "content": m["content"]}
{"role": "user", "content": m["message"]}
for m in st.session_state.messages
],
temperature=temp_values,
stream=True,
max_tokens=3000,
)
return_text = st.write_stream(stream)
except Exception as e:
return_text = f"Error: {str(e)}"
st.error(return_text)
st.markdown(f"Assistant ({timestamp}): {return_text}")
filename = generate_filename(text_input, "md")
create_file(filename, text_input, return_text, user_name, timestamp)
st.session_state.messages.append({"user": "Assistant", "message": return_text, "timestamp": timestamp})
save_data()
# Function to process image (using GPT-4o)
def process_image(user_name, image_input, user_prompt):
image = Image.open(BytesIO(image_input))
base64_image = base64.b64encode(image_input).decode("utf-8")
response = client.chat.completions.create(
model=GPT4O_MODEL,
messages=[
{"role": "system", "content": "You are a helpful assistant that responds in Markdown."},
{"role": "user", "content": [
{"type": "text", "text": user_prompt},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}}
]}
],
temperature=0.0,
)
image_response = response.choices[0].message.content
timestamp = datetime.now(pytz.utc).strftime('%Y-%m-%d %H:%M:%S %Z')
st.session_state.messages.append({"user": user_name, "message": image_response, "timestamp": timestamp})
with st.chat_message(user_name):
st.image(image)
st.markdown(f"{user_name} ({timestamp}): {user_prompt}")
with st.chat_message("Assistant"):
st.markdown(image_response)
filename_md = generate_filename(user_prompt, "md")
create_file(filename_md, user_prompt, image_response, user_name, timestamp)
save_data()
return image_response
# Function to process audio (using GPT-4o for transcription)
def process_audio(user_name, audio_input, text_input):
if audio_input:
transcription = client.audio.transcriptions.create(
model="whisper-1",
file=audio_input,
)
timestamp = datetime.now(pytz.utc).strftime('%Y-%m-%d %H:%M:%S %Z')
st.session_state.messages.append({"user": user_name, "message": transcription.text, "timestamp": timestamp})
with st.chat_message(user_name):
st.markdown(f"{user_name} ({timestamp}): {transcription.text}")
with st.chat_message("Assistant"):
st.markdown(transcription.text)
filename = generate_filename(transcription.text, "wav")
create_file(filename, text_input, transcription.text, user_name, timestamp)
st.session_state.messages.append({"user": "Assistant", "message": transcription.text, "timestamp": timestamp})
save_data()
# Function to process video (using GPT-4o)
def process_video(user_name, video_input, user_prompt):
if isinstance(video_input, str):
with open(video_input, "rb") as video_file:
video_input = video_file.read()
base64Frames, audio_path = extract_video_frames(video_input)
transcript = process_audio_for_video(video_input)
response = client.chat.completions.create(
model=GPT4O_MODEL,
messages=[
{"role": "system", "content": "You are generating a video summary. Create a summary of the provided video and its transcript. Respond in Markdown"},
{"role": "user", "content": [
"These are the frames from the video.",
*map(lambda x: {"type": "image_url", "image_url": {"url": f'data:image/jpg;base64,{x}', "detail": "low"}}, base64Frames),
{"type": "text", "text": f"The audio transcription is: {transcript}"},
{"type": "text", "text": user_prompt}
]}
],
temperature=0,
)
video_response = response.choices[0].message.content
st.markdown(video_response)
timestamp = datetime.now(pytz.utc).strftime('%Y-%m-%d %H:%M:%S %Z')
filename_md = generate_filename(user_prompt, "md")
create_file(filename_md, user_prompt, video_response, user_name, timestamp)
st.session_state.messages.append({"user": user_name, "message": video_response, "timestamp": timestamp})
save_data()
return video_response
# Main function for each column
def main_column(column_name):
st.markdown(f"##### {column_name}")
selected_model = st.selectbox(f"Select Model for {column_name}", list(model_links.keys()), key=f"{column_name}_model")
temp_values = st.slider(f'Select a temperature value for {column_name}', 0.0, 1.0, (0.5), key=f"{column_name}_temp")
option = st.selectbox(f"Select an option for {column_name}", ("Text", "Image", "Audio", "Video"), key=f"{column_name}_option")
if option == "Text":
text_input = st.text_input(f"Enter your text for {column_name}:", key=f"{column_name}_text")
if text_input:
process_text(st.session_state.current_user['name'], text_input, selected_model, temp_values)
elif option == "Image":
text_input = st.text_input(f"Enter text prompt to use with Image context for {column_name}:", key=f"{column_name}_image_text")
uploaded_files = st.file_uploader(f"Upload images for {column_name}", type=["png", "jpg", "jpeg"], accept_multiple_files=True, key=f"{column_name}_image_upload")
for image_input in uploaded_files:
image_bytes = image_input.read()
process_image(st.session_state.current_user['name'], image_bytes, text_input)
elif option == "Audio":
text_input = st.text_input(f"Enter text prompt to use with Audio context for {column_name}:", key=f"{column_name}_audio_text")
uploaded_files = st.file_uploader(f"Upload an audio file for {column_name}", type=["mp3", "wav"], accept_multiple_files=True, key=f"{column_name}_audio_upload")
for audio_input in uploaded_files:
process_audio(st.session_state.current_user['name'], audio_input, text_input)
elif option == "Video":
video_input = st.file_uploader(f"Upload a video file for {column_name}", type=["mp4"], key=f"{column_name}_video_upload")
text_input = st.text_input(f"Enter text prompt to use with Video context for {column_name}:", key=f"{column_name}_video_text")
if video_input and text_input:
process_video(st.session_state.current_user['name'], video_input, text_input)
# Main Streamlit app
st.title("Personalized Real-Time Chat")
# Sidebar
with st.sidebar:
st.title("User Info")
st.write(f"Current User: {st.session_state.current_user['name']}")
st.write(f"Browser: {st.session_state.current_user['browser']}")
new_name = st.text_input("Change your name:")
if st.button("Update Name"):
if new_name:
for user in st.session_state.users:
if user['id'] == st.session_state.current_user['id']:
user['name'] = new_name
st.session_state.current_user['name'] = new_name
save_data()
st.success(f"Name updated to {new_name}")
break
st.title("Active Users")
for user in st.session_state.users:
st.write(f"{user['name']} ({user['browser']})")
if st.button('Reset Chat'):
reset_conversation()
# Create two columns
col1, col2 = st.columns(2)
# Run main function for each column
with col1:
main_column("Column 1")
with col2:
main_column("Column 2")
# Run the Streamlit app
if __name__ == "__main__":
st.markdown("*by Aaron Wacker*")
st.markdown("\n[Aaron Wacker](https://huggingface.co/spaces/awacke1/).")