Neurasense / app.py
Sephfox's picture
Update app.py
9aeacca verified
raw
history blame
5.79 kB
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg
from streamlit_drawable_canvas import st_canvas
import time
from PIL import Image
import io
from transformers import AutoModelForCausalLM, AutoTokenizer
# Constants
WIDTH, HEIGHT = 800, 400
AVATAR_WIDTH, AVATAR_HEIGHT = 300, 400
# Set up DialoGPT model
@st.cache_resource
def load_model():
tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-small")
model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-small")
return tokenizer, model
tokenizer, model = load_model()
# Create sensation map for the avatar
def create_sensation_map(width, height):
sensation_map = np.zeros((height, width, 3)) # RGB channels for pain, pleasure, and neutral
for y in range(height):
for x in range(width):
# Base sensation
base = np.sin(x/15) * np.cos(y/15) * 0.5 + np.random.normal(0, 0.1)
# Pain regions (red channel)
pain = np.exp(-((x-75)**2 + (y-100)**2) / 2000) + np.exp(-((x-225)**2 + (y-300)**2) / 2000)
# Pleasure regions (green channel)
pleasure = np.exp(-((x-150)**2 + (y-200)**2) / 2000) + np.exp(-((x-75)**2 + (y-300)**2) / 2000)
# Neutral sensation (blue channel)
neutral = 1 - (pain + pleasure)
sensation_map[y, x] = [pain, pleasure, neutral]
return sensation_map
avatar_sensation_map = create_sensation_map(AVATAR_WIDTH, AVATAR_HEIGHT)
# Streamlit app
st.title("Advanced Humanoid Touch Simulation")
# Create two columns
col1, col2 = st.columns(2)
# Avatar column
with col1:
st.subheader("Humanoid Avatar")
avatar_fig, avatar_ax = plt.subplots(figsize=(4, 6))
avatar_ax.imshow(avatar_sensation_map)
avatar_ax.axis('off')
st.pyplot(avatar_fig)
# Touch interface column
with col2:
st.subheader("Touch Interface")
touch_fig, touch_ax = plt.subplots(figsize=(4, 6))
touch_ax.add_patch(plt.Rectangle((0, 0), AVATAR_WIDTH, AVATAR_HEIGHT, fill=False))
touch_ax.set_xlim(0, AVATAR_WIDTH)
touch_ax.set_ylim(0, AVATAR_HEIGHT)
touch_ax.axis('off')
# Convert matplotlib figure to Image
canvas = FigureCanvasAgg(touch_fig)
canvas.draw()
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
img = Image.open(buf)
# Use streamlit-drawable-canvas for interaction
canvas_result = st_canvas(
fill_color="rgba(255, 165, 0, 0.3)",
stroke_width=3,
stroke_color="#e00",
background_color="#eee",
background_image=img,
update_streamlit=True,
height=AVATAR_HEIGHT,
width=AVATAR_WIDTH,
drawing_mode="point",
point_display_radius=5,
key="canvas",
)
def calculate_sensation(x, y, pressure, duration):
sensation = avatar_sensation_map[int(y), int(x)]
modified_sensation = sensation * pressure * (1 + np.log(duration + 1))
return modified_sensation
def generate_description(x, y, pressure, duration, pain, pleasure, neutral):
prompt = f"Human: Describe the sensation when touched at ({x:.1f}, {y:.1f}) with pressure {pressure:.2f} for {duration:.2f} seconds. Pain: {pain:.2f}, Pleasure: {pleasure:.2f}, Neutral: {neutral:.2f}.\nAvatar:"
input_ids = tokenizer.encode(prompt, return_tensors="pt")
output = model.generate(input_ids, max_length=150, num_return_sequences=1, no_repeat_ngram_size=2, top_k=50, top_p=0.95, temperature=0.7)
return tokenizer.decode(output[0], skip_special_tokens=True).split("Avatar: ")[-1].strip()
# Initialize session state
if 'touch_start_time' not in st.session_state:
st.session_state.touch_start_time = None
if 'last_touch_position' not in st.session_state:
st.session_state.last_touch_position = None
# Handle touch events
if canvas_result.json_data is not None:
objects = canvas_result.json_data["objects"]
if len(objects) > 0:
last_object = objects[-1]
current_position = (last_object["left"], last_object["top"])
if st.session_state.touch_start_time is None:
st.session_state.touch_start_time = time.time()
st.session_state.last_touch_position = current_position
else:
# Calculate pressure based on movement
if st.session_state.last_touch_position is not None:
dx = current_position[0] - st.session_state.last_touch_position[0]
dy = current_position[1] - st.session_state.last_touch_position[1]
distance = np.sqrt(dx**2 + dy**2)
pressure = 1 + distance / 10 # Adjust this formula as needed
else:
pressure = 1.0
duration = time.time() - st.session_state.touch_start_time
x, y = current_position
sensation = calculate_sensation(x, y, pressure, duration)
pain, pleasure, neutral = sensation
description = generate_description(x, y, pressure, duration, pain, pleasure, neutral)
st.write(f"Touch at ({x:.1f}, {y:.1f}) with pressure {pressure:.2f} for {duration:.2f} seconds")
st.write(f"Pain: {pain:.2f}, Pleasure: {pleasure:.2f}, Neutral: {neutral:.2f}")
st.write("Avatar's response:")
st.write(description)
st.session_state.last_touch_position = current_position
else:
st.session_state.touch_start_time = None
st.session_state.last_touch_position = None
st.write("Click and drag on the touch interface to simulate touching the avatar.")
st.write("The avatar's sensation map shows pain (red), pleasure (green), and neutral (blue) areas.")