Israeli Military Raids Gaza’s Largest Hospital
+Israeli troops have entered the Al-Shifa Hospital complex, where conditions have grown dire and Israel says Hamas fighters are embedded.
+ See more updates +diff --git a/backend/image_generation.py b/backend/image_generation.py new file mode 100644 index 0000000..ec9802d --- /dev/null +++ b/backend/image_generation.py @@ -0,0 +1,83 @@ +import asyncio +import os +import re +from openai import AsyncOpenAI +from bs4 import BeautifulSoup + + +async def process_tasks(prompts): + tasks = [generate_image(prompt) for prompt in prompts] + results = await asyncio.gather(*tasks, return_exceptions=True) + + processed_results = [] + for result in results: + if isinstance(result, Exception): + print(f"An exception occurred: {result}") + processed_results.append(None) + else: + processed_results.append(result) + + return processed_results + + +async def generate_image(prompt): + client = AsyncOpenAI(api_key=os.environ.get("OPENAI_API_KEY")) + image_params = { + "model": "dall-e-3", + "quality": "standard", + "style": "natural", + "n": 1, + "size": "1024x1024", + "prompt": prompt, + } + res = await client.images.generate(**image_params) + return res.data[0].url + + +def extract_dimensions(url): + # Regular expression to match numbers in the format '300x200' + matches = re.findall(r"(\d+)x(\d+)", url) + + if matches: + width, height = matches[0] # Extract the first match + width = int(width) + height = int(height) + return (width, height) + else: + return (100, 100) + + +async def generate_images(code): + # Find all images and extract their alt texts + soup = BeautifulSoup(code, "html.parser") + images = soup.find_all("img") + alts = [img.get("alt", None) for img in images] + + # Exclude images with no alt text + alts = [alt for alt in alts if alt is not None] + + # Remove duplicates + prompts = list(set(alts)) + + # Generate images + results = await process_tasks(prompts) + + # Create a dict mapping alt text to image URL + mapped_image_urls = dict(zip(prompts, results)) + + # Replace alt text with image URLs + for img in images: + new_url = mapped_image_urls[img.get("alt")] + + if new_url: + # Set width and height attributes + width, height = extract_dimensions(img["src"]) + img["width"] = width + img["height"] = height + # Replace img['src'] with the mapped image URL + img["src"] = new_url + else: + print("Image generation failed for alt text:" + img.get("alt")) + + # Return the modified HTML + return str(soup) diff --git a/backend/main.py b/backend/main.py index 7d30ebc..f93284a 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,19 +1,26 @@ # Load environment variables first -import json from dotenv import load_dotenv -import os -from datetime import datetime - -from prompts import assemble_prompt load_dotenv() +import json +import os +import traceback +from datetime import datetime from fastapi import FastAPI, WebSocket + from llm import stream_openai_response +from mock import MOCK_HTML, mock_completion +from image_generation import generate_images +from prompts import assemble_prompt app = FastAPI() +# Useful for debugging purposes when you don't want to waste GPT4-Vision credits +# Setting to True will stream a mock response instead of calling the OpenAI API +SHOULD_MOCK_AI_RESPONSE = False + def write_logs(prompt_messages, completion): # Create run_logs directory if it doesn't exist @@ -41,14 +48,31 @@ async def stream_code_test(websocket: WebSocket): prompt_messages = assemble_prompt(params["image"]) - completion = await stream_openai_response( - prompt_messages, - lambda x: process_chunk(x), - ) + if SHOULD_MOCK_AI_RESPONSE: + completion = await mock_completion(process_chunk) + else: + completion = await stream_openai_response( + prompt_messages, + lambda x: process_chunk(x), + ) # Write the messages dict into a log so that we can debug later write_logs(prompt_messages, completion) - await websocket.send_json({"type": "status", "value": "Code generation complete."}) + # Generate images + await websocket.send_json({"type": "status", "value": "Generating images..."}) - await websocket.close() + try: + updated_html = await generate_images(completion) + await websocket.send_json({"type": "setCode", "value": updated_html}) + await websocket.send_json( + {"type": "status", "value": "Code generation complete."} + ) + except Exception as e: + traceback.print_exc() + print("Image generation failed", e) + await websocket.send_json( + {"type": "status", "value": "Image generation failed but code is complete."} + ) + finally: + await websocket.close() diff --git a/backend/mock.py b/backend/mock.py new file mode 100644 index 0000000..ec26339 --- /dev/null +++ b/backend/mock.py @@ -0,0 +1,140 @@ +import asyncio + + +async def mock_completion(process_chunk): + code_to_return = MOCK_HTML_2 + + for i in range(0, len(code_to_return), 10): + await process_chunk(code_to_return[i : i + 10]) + await asyncio.sleep(0.01) + + return code_to_return + + +MOCK_HTML = """ +
+ + +Israeli troops have entered the Al-Shifa Hospital complex, where conditions have grown dire and Israel says Hamas fighters are embedded.
+ See more updates +The glittering city that attracts thousands of couples seeking unconventional nuptials has grown beyond the drive-through wedding.
+ 8 MIN READ +