File size: 8,258 Bytes
d9be852
0611560
c5987cc
58b97f2
ac166dc
b083c09
c5987cc
d9be852
ac166dc
9aeacca
0611560
6e1639c
d9be852
 
0611560
9aeacca
 
 
d9be852
 
9aeacca
 
 
 
d9be852
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9aeacca
60e6faa
d9be852
60e6faa
 
d9be852
 
60e6faa
d9be852
 
 
 
 
60e6faa
d9be852
60e6faa
 
 
9aeacca
0611560
d9be852
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6e1639c
d9be852
9aeacca
 
 
 
 
 
 
d9be852
9aeacca
 
 
 
 
 
 
 
 
d9be852
9aeacca
 
 
d9be852
9aeacca
 
0611560
d9be852
9aeacca
d9be852
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60e6faa
9aeacca
d9be852
c5987cc
d9be852
0611560
58b97f2
d9be852
 
58b97f2
b083c09
 
 
 
d9be852
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

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
@st.cache_resource
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()