import json
import uuid
import urllib.request
import urllib.parse
import ssl
import asyncio
import websockets
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.image import Image
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.modalview import ModalView
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle, RoundedRectangle, BorderImage, Line, Mesh, Ellipse, StencilPush, StencilUse, StencilUnUse, StencilPop, Triangle
from kivy.properties import StringProperty, ObjectProperty, BooleanProperty, NumericProperty, ListProperty
from kivy.clock import Clock
from kivy.metrics import dp
from kivy.lang import Builder
from kivy.utils import get_color_from_hex
from kivy.animation import Animation
from kivy.core.image import Image as CoreImage
from kivy.effects.scroll import ScrollEffect
from kivy.effects.dampedscroll import DampedScrollEffect
from kivy.uix.relativelayout import RelativeLayout
import os
import random
import string
import requests
from io import BytesIO
from PIL import Image as PILImage
import time
from math import sin, cos, pi, radians
Enhanced color palette with better visibility
MAIN_ORANGE = (0.75, 0.30, 0.08, 1.0) # Deeper, more muted base orange
LIGHT_ORANGE = (0.85, 0.40, 0.15, 1.0) # Darker but still distinguishable
DARK_ORANGE = (0.55, 0.20, 0.03, 1.0) # Much darker, almost brown-orange
GLASS_HIGHLIGHT = (1.0, 1.0, 1.0, 0.25) # Stronger glass highlight
GLASS_SHADOW = (0.2, 0.1, 0.05, 0.25) # Deeper shadow
Enhanced glass effect colors
GLASS_TOP = (1.0, 1.0, 1.0, 0.55) # More prominent top highlight
GLASS_MIDDLE = (1.0, 1.0, 1.0, 0.3) # More visible middle layer
GLASS_BOTTOM = (1.0, 1.0, 1.0, 0.15) # Subtle but visible bottom
Enhanced gradient colors
GRADIENT_TOP = (1.0, 0.50, 0.25, 1.0) # Brighter top
GRADIENT_BOTTOM = (0.95, 0.40, 0.15, 1.0) # Richer bottom
Enhanced energy field colors
FIELD_OUTER = (1.0, 0.50, 0.25, 0.2) # More visible outer field
FIELD_INNER = (0.95, 0.40, 0.15, 0.3) # Stronger inner field
System constants
PARTICLE_COUNT = 20
TWO_PI = 2 * pi
CORNER_ROTATION_SPEED = 60 # Degrees per second
HEXAGON_POINTS = 6
ENERGY_PARTICLES = 15
def ensure_assets():
if not os.path.exists(assets_path):
os.makedirs(assets_path)
Path and window setup
is_mobile = os.path.exists("/storage/emulated/0")
if is_mobile:
assets_path = "/storage/emulated/0/python/assets"
save_path = "/storage/emulated/0/Pictures"
settings_path = "/storage/emulated/0/python/settings"
else:
base_path = os.path.dirname(os.path.abspath(file))
assets_path = os.path.join(base_path, "assets")
save_path = os.path.join(os.path.expanduser("~"), "Pictures")
settings_path = os.path.join(base_path, "settings")
from kivy.config import Config
Config.set('graphics', 'resizable', True)
Config.set('kivy', 'keyboard_mode', 'systemanddock')
if is_mobile:
Window.softinput_mode = 'below_target'
Window.keyboard_anim_args = {'d': .2, 't': 'in_out_expo'}
else:
Window.size = (1440, 720)
Window.left = 100
Window.top = 100
Window.minimum_width = 320
Window.minimum_height = 480
Builder.load_string('''
: import get_color_from_hex kivy.utils.get_color_from_hex
: set primary_dark '#1A1A1A'
: set secondary_dark '#2D2D2D'
: set accent_orange '#FF5722'
: set accent_light '#FF8A65'
: set text_primary '#FFFFFF'
: set text_secondary '#B3B3B3'
<MainButton>:
background_normal: ''
background_color: 0, 0, 0, 0
font_name: 'Roboto'
font_size: dp(18)
bold: True
text: 'Generate'
glow_radius: 0
border_width: dp(2)
canvas.after:
Color:
rgba: 0, 0, 0, 0.2
Rectangle:
pos: self.pos[0] + dp(2), self.pos[1] - dp(2)
size: self.size
<GlassButton>:
background_color: 0, 0, 0, 0
color: get_color_from_hex(text_primary)
font_size: '13sp'
bold: True
padding: dp(8), dp(4)
<ScrollText>:
background_color: get_color_from_hex(primary_dark)
foreground_color: get_color_from_hex(text_primary)
hint_text_color: get_color_from_hex(text_secondary)
cursor_color: get_color_from_hex(accent_orange)
selection_color: get_color_from_hex(accent_orange + '40')
font_size: '13sp'
padding: dp(5)
<GlassPanel>:
canvas.before:
Color:
rgba: get_color_from_hex(secondary_dark)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [dp(5)]
CustomButton@Button:
background_color: 0, 0, 0, 0
color: get_color_from_hex(text_primary)
canvas.before:
Color:
rgba: [get_color_from_hex(accent_orange)[:3], 0.9] if self.state == 'normal' else [get_color_from_hex(accent_light)[:3], 0.9]
RoundedRectangle:
pos: self.pos
size: self.size
radius: [dp(3)]
font_size: '13sp'
padding: dp(6), dp(3)
CustomTextInput@TextInput:
background_color: get_color_from_hex(primary_dark)
foreground_color: get_color_from_hex(text_primary)
hint_text_color: get_color_from_hex(text_secondary)
cursor_color: get_color_from_hex(accent_orange)
selection_color: get_color_from_hex(accent_orange + '40')
font_size: '13sp'
padding: dp(5)
multiline: False
CustomLabel@Label:
color: get_color_from_hex(text_primary)
font_size: '13sp'
<ScrollView>:
bar_width: dp(5)
bar_color: [get_color_from_hex(accent_orange)[:3], 0.8]
bar_inactive_color: [get_color_from_hex(secondary_dark)[:3], 0.4]
effect_cls: "ScrollEffect"
<ModalView>:
background_color: get_color_from_hex(primary_dark)
canvas.before:
Color:
rgba: get_color_from_hex(secondary_dark)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [dp(5)]
<BoxLayout>:
padding: dp(1)
spacing: dp(1)
<FloatLayout>:
canvas.before:
Color:
rgba: get_color_from_hex(primary_dark)
Rectangle:
pos: self.pos
size: self.size
<ImageViewer>:
canvas.before:
Color:
rgba: get_color_from_hex(primary_dark)
Rectangle:
pos: self.pos
size: self.size
<FullscreenImage>:
canvas.before:
Color:
rgba: get_color_from_hex(primary_dark + 'F0')
Rectangle:
pos: self.pos
size: self.size
NotificationPanel@BoxLayout:
canvas.before:
Color:
rgba: get_color_from_hex(accent_orange + 'E6')
RoundedRectangle:
pos: self.pos
size: self.size
radius: [dp(3)]
''')
class EnergyParticle:
def init(self, x, y, angle, speed, size, lifetime):
self.x = x
self.y = y
self.angle = angle
self.speed = speed
self.size = size
self.lifetime = lifetime
self.max_lifetime = lifetime
self.active = True
class MainButton(Button):
glow_radius = NumericProperty(0)
border_width = NumericProperty(dp(2))
border_color = ListProperty(MAIN_ORANGE)
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 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | def __init__(self, **kwargs):
super(MainButton, self).__init__(**kwargs)
self._time = time.time()
self._pulse_alpha = 0
self._energy_alpha = 0
self._shine_pos = 0
self._glass_shine_pos = 0
self._particles = []
self._corner_angles = [0] * 4
self._particle_life = [random.random() for _ in range(PARTICLE_COUNT)]
self._particle_speed = [random.random() * 0.5 + 0.5 for _ in range(PARTICLE_COUNT)]
# Properties for enhanced effects
self._hexagon_rotation = 0
self._energy_flow = 0
self._energy_particles = []
self._energy_level = 0
self._holo_offset = 0
self._generate_particles()
self._init_energy_particles()
self.fbind('pos', self._update)
self.fbind('size', self._update)
self.fbind('state', self._on_state)
Clock.schedule_once(self._update, 0)
Clock.schedule_interval(self._ambient_animation, 1/60)
def _draw_glass_effect(self):
with self.canvas.before:
# Base glass layer
StencilPush()
Color(rgba=(1, 1, 1, 1))
RoundedRectangle(
pos=self.pos,
size=self.size,
radius=[dp(12)]
)
StencilUse()
# Enhanced glass gradient
steps = 25 # Increased steps for smoother gradient
height_segment = self.height / steps
for i in range(steps):
progress = i / steps
alpha = 0.4 - (progress * 0.25) # Increased alpha values
Color(rgba=(1, 1, 1, alpha))
Rectangle(
pos=(self.pos[0], self.pos[1] + i * height_segment),
size=(self.width, height_segment)
)
# Enhanced top highlight
Color(rgba=GLASS_TOP)
Rectangle(
pos=(self.pos[0], self.pos[1] + self.height * 0.75),
size=(self.width, self.height * 0.25)
)
# Enhanced moving glass reflection
shine_width = self.width * 0.5 # Wider shine
shine_height = self.height * 1.5
shine_x = self.pos[0] - shine_width + (self.width + shine_width * 2) * self._glass_shine_pos
Color(rgba=(1, 1, 1, 0.15)) # Slightly stronger shine
Mesh(
vertices=[
shine_x, self.pos[1], 0, 0,
shine_x + shine_width, self.pos[1], 1, 0,
shine_x + shine_width * 0.7, self.pos[1] + shine_height, 1, 1,
shine_x - shine_width * 0.3, self.pos[1] + shine_height, 0, 1],
indices=[0, 1, 2, 2, 3, 0],
mode='triangles'
)
StencilUnUse()
StencilPop()
def _init_energy_particles(self):
self._energy_particles = []
for _ in range(ENERGY_PARTICLES):
self._create_energy_particle()
def _create_energy_particle(self):
angle = random.random() * TWO_PI
speed = random.random() * 100 + 50
size = random.random() * dp(3) + dp(1)
lifetime = random.random() * 2 + 1
particle = EnergyParticle(
random.random(), random.random(),
angle, speed, size, lifetime
)
self._energy_particles.append(particle)
def _generate_particles(self):
self._particles = [
(random.random(), random.random(),
random.random() * TWO_PI,
random.random() * 0.4 + 0.3)
for _ in range(PARTICLE_COUNT)
]
def _draw_hexagonal_border(self):
with self.canvas.before:
center_x = self.pos[0] + self.width / 2
center_y = self.pos[1] + self.height / 2
radius = min(self.width, self.height) * 0.3
points = []
for i in range(HEXAGON_POINTS):
angle = radians(i * 60 + self._hexagon_rotation)
points.extend([
center_x + cos(angle) * radius,
center_y + sin(angle) * radius
])
# Enhanced hexagon layers with better visibility
for i in range(3):
Color(rgba=(
LIGHT_ORANGE[0],
LIGHT_ORANGE[1],
LIGHT_ORANGE[2],
(0.3 - i * 0.05) * self._energy_level # Increased base alpha
))
Line(points=points, width=self.border_width - dp(i * 0.5))
def _draw_energy_particles(self):
with self.canvas.before:
for particle in self._energy_particles:
life_ratio = particle.lifetime / particle.max_lifetime
Color(rgba=(
LIGHT_ORANGE[0],
LIGHT_ORANGE[1],
LIGHT_ORANGE[2],
life_ratio * 0.4 # Increased visibility
))
Ellipse(
pos=(
self.pos[0] + particle.x * self.width - particle.size/2,
self.pos[1] + particle.y * self.height - particle.size/2
),
size=(particle.size, particle.size)
)
def _draw_corner_decoration(self, pos, angle):
with self.canvas.before:
# Enhanced outer triangle
Color(rgba=(1.0, 0.8, 0.6, 0.9)) # Increased visibility
size = dp(10) # Slightly larger size
Triangle(points=[
pos[0], pos[1],
pos[0] + size * cos(radians(angle)),
pos[1] + size * sin(radians(angle)),
pos[0] + size * cos(radians(angle + 90)),
pos[1] + size * sin(radians(angle + 90))
])
# Enhanced inner triangle
Color(rgba=(1.0, 0.9, 0.7, 0.8)) # Increased visibility
size_small = dp(5)
Triangle(points=[
pos[0], pos[1],
pos[0] + size_small * cos(radians(angle)),
pos[1] + size_small * sin(radians(angle)),
pos[0] + size_small * cos(radians(angle + 90)),
pos[1] + size_small * sin(radians(angle + 90))
])
def _on_state(self, instance, value):
Animation.cancel_all(self)
if value == 'down':
anim = Animation(
glow_radius=dp(15), # Increased glow radius
border_width=dp(3),
duration=0.15,
t='out_quad'
)
else:
anim = Animation(
glow_radius=dp(0),
border_width=dp(2),
duration=0.25,
t='out_quad'
)
anim.start(self)
def _ambient_animation(self, dt):
self._time += dt
self._pulse_alpha = (sin(self._time * 2) + 1) * 0.2 # Increased pulse visibility
self._energy_alpha = (sin(self._time * 1.5) + 1) * 0.6 # Enhanced energy effect
self._shine_pos = (self._shine_pos + dt * 4.5) % 3
self._glass_shine_pos = (self._glass_shine_pos + dt * 1.8) % 5
self._hexagon_rotation += dt * 30 # 30 degrees per second
self._energy_flow = (self._energy_flow + dt * 1.2) % 1
self._energy_level = (sin(self._time * 1.5) + 1) * 0.6 # Increased energy level
# Update corner rotations
rotation = dt * CORNER_ROTATION_SPEED
self._corner_angles = [(angle + rotation) % 360 for angle in self._corner_angles]
# Update regular particles
for i, (x, y, angle, speed) in enumerate(self._particles):
new_x = (x + cos(angle) * dt * speed) % 1
new_y = (y + sin(angle) * dt * speed) % 1
self._particles[i] = (new_x, new_y, angle, speed)
self._particle_life[i] -= 0.01 * self._particle_speed[i]
if self._particle_life[i] <= 0:
self._particle_life[i] = 1.0
self._particles[i] = (random.random(), random.random(),
random.random() * TWO_PI,
random.random() * 0.4 + 0.3)
# Update energy particles
for particle in self._energy_particles:
particle.update(dt)
if not particle.active:
self._energy_particles.remove(particle)
self._create_energy_particle()
self._update()
def _update(self, *args):
self.canvas.before.clear()
with self.canvas.before:
# Enhanced outer glow with improved flickering effect
for i in range(6): # Added an extra layer
glow_alpha = (0.15 - i * 0.02) * (0.7 + 0.3 * sin(self._time * 8 + i))
Color(rgba=(*LIGHT_ORANGE[:3], glow_alpha))
RoundedRectangle(
pos=(self.pos[0] - dp(3+i*2), self.pos[1] - dp(3+i*2)),
size=(self.width + dp(6+i*4), self.height + dp(6+i*4)),
radius=[dp(15+i*2)]
)
# Enhanced base button color
Color(rgba=DARK_ORANGE)
RoundedRectangle(
pos=self.pos,
size=self.size,
radius=[dp(12)]
)
# Enhanced energy field effect
Color(rgba=(*FIELD_OUTER[:3], FIELD_OUTER[3] * self._energy_level * 1.2)) # Increased visibility
RoundedRectangle(
pos=(self.pos[0] - dp(4), self.pos[1] - dp(4)),
size=(self.width + dp(8), self.height + dp(8)),
radius=[dp(14)]
)
# Base gradient and enhanced effects
self._draw_glass_effect()
# Enhanced energy particles
self._draw_energy_particles()
# Enhanced hexagonal rotating symbol
self._draw_hexagonal_border()
# Enhanced particle effects
for i, (x, y, angle, speed) in enumerate(self._particles):
particle_alpha = self._particle_life[i] * 0.6 * (0.6 + self._pulse_alpha) # Increased visibility
Color(rgba=(*LIGHT_ORANGE[:3], particle_alpha))
size = dp(2 + self._particle_life[i] * 2) # Slightly larger particles
Rectangle(
pos=(self.pos[0] + x * self.width - size/2,
self.pos[1] + y * self.height - size/2),
size=(size, size)
)
# Enhanced corner decorations
for i, angle in enumerate(self._corner_angles):
if i == 0:
self._draw_corner_decoration(
(self.pos[0] + dp(4), self.pos[1] + self.height - dp(4)),
angle)
elif i == 1:
self._draw_corner_decoration(
(self.pos[0] + self.width - dp(4), self.pos[1] + self.height - dp(4)),
angle + 90)
elif i == 2:
self._draw_corner_decoration(
(self.pos[0] + self.width - dp(4), self.pos[1] + dp(4)),
angle + 180)
else:
self._draw_corner_decoration(
(self.pos[0] + dp(4), self.pos[1] + dp(4)),
angle + 270)
# Enhanced border effect
for i in range(3): # Added an extra layer for more depth
Color(rgba=(*LIGHT_ORANGE[:3],
0.95 - i * 0.25 + self._pulse_alpha * 0.2))
Line(
rounded_rectangle=(
self.pos[0] + dp(i), self.pos[1] + dp(i),
self.width - dp(i*2), self.height - dp(i*2),
dp(12-i)
),
width=self.border_width - dp(i*0.3)
)
# Enhanced text shadow with better visibility
self.canvas.after.clear()
with self.canvas.after:
Color(rgba=(0, 0, 0, 0.3)) # Slightly darker shadow
Rectangle(
pos=(self.pos[0] + dp(1), self.pos[1] - dp(1)), # Adjusted offset
size=(self.width, self.height)
)
# Enhanced text color with better contrast
self.color = [1, 1, 1, 0.98] # Slightly increased opacity for better readability
|
class ScrollText(TextInput):
def init(self, kwargs):
super().init(kwargs)
self.background_color = get_color_from_hex('#383838')
self.foreground_color = get_color_from_hex('#FFFFFF')
self.cursor_color = get_color_from_hex('#8C5EF2')
self.selection_color = get_color_from_hex('#FF8C0080')
self.hint_text_color = get_color_from_hex('#CCCCCC')
class GlassPanel(BoxLayout):
def init(self, kwargs):
super().init(kwargs)
self.orientation = kwargs.get('orientation', 'vertical')
self.padding = dp(10)
self.spacing = dp(6)
self.opacity = 0
class ImageViewer(Image):
def init(self, kwargs):
super().init(kwargs)
self.allow_stretch = True
self.keep_ratio = True
self.opacity = 0
self.size_hint = (1, 1)
class FullscreenImage(ModalView):
def init(self, image_source, kwargs):
super().init(kwargs)
self.background_color = (0, 0, 0, 0)
self.size_hint = (1, 1)
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 | self.layout = FloatLayout()
with self.layout.canvas.before:
Color(rgba=get_color_from_hex('#000000F0'))
self.bg_rect = Rectangle(pos=self.pos, size=self.size)
self.image = Image(
source=image_source,
allow_stretch=True,
keep_ratio=True,
pos_hint={'center_x': 0.5, 'center_y': 0.5},
size_hint=(0.95, 0.95),
opacity=0
)
self.layout.add_widget(self.image)
# Save button with icon
floppy_path = os.path.join(assets_path, 'floppy.png')
self.save_btn = Button(
background_normal=floppy_path,
background_down=floppy_path,
size_hint=(None, None),
size=(dp(48), dp(48)),
pos_hint={'x': 0.02, 'top': 0.98},
opacity=0
)
self.save_btn.bind(on_release=self._save_image)
self.layout.add_widget(self.save_btn)
# Notification panel
self.notification_bg = BoxLayout(
size_hint=(None, None),
size=(dp(280), dp(44)),
pos_hint={'center_x': 0.5, 'top': 0.95},
opacity=0
)
with self.notification_bg.canvas.before:
Color(rgba=get_color_from_hex('#8C5EF2'))
self.rect = RoundedRectangle(
pos=self.notification_bg.pos,
size=self.notification_bg.size,
radius=[dp(10)]
)
self.notification = Label(
text='',
size_hint=(1, 1),
color=(1, 1, 1, 1),
font_size='16sp'
)
self.notification_bg.add_widget(self.notification)
self.layout.add_widget(self.notification_bg)
self.notification_bg.bind(pos=self._update_rect, size=self._update_rect)
self.bind(pos=self._update_bg, size=self._update_bg)
self.add_widget(self.layout)
# Smooth opening animation
def start_animations(dt):
Animation(background_color=(0, 0, 0, 0.97), duration=0.3).start(self)
Animation(opacity=1, duration=0.4, transition='out_quad').start(self.image)
Animation(opacity=1, duration=0.5, transition='out_quad').start(self.save_btn)
Clock.schedule_once(start_animations, 0)
def _update_rect(self, instance, value):
self.rect.pos = instance.pos
self.rect.size = instance.size
def _update_bg(self, instance, value):
self.bg_rect.pos = instance.pos
self.bg_rect.size = instance.size
def on_touch_down(self, touch):
if not self.save_btn.collide_point(*touch.pos):
anim = Animation(opacity=0, duration=0.2)
anim.bind(on_complete=lambda *x: self.dismiss())
anim.start(self.image)
Animation(background_color=(0, 0, 0, 0), duration=0.3).start(self)
return True
return super().on_touch_down(touch)
def show_notification(self, text):
self.notification.text = text
anim = (Animation(opacity=1, duration=0.2) +
Animation(opacity=1, duration=1.5) +
Animation(opacity=0, duration=0.3))
anim.start(self.notification_bg)
def _save_image(self, instance):
try:
random_name = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
save_file = os.path.join(save_path, f"{random_name}.png")
os.makedirs(save_path, exist_ok=True)
import shutil
shutil.copy2(self.image.source, save_file)
# Simple button press animation
anim = Animation(size=(dp(42), dp(42)), duration=0.1) + Animation(size=(dp(48), dp(48)), duration=0.1)
anim.start(self.save_btn)
self.show_notification(f'Saved as: {os.path.basename(save_file)}')
except Exception as e:
self.show_notification(f'Save failed: {str(e)}')
|
class MainLayout(BoxLayout):
def init(self, kwargs):
super().init(kwargs)
Window.softinput_mode = 'below_target'
self.orientation = 'vertical'
self.spacing = dp(3)
self.opacity = 0
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 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | self._init_top_section() # Call _init_top_section before accessing prompt_input
self._init_bottom_section()
anim = Animation(opacity=1, duration=0.3)
Clock.schedule_once(lambda dt: anim.start(self), 0.1)
app = App.get_running_app()
if app.last_image_source:
self.preview_image.source = app.last_image_source
self.preview_image.reload()
try:
with open(os.path.join(settings_path, "prompt.txt"), "r", encoding='utf-8') as f:
prompt_text = f.read()
with open(os.path.join(settings_path, "negative.txt"), "r", encoding='utf-8') as f:
negative_text = f.read()
self.prompt_input.text = prompt_text
self.negative_input.text = negative_text
except FileNotFoundError:
print(f"Error: prompt.txt or negative.txt not found in {settings_path}")
pass
def _init_top_section(self):
top_section = BoxLayout(
orientation='horizontal',
size_hint_y=0.3, # Use relative size
spacing=dp(3)
)
input_panel = GlassPanel(
orientation='vertical',
size_hint_x=0.85
)
self.prompt_input = ScrollText(
size_hint_y=1,
text=self.load_text("prompt.txt")
)
input_panel.add_widget(self.prompt_input)
control_panel = GlassPanel(
orientation='vertical',
size_hint_x=0.15,
padding=dp(3)
)
wait_icon_path = os.path.join(assets_path, 'wait.png')
self.wait_icon = Image(
source=wait_icon_path,
size_hint=(None, None),
size=(dp(24), dp(24)),
opacity=0,
pos_hint={'center_x': 0.5}
)
self.generate_btn = MainButton(
size_hint_y=None,
height=dp(44),
on_release=self.generate_image
)
control_panel.add_widget(self.wait_icon)
control_panel.add_widget(self.generate_btn)
top_section.add_widget(input_panel)
top_section.add_widget(control_panel)
self.add_widget(top_section)
def _init_bottom_section(self):
bottom_section = BoxLayout(
orientation='horizontal',
size_hint_y=0.7, # Use relative size
spacing=dp(3)
)
preview_panel = GlassPanel(
orientation='vertical',
size_hint_x=0.85
)
preview_panel.padding = 0
default_img_path = os.path.join(assets_path, 'out.png')
self.preview_image = ImageViewer(
source=default_img_path,
size_hint=(1, 1),
pos_hint={'top': 1}
)
preview_panel.add_widget(self.preview_image)
negative_panel = GlassPanel(
orientation='vertical',
size_hint_x=0.15
)
self.negative_input = ScrollText(
size_hint_y=1,
text=self.load_text("negative.txt")
)
negative_panel.add_widget(self.negative_input)
bottom_section.add_widget(preview_panel)
bottom_section.add_widget(negative_panel)
self.add_widget(bottom_section)
def load_text(self, filename):
try:
with open(os.path.join(settings_path, filename), "r", encoding='utf-8') as f:
return f.read()
except FileNotFoundError:
return ""
def _init_bottom_section(self):
bottom_section = BoxLayout(
orientation='horizontal',
size_hint_y=0.7, # Use relative size
spacing=dp(3)
)
preview_panel = GlassPanel(
orientation='vertical',
size_hint_x=0.85
)
preview_panel.padding = 0
default_img_path = os.path.join(assets_path, 'out.png')
self.preview_image = ImageViewer(
source=default_img_path,
size_hint=(1, 1),
pos_hint={'top': 1}
)
preview_panel.add_widget(self.preview_image)
negative_panel = GlassPanel(
orientation='vertical',
size_hint_x=0.15
)
self.negative_input = ScrollText(
size_hint_y=1,
text=self.load_text("negative.txt") # Correct filename here
)
negative_panel.add_widget(self.negative_input)
bottom_section.add_widget(preview_panel)
bottom_section.add_widget(negative_panel)
self.add_widget(bottom_section)
def _update_image_height(self, instance, width): # Define the method
if instance.texture:
ratio = instance.texture.height / instance.texture.width
instance.height = width * ratio
def on_size(self, *args):
Clock.schedule_once(self._update_layout, 0)
def _update_layout(self, dt):
is_portrait = Window.height > Window.width
self.padding = dp(5) if is_portrait else dp(7)
self.spacing = dp(5) if is_portrait else dp(7)
base_font_size = 15
width_factor = Window.width / 1440
adjusted_font_size = max(13, min(17, base_font_size * width_factor))
self.prompt_input.font_size = f'{adjusted_font_size}sp'
self.negative_input.font_size = f'{adjusted_font_size}sp'
self.generate_btn.height = dp(40) if is_portrait else dp(50)
# Update the layout of child widgets
self.clear_widgets()
self._init_top_section()
self._init_bottom_section()
def generate_image(self, instance):
prompt = self.prompt_input.text
negative_prompt = self.negative_input.text
try:
os.makedirs(settings_path, exist_ok=True)
with open(os.path.join(settings_path, "prompt.txt"), "w", encoding='utf-8') as f:
f.write(prompt)
with open(os.path.join(settings_path, "negative.txt"), "w", encoding='utf-8') as f:
f.write(negative_prompt)
except Exception as e:
print(f"Error saving settings: {e}")
self.generate_btn.disabled = True
self.wait_icon.opacity = 1
anim = Animation(opacity=0.7, duration=0.4) + Animation(opacity=1, duration=0.4)
anim.repeat = True
anim.start(self.wait_icon)
asyncio.run(self._generate_image_api(prompt, negative_prompt))
async def _generate_image_api(self, prompt, negative):
try:
with open(os.path.join(settings_path, "workflow.json"), 'r') as f:
prompt_json = json.load(f)
prompt_json["6"]["inputs"]["text"] = prompt
prompt_json["7"]["inputs"]["text"] = negative
prompt_json["3"]["inputs"]["seed"] = random.randint(0, 999999999)
prompt_json["4"]["inputs"]["ckpt_name"] = "YOUR MODEL NAME"
ws_url = "YOUR URL"
client_id = str(uuid.uuid4())
async def queue_prompt(prompt):
p = {"prompt": prompt, "client_id": client_id}
data = json.dumps(p).encode('utf-8')
req = urllib.request.Request(f"https://{ws_url}/prompt", data=data, headers={'Content-Type': 'application/json'})
response = urllib.request.urlopen(req, context=ssl.create_default_context())
return json.loads(response.read())
async def get_image(filename, subfolder, folder_type):
data = {"filename": filename, "subfolder": subfolder, "type": folder_type}
url_values = urllib.parse.urlencode(data)
with urllib.request.urlopen(f"https://{ws_url}/view?{url_values}", context=ssl.create_default_context()) as response:
return response.read()
async def get_history(prompt_id):
with urllib.request.urlopen(f"https://{ws_url}/history/{prompt_id}", context=ssl.create_default_context()) as response:
return json.loads(response.read())
async def get_images(ws, prompt):
prompt_id = (await queue_prompt(prompt))['prompt_id']
while True:
out = await ws.recv()
if isinstance(out, str):
message = json.loads(out)
if message['type'] == 'executing' and message['data']['node'] is None and message['data']['prompt_id'] == prompt_id:
break
history = await get_history(prompt_id)
history = history[prompt_id]
for node_id, node_output in history['outputs'].items():
if 'images' in node_output:
for image in node_output['images']:
return await get_image(image['filename'], image['subfolder'], image['type'])
return None
async with websockets.connect(f"wss://{ws_url}/ws?clientId={client_id}") as ws:
image_data = await get_images(ws, prompt_json)
if image_data:
temp_path = os.path.join(assets_path, "cache", f"temp_image.png")
os.makedirs(os.path.dirname(temp_path), exist_ok=True)
with open(temp_path, "wb") as f:
f.write(image_data)
def update_preview(dt):
self.preview_image.source = temp_path
self.preview_image.reload()
anim = Animation(opacity=1, duration=0.3, transition='out_quad')
anim.start(self.preview_image)
app = App.get_running_app()
app.last_image_source = temp_path
Clock.schedule_once(update_preview, 0)
else:
print("Error: No image data returned")
except Exception as e:
print(f"Image generation error: {e}")
finally:
self.wait_icon.opacity = 0
Animation.cancel_all(self.wait_icon)
self.generate_btn.disabled = False
|
class ImageGeneratorApp(App):
last_image_source = StringProperty('')
if name == 'main':
try:
ensure_assets()