Spaces:
Sleeping
Sleeping
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, ImageDraw | |
import io | |
from transformers import AutoModelForCausalLM, AutoTokenizer | |
# Constants | |
WIDTH, HEIGHT = 1000, 600 | |
AVATAR_WIDTH, AVATAR_HEIGHT = 400, 600 | |
# Set up DialoGPT model | |
def load_model(): | |
tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium") | |
model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium") | |
return tokenizer, model | |
tokenizer, model = load_model() | |
# Simulated Sensor Classes | |
class PressureSensor: | |
def __init__(self, sensitivity=1.0): | |
self.sensitivity = sensitivity | |
def measure(self, pressure): | |
return pressure * self.sensitivity | |
class TemperatureSensor: | |
def __init__(self, base_temp=37.0): | |
self.base_temp = base_temp | |
def measure(self, touch_temp): | |
return self.base_temp + (touch_temp - self.base_temp) * 0.1 | |
class TextureSensor: | |
def __init__(self): | |
self.textures = ["smooth", "rough", "bumpy", "silky", "grainy"] | |
def measure(self, x, y): | |
return self.textures[hash((x, y)) % len(self.textures)] | |
class EMFieldSensor: | |
def measure(self, x, y): | |
return np.sin(x/50) * np.cos(y/50) * 10 # simulated EM field | |
# Create sensation map for the avatar | |
def create_sensation_map(width, height): | |
sensation_map = np.zeros((height, width, 7)) # RGBPVTE channels for pain, pleasure, neutral, pressure, velocity, temperature, and EM sensitivity | |
for y in range(height): | |
for x in range(width): | |
pain = np.exp(-((x-100)**2 + (y-150)**2) / 5000) + np.exp(-((x-300)**2 + (y-450)**2) / 5000) | |
pleasure = np.exp(-((x-200)**2 + (y-300)**2) / 5000) + np.exp(-((x-100)**2 + (y-500)**2) / 5000) | |
neutral = 1 - (pain + pleasure) | |
pressure = np.exp(-((x-50)**2 + (y-150)**2) / 2000) + np.exp(-((x-350)**2 + (y-150)**2) / 2000) + \ | |
np.exp(-((x-100)**2 + (y-550)**2) / 2000) + np.exp(-((x-300)**2 + (y-550)**2) / 2000) | |
velocity = np.exp(-((x-200)**2 + (y-100)**2) / 5000) + np.exp(-((x-200)**2 + (y-300)**2) / 5000) | |
temperature = np.exp(-((x-200)**2 + (y-200)**2) / 10000) # more sensitive in the core | |
em_sensitivity = np.exp(-((x-200)**2 + (y-100)**2) / 8000) # more sensitive in the head | |
sensation_map[y, x] = [pain, pleasure, neutral, pressure, velocity, temperature, em_sensitivity] | |
return sensation_map | |
avatar_sensation_map = create_sensation_map(AVATAR_WIDTH, AVATAR_HEIGHT) | |
# Initialize sensors | |
pressure_sensor = PressureSensor() | |
temp_sensor = TemperatureSensor() | |
texture_sensor = TextureSensor() | |
em_sensor = EMFieldSensor() | |
# Create human-like avatar (same as before) | |
def create_avatar(): | |
img = Image.new('RGB', (AVATAR_WIDTH, AVATAR_HEIGHT), color='white') | |
draw = ImageDraw.Draw(img) | |
# Head | |
draw.ellipse([150, 50, 250, 150], fill='beige', outline='black') | |
# Body | |
draw.rectangle([175, 150, 225, 400], fill='beige', outline='black') | |
# Arms | |
draw.rectangle([125, 150, 175, 350], fill='beige', outline='black') | |
draw.rectangle([225, 150, 275, 350], fill='beige', outline='black') | |
# Legs | |
draw.rectangle([175, 400, 200, 550], fill='beige', outline='black') | |
draw.rectangle([200, 400, 225, 550], fill='beige', outline='black') | |
return img | |
avatar_image = create_avatar() | |
# Streamlit app | |
st.title("Advanced Humanoid Techno-Sensory Simulation") | |
# Create two columns | |
col1, col2 = st.columns(2) | |
# Avatar column | |
with col1: | |
st.subheader("Humanoid Avatar") | |
st.image(avatar_image, use_column_width=True) | |
# Touch interface column | |
with col2: | |
st.subheader("Touch Interface") | |
canvas_result = st_canvas( | |
fill_color="rgba(255, 165, 0, 0.3)", | |
stroke_width=3, | |
stroke_color="#e00", | |
background_color="#eee", | |
background_image=avatar_image, | |
update_streamlit=True, | |
height=AVATAR_HEIGHT, | |
width=AVATAR_WIDTH, | |
drawing_mode="freedraw", | |
key="canvas", | |
) | |
def calculate_sensation(x, y, pressure, velocity): | |
sensation = avatar_sensation_map[int(y), int(x)] | |
pain, pleasure, neutral, pressure_sensitivity, velocity_sensitivity, temp_sensitivity, em_sensitivity = sensation | |
measured_pressure = pressure_sensor.measure(pressure * pressure_sensitivity) | |
measured_temp = temp_sensor.measure(37 + pressure * 5) # Simulating temperature increase with pressure | |
measured_texture = texture_sensor.measure(x, y) | |
measured_em = em_sensor.measure(x, y) * em_sensitivity | |
modified_pain = pain * measured_pressure / 10 | |
modified_pleasure = pleasure * velocity * velocity_sensitivity | |
modified_neutral = neutral * (1 - (measured_pressure + velocity) / 2) | |
return modified_pain, modified_pleasure, modified_neutral, measured_pressure, measured_temp, measured_texture, measured_em | |
def generate_description(x, y, pressure, velocity, pain, pleasure, neutral, measured_pressure, measured_temp, measured_texture, measured_em): | |
prompt = f"""Human: Describe the sensation when touched at ({x:.1f}, {y:.1f}) with these measurements: | |
Pressure: {measured_pressure:.2f} | |
Temperature: {measured_temp:.2f}°C | |
Texture: {measured_texture} | |
Electromagnetic field: {measured_em:.2f} | |
Resulting in: | |
Pain: {pain:.2f}, Pleasure: {pleasure:.2f}, Neutral: {neutral:.2f} | |
Avatar:""" | |
input_ids = tokenizer.encode(prompt, return_tensors="pt") | |
output = model.generate(input_ids, max_length=200, 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_history' not in st.session_state: | |
st.session_state.touch_history = [] | |
# Handle touch events | |
if canvas_result.json_data is not None: | |
objects = canvas_result.json_data["objects"] | |
if len(objects) > 0: | |
new_points = objects[-1].get("points", []) | |
if new_points: | |
for i in range(1, len(new_points)): | |
x1, y1 = new_points[i-1]["x"], new_points[i-1]["y"] | |
x2, y2 = new_points[i]["x"], new_points[i]["y"] | |
# Calculate pressure and velocity | |
distance = np.sqrt((x2-x1)**2 + (y2-y1)**2) | |
velocity = distance / 0.01 # Assuming 10ms between points | |
pressure = 1 + velocity / 100 # Simple pressure model | |
x, y = (x1 + x2) / 2, (y1 + y2) / 2 | |
pain, pleasure, neutral, measured_pressure, measured_temp, measured_texture, measured_em = calculate_sensation(x, y, pressure, velocity) | |
st.session_state.touch_history.append((x, y, pressure, velocity, pain, pleasure, neutral, measured_pressure, measured_temp, measured_texture, measured_em)) | |
# Display touch history and generate descriptions | |
if st.session_state.touch_history: | |
st.subheader("Touch History and Sensations") | |
for x, y, pressure, velocity, pain, pleasure, neutral, measured_pressure, measured_temp, measured_texture, measured_em in st.session_state.touch_history[-5:]: | |
st.write(f"Touch at ({x:.1f}, {y:.1f})") | |
st.write(f"Pressure: {measured_pressure:.2f}, Temperature: {measured_temp:.2f}°C") | |
st.write(f"Texture: {measured_texture}, EM Field: {measured_em:.2f}") | |
st.write(f"Sensations - Pain: {pain:.2f}, Pleasure: {pleasure:.2f}, Neutral: {neutral:.2f}") | |
description = generate_description(x, y, pressure, velocity, pain, pleasure, neutral, measured_pressure, measured_temp, measured_texture, measured_em) | |
st.write("Avatar's response:") | |
st.write(description) | |
st.write("---") | |
st.write("Draw on the avatar to simulate touch. The simulation will process pressure, temperature, texture, and electromagnetic sensations.") | |
# Add a button to clear the touch history | |
if st.button("Clear Touch History"): | |
st.session_state.touch_history = [] | |
st.experimental_rerun() |