Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
dist
.git
.gitignore
*.log
.franklin-store
release
.DS_Store
npm-debug.log*
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Franklin Canvas — single-container deploy.
# One Node process serves BOTH the built Vite SPA (dist/) and the /api backend,
# so the UI and API share one origin (no CORS, one URL). ffmpeg is needed for
# the video stitch / film-assemble tools.
FROM node:20-slim

RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg ca-certificates \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Cloud Run injects PORT; bind all interfaces. NODE_ENV=production tightens deps.
# VITE_PAYMENT_MODE=browser → the web build pays x402 with each VISITOR's wallet
# (no shared server wallet). Vite inlines this at build time.
ENV NODE_ENV=production HOST=0.0.0.0 VITE_PAYMENT_MODE=browser

# Install full deps (build needs vite/tsc), build the SPA, then drop dev deps.
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

EXPOSE 8080
CMD ["node", "server.mjs"]
11 changes: 9 additions & 2 deletions agent-tools.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -761,13 +761,20 @@ export async function runAgentChat({ model, messages, defaults }, ctx) {
// (auto-compact). The frontend feeds the early turns here when history grows too
// large, then replaces them with the returned summary to keep the context lean.
export async function summarizeConversation(messages, ctx) {
// Flatten OpenAI multimodal content (string | content-part array) to plain text
// for the transcript — image parts become a short placeholder.
const flatten = (c) => {
if (typeof c === 'string') return c;
if (Array.isArray(c)) return c.map((p) => (p?.type === 'text' ? p.text : p?.type === 'image_url' ? '[image]' : '')).join(' ');
return '';
};
const transcript = (Array.isArray(messages) ? messages : []).map((m) => {
if (m.role === 'assistant' && m.tool_calls?.length) {
const calls = m.tool_calls.map((c) => `${c.function?.name}(${clamp(String(c.function?.arguments || ''), 200)})`).join(', ');
return `ASSISTANT called: ${calls}${m.content ? `\nASSISTANT: ${m.content}` : ''}`;
return `ASSISTANT called: ${calls}${m.content ? `\nASSISTANT: ${flatten(m.content)}` : ''}`;
}
if (m.role === 'tool') return `TOOL RESULT (${m.name}): ${clamp(String(m.content || ''), 500)}`;
return `${String(m.role).toUpperCase()}: ${m.content || ''}`;
return `${String(m.role).toUpperCase()}: ${flatten(m.content)}`;
}).join('\n');
const sys = `You compress the earlier part of an AI media-studio agent conversation into a brief running memory. PRESERVE: the user's overall goal; every asset created (node id + media kind + result_url + model); key creative decisions; and any unfinished tasks. Drop chit-chat. Output concise plain-text notes (<= 250 words).`;
const client = llm(ctx);
Expand Down
14 changes: 12 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/franklin-canvas-icon.png?v=2" />
<link rel="apple-touch-icon" href="/franklin-canvas-icon.png?v=2" />
<link rel="icon" type="image/png" href="/franklin-avatar.png?v=3" />
<link rel="apple-touch-icon" href="/franklin-avatar.png?v=3" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Franklin Canvas</title>
<!-- Apply the saved theme before paint so we don't flash the default dark
theme before React sets data-theme (App.tsx applies it on mount). -->
<script>
(function () {
try {
var t = localStorage.getItem('franklin-canvas:theme') || 'gold';
if (t === 'gold' || t === 'light') document.documentElement.setAttribute('data-theme', t);
} catch (e) {}
})();
</script>
</head>
<body>
<div id="root"></div>
Expand Down
218 changes: 209 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@
"server": "node server.mjs",
"build": "tsc -b && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"deploy": "bash scripts/deploy.sh"
},
"dependencies": {
"@blockrun/llm": "^2.1.1",
"@tanstack/react-query": "^5.101.0",
"@xyflow/react": "^12.4.0",
"lucide-react": "^1.14.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"viem": "^2.52.2",
"wagmi": "^3.6.16",
"zustand": "^5.0.2"
},
"devDependencies": {
Expand Down
Binary file added public/franklin-avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading