mirror of
https://github.com/exo-explore/exo.git
synced 2026-02-07 04:32:28 -05:00
Compare commits
5 Commits
v0.0.9-alp
...
v0.0.12-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07ceb19f0a | ||
|
|
27b4577f38 | ||
|
|
a70943f8d2 | ||
|
|
410d901505 | ||
|
|
5c4ce5392c |
@@ -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
|
||||
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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":
|
||||
|
||||
Reference in New Issue
Block a user