Compare commits

...

5 Commits

Author SHA1 Message Date
Alex Cheema
07ceb19f0a Merge pull request #614 from samiamjidkhan/main
animation fix
2025-01-22 14:59:54 +00:00
Sami Khan
27b4577f38 directory for images 2025-01-22 05:47:25 -05:00
Sami Khan
a70943f8d2 base images for animation 2025-01-22 05:46:38 -05:00
Alex Cheema
410d901505 Merge pull request #613 from samiamjidkhan/dmg-backend
image and text mode fix
2025-01-21 13:12:08 +00:00
Sami Khan
5c4ce5392c image and text mode fix 2025-01-21 04:33:54 -05:00
3 changed files with 65 additions and 25 deletions

View File

@@ -139,11 +139,23 @@ def remap_messages(messages: List[Message]) -> List[Message]:
def build_prompt(tokenizer, _messages: List[Message], tools: Optional[List[Dict]] = None):
messages = remap_messages(_messages)
chat_template_args = {"conversation": [m.to_dict() for m in messages], "tokenize": False, "add_generation_prompt": True}
if tools: chat_template_args["tools"] = tools
if tools:
chat_template_args["tools"] = tools
prompt = tokenizer.apply_chat_template(**chat_template_args)
print(f"!!! Prompt: {prompt}")
return prompt
try:
prompt = tokenizer.apply_chat_template(**chat_template_args)
if DEBUG >= 3: print(f"!!! Prompt: {prompt}")
return prompt
except UnicodeEncodeError:
# Handle Unicode encoding by ensuring everything is UTF-8
chat_template_args["conversation"] = [
{k: v.encode('utf-8').decode('utf-8') if isinstance(v, str) else v
for k, v in m.to_dict().items()}
for m in messages
]
prompt = tokenizer.apply_chat_template(**chat_template_args)
if DEBUG >= 3: print(f"!!! Prompt (UTF-8 encoded): {prompt}")
return prompt
def parse_message(data: dict):
@@ -213,11 +225,16 @@ class ChatGPTAPI:
cors.add(self.app.router.add_post("/download", self.handle_post_download), {"*": cors_options})
cors.add(self.app.router.add_get("/topology", self.handle_get_topology), {"*": cors_options})
# Add static routes
if "__compiled__" not in globals():
self.static_dir = Path(__file__).parent.parent/"tinychat"
self.app.router.add_get("/", self.handle_root)
self.app.router.add_static("/", self.static_dir, name="static")
self.app.router.add_static('/images/', get_exo_images_dir(), name='static_images')
# Always add images route, regardless of compilation status
self.images_dir = get_exo_images_dir()
self.images_dir.mkdir(parents=True, exist_ok=True)
self.app.router.add_static('/images/', self.images_dir, name='static_images')
self.app.middlewares.append(self.timeout_middleware)
self.app.middlewares.append(self.log_request)
@@ -509,20 +526,32 @@ class ChatGPTAPI:
await response.write(json.dumps({'progress': get_progress_bar((result[0]), (result[1]))}).encode('utf-8') + b'\n')
elif isinstance(result, np.ndarray):
im = Image.fromarray(np.array(result))
images_folder = get_exo_images_dir()
# Save the image to a file
image_filename = f"{_request_id}.png"
image_path = images_folder/image_filename
im.save(image_path)
image_url = request.app.router['static_images'].url_for(filename=image_filename)
base_url = f"{request.scheme}://{request.host}"
# Construct the full URL correctly
full_image_url = base_url + str(image_url)
await response.write(json.dumps({'images': [{'url': str(full_image_url), 'content_type': 'image/png'}]}).encode('utf-8') + b'\n')
if is_finished:
await response.write_eof()
try:
im = Image.fromarray(np.array(result))
# Save the image to a file
image_filename = f"{_request_id}.png"
image_path = self.images_dir/image_filename
im.save(image_path)
# Get URL for the saved image
try:
image_url = request.app.router['static_images'].url_for(filename=image_filename)
base_url = f"{request.scheme}://{request.host}"
full_image_url = base_url + str(image_url)
await response.write(json.dumps({'images': [{'url': str(full_image_url), 'content_type': 'image/png'}]}).encode('utf-8') + b'\n')
except KeyError as e:
if DEBUG >= 2: print(f"Error getting image URL: {e}")
# Fallback to direct file path if URL generation fails
await response.write(json.dumps({'images': [{'url': str(image_path), 'content_type': 'image/png'}]}).encode('utf-8') + b'\n')
if is_finished:
await response.write_eof()
except Exception as e:
if DEBUG >= 2: print(f"Error processing image: {e}")
if DEBUG >= 2: traceback.print_exc()
await response.write(json.dumps({'error': str(e)}).encode('utf-8') + b'\n')
stream_task = None

View File

@@ -2,6 +2,7 @@ from PIL import Image, ImageDraw, ImageFont, ImageFilter
import os
import numpy as np
import cv2
import sys
def draw_rounded_rectangle(draw, coords, radius, fill):
left, top, right, bottom = coords
@@ -80,14 +81,20 @@ def create_animation_mp4(
font = ImageFont.load_default()
promptfont = ImageFont.load_default()
# Get the base directory for images when running as a bundled app
if hasattr(sys, '_MEIPASS'):
base_dir = os.path.join(sys._MEIPASS, "exo", "apputil", "baseimages")
else:
base_dir = os.path.join(os.path.dirname(__file__), "baseimages")
# Process first frame
base_img = Image.open(os.path.join(os.path.dirname(__file__), "baseimages", "image1.png"))
base_img = Image.open(os.path.join(base_dir, "image1.png"))
draw = ImageDraw.Draw(base_img)
draw_centered_text_rounded(draw, device_name, font, device_coords)
frames.extend([crop_image(base_img)] * 30) # 1 second at 30fps
# Process second frame with typing animation
base_img2 = Image.open(os.path.join(os.path.dirname(__file__), "baseimages", "image2.png"))
base_img2 = Image.open(os.path.join(base_dir, "image2.png"))
for i in range(len(prompt_text) + 1):
current_frame = base_img2.copy()
draw = ImageDraw.Draw(current_frame)
@@ -101,7 +108,7 @@ def create_animation_mp4(
# Create blur sequence
replacement_img = Image.open(replacement_image_path)
base_img = Image.open(os.path.join(os.path.dirname(__file__), "baseimages", "image3.png"))
base_img = Image.open(os.path.join(base_dir, "image3.png"))
blur_steps = [int(80 * (1 - i/8)) for i in range(9)]
for i, blur_amount in enumerate(blur_steps):
@@ -123,7 +130,7 @@ def create_animation_mp4(
frames.extend([crop_image(new_frame)] * 15) # 0.5 seconds at 30fps
# Create and add final frame (image4)
final_base = Image.open(os.path.join(os.path.dirname(__file__), "baseimages", "image4.png"))
final_base = Image.open(os.path.join(base_dir, "image4.png"))
draw = ImageDraw.Draw(final_base)
draw_centered_text_rounded(draw, device_name, font, device_coords)
@@ -158,4 +165,4 @@ def create_animation_mp4(
out.write(frame_array)
out.release()
print(f"Video saved successfully to {output_path}")
print(f"Video saved successfully to {output_path}")

View File

@@ -6,6 +6,9 @@ import pkgutil
def run():
site_packages = site.getsitepackages()[0]
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
baseimages_dir = os.path.join(base_dir, "exo", "apputil", "baseimages")
command = [
f"{sys.executable}", "-m", "nuitka", "exo/main.py",
"--company-name=exolabs",
@@ -15,7 +18,8 @@ def run():
"--standalone",
"--output-filename=exo",
"--python-flag=no_site",
"--onefile"
"--onefile",
f"--include-data-dir={baseimages_dir}=exo/apputil/baseimages"
]
if sys.platform == "darwin":