diff --git a/electron/servers/fastapi/models/sql/image_asset.py b/electron/servers/fastapi/models/sql/image_asset.py
index 76303ec3..8639f6ce 100644
--- a/electron/servers/fastapi/models/sql/image_asset.py
+++ b/electron/servers/fastapi/models/sql/image_asset.py
@@ -7,10 +7,23 @@ from sqlalchemy import JSON, Column, DateTime
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
-from utils.get_env import get_app_data_directory_env
+from utils.get_env import get_app_data_directory_env, get_next_public_fast_api_env
from utils.path_helpers import get_resource_path
+def _with_fastapi_origin(path: str) -> str:
+ """Prefix relative web paths with FastAPI origin when available."""
+ if path.startswith("http://") or path.startswith("https://"):
+ return path
+
+ fastapi_origin = (get_next_public_fast_api_env() or "").strip()
+ if not fastapi_origin:
+ return path
+
+ normalized_path = path if path.startswith("/") else f"/{path}"
+ return f"{fastapi_origin.rstrip('/')}{normalized_path}"
+
+
class ImageAsset(SQLModel, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
created_at: datetime = Field(
@@ -36,6 +49,10 @@ class ImageAsset(SQLModel, table=True):
if path.startswith("http://") or path.startswith("https://"):
return path
+ # Already a web path under known mounts
+ if path.startswith("/app_data/") or path.startswith("/static/"):
+ return _with_fastapi_origin(path)
+
# Normalize filesystem path
real_path = os.path.realpath(path)
@@ -46,7 +63,7 @@ class ImageAsset(SQLModel, table=True):
if real_path.startswith(app_data_dir_real):
rel = os.path.relpath(real_path, app_data_dir_real)
rel_web = rel.replace(os.sep, "/")
- return f"/app_data/{rel_web}"
+ return _with_fastapi_origin(f"/app_data/{rel_web}")
# Map packaged static assets to /static/...
static_root = get_resource_path("static")
@@ -54,7 +71,7 @@ class ImageAsset(SQLModel, table=True):
if real_path.startswith(static_root_real):
rel = os.path.relpath(real_path, static_root_real)
rel_web = rel.replace(os.sep, "/")
- return f"/static/{rel_web}"
+ return _with_fastapi_origin(f"/static/{rel_web}")
# Fallback: return the original path (may be absolute or relative);
# frontend can decide how to handle unusual cases.
diff --git a/electron/servers/fastapi/server.py b/electron/servers/fastapi/server.py
index 0e1f3994..3c4abca5 100644
--- a/electron/servers/fastapi/server.py
+++ b/electron/servers/fastapi/server.py
@@ -1,5 +1,6 @@
import uvicorn
import argparse
+import os
from api.main import app
if __name__ == "__main__":
@@ -12,10 +13,14 @@ if __name__ == "__main__":
)
args = parser.parse_args()
reload = args.reload == "true"
+ host = "127.0.0.1"
+
+ # Provide a predictable public URL for services that need absolute asset links.
+ os.environ.setdefault("FASTAPI_PUBLIC_URL", f"http://{host}:{args.port}")
uvicorn.run(
"api.main:app",
- host="127.0.0.1",
+ host=host,
port=args.port,
log_level="info",
reload=reload,
diff --git a/electron/servers/fastapi/services/image_generation_service.py b/electron/servers/fastapi/services/image_generation_service.py
index adbf881a..8e14b8be 100644
--- a/electron/servers/fastapi/services/image_generation_service.py
+++ b/electron/servers/fastapi/services/image_generation_service.py
@@ -12,6 +12,7 @@ from models.sql.image_asset import ImageAsset
from utils.get_env import (
get_dall_e_3_quality_env,
get_gpt_image_1_5_quality_env,
+ get_next_public_fast_api_env,
get_pexels_api_key_env,
)
from utils.get_env import get_pixabay_api_key_env
@@ -59,6 +60,17 @@ class ImageGenerationService:
def is_stock_provider_selected(self):
return is_pixels_selected() or is_pixabay_selected()
+ def _to_frontend_url(self, path: str) -> str:
+ if path.startswith("http://") or path.startswith("https://"):
+ return path
+
+ fastapi_origin = (get_next_public_fast_api_env() or "").strip()
+ if not fastapi_origin:
+ return path
+
+ normalized_path = path if path.startswith("/") else f"/{path}"
+ return f"{fastapi_origin.rstrip('/')}{normalized_path}"
+
async def generate_image(self, prompt: ImagePrompt) -> str | ImageAsset:
"""
Generates an image based on the provided prompt.
@@ -69,11 +81,11 @@ class ImageGenerationService:
"""
if self.is_image_generation_disabled:
print("Image generation is disabled. Using placeholder image.")
- return "/static/images/placeholder.jpg"
+ return self._to_frontend_url("/static/images/placeholder.jpg")
if not self.image_gen_func:
print("No image generation function found. Using placeholder image.")
- return "/static/images/placeholder.jpg"
+ return self._to_frontend_url("/static/images/placeholder.jpg")
image_prompt = prompt.get_image_prompt(
with_theme=not self.is_stock_provider_selected()
@@ -99,11 +111,13 @@ class ImageGenerationService:
"theme_prompt": prompt.theme_prompt,
},
)
+ elif image_path.startswith("/app_data/") or image_path.startswith("/static/"):
+ return self._to_frontend_url(image_path)
raise Exception(f"Image not found at {image_path}")
except Exception as e:
print(f"Error generating image: {e}")
- return "/static/images/placeholder.jpg"
+ return self._to_frontend_url("/static/images/placeholder.jpg")
async def generate_image_openai(
self, prompt: str, output_directory: str, model: str, quality: str
diff --git a/electron/servers/fastapi/utils/get_env.py b/electron/servers/fastapi/utils/get_env.py
index 74cf2e1f..53680acd 100644
--- a/electron/servers/fastapi/utils/get_env.py
+++ b/electron/servers/fastapi/utils/get_env.py
@@ -142,3 +142,7 @@ def get_codex_model_env():
def get_migrate_database_on_startup_env():
return os.getenv("MIGRATE_DATABASE_ON_STARTUP")
+
+
+def get_next_public_fast_api_env():
+ return os.getenv("FASTAPI_PUBLIC_URL")
diff --git a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx
index 3da715e3..87658cf4 100644
--- a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx
+++ b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/dashboard/components/PresentationCard.tsx
@@ -111,14 +111,14 @@ export const PresentationCard = ({
{new Date(presentation?.created_at).toLocaleDateString()} diff --git a/electron/servers/nextjs/app/(presentation-generator)/components/PresentationRender.tsx b/electron/servers/nextjs/app/(presentation-generator)/components/PresentationRender.tsx index 9b9a3675..855dcf1f 100644 --- a/electron/servers/nextjs/app/(presentation-generator)/components/PresentationRender.tsx +++ b/electron/servers/nextjs/app/(presentation-generator)/components/PresentationRender.tsx @@ -76,7 +76,7 @@ const SlideScale = ({ } as React.CSSProperties} > - {/*