Compare commits

...

6 Commits

Author SHA1 Message Date
1bbe89c879 chore: sync versions to v1.8.15
Some checks failed
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 4s
Monorepo Pipeline / 🧪 Test (push) Successful in 5m30s
Monorepo Pipeline / 🏗️ Build (push) Successful in 7m42s
Monorepo Pipeline / 🧹 Lint (push) Successful in 2m5s
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Successful in 1m4s
Monorepo Pipeline / 🐳 Build Build-Base (push) Successful in 1m31s
Monorepo Pipeline / 🐳 Build Production Runtime (push) Successful in 59s
Monorepo Pipeline / 🚀 Release (push) Successful in 2m52s
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Successful in 4m32s
Monorepo Pipeline / 🐳 Build Image Processor (push) Has been cancelled
2026-02-22 23:07:34 +01:00
554ca81c9b chore(image-processor): fix tfjs-node cross compile arch flags 2026-02-22 23:07:32 +01:00
aac0fe81b9 fix(image-service): enforce arm64 cpu architecture for tfjs-node in dockerfile
All checks were successful
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 2s
Monorepo Pipeline / 🧪 Test (push) Successful in 4m59s
Monorepo Pipeline / 🧹 Lint (push) Successful in 6m11s
Monorepo Pipeline / 🏗️ Build (push) Successful in 9m49s
Monorepo Pipeline / 🐳 Build Build-Base (push) Successful in 2m13s
Monorepo Pipeline / 🚀 Release (push) Successful in 3m6s
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Successful in 1m26s
Monorepo Pipeline / 🐳 Build Production Runtime (push) Successful in 23s
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Successful in 6m17s
Monorepo Pipeline / 🐳 Build Image Processor (push) Successful in 16m2s
2026-02-22 22:44:03 +01:00
ada1e9c717 fix(image-service): force rebuild tfjs-node for container architecture in Dockerfile
All checks were successful
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 2s
Monorepo Pipeline / 🧪 Test (push) Successful in 5m5s
Monorepo Pipeline / 🧹 Lint (push) Successful in 6m36s
Monorepo Pipeline / 🏗️ Build (push) Successful in 10m21s
Monorepo Pipeline / 🐳 Build Image Processor (push) Successful in 5m10s
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Successful in 1m56s
Monorepo Pipeline / 🐳 Build Build-Base (push) Successful in 2m38s
Monorepo Pipeline / 🐳 Build Production Runtime (push) Successful in 1m25s
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Successful in 7m34s
Monorepo Pipeline / 🚀 Release (push) Successful in 9m13s
2026-02-22 22:29:25 +01:00
4d295d10d1 chore: sync versions to v1.8.12
All checks were successful
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 1s
Monorepo Pipeline / 🧪 Test (push) Successful in 3m55s
Monorepo Pipeline / 🧹 Lint (push) Successful in 2m11s
Monorepo Pipeline / 🏗️ Build (push) Successful in 5m59s
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Successful in 1m12s
Monorepo Pipeline / 🐳 Build Build-Base (push) Successful in 1m39s
Monorepo Pipeline / 🐳 Build Production Runtime (push) Successful in 1m29s
Monorepo Pipeline / 🐳 Build Image Processor (push) Successful in 5m35s
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Successful in 6m14s
Monorepo Pipeline / 🚀 Release (push) Successful in 7m4s
2026-02-22 22:14:44 +01:00
c00f4e5ea5 fix(image-service): resolve next.js build crash and strict TS lint warnings for ci deploy 2026-02-22 22:14:35 +01:00
38 changed files with 105 additions and 79 deletions

2
.env
View File

@@ -1,5 +1,5 @@
# Project # Project
IMAGE_TAG=v1.8.6 IMAGE_TAG=v1.8.12
PROJECT_NAME=at-mintel PROJECT_NAME=at-mintel
PROJECT_COLOR=#82ed20 PROJECT_COLOR=#82ed20
GITEA_TOKEN=ccce002e30fe16a31a6c9d5a414740af2f72a582 GITEA_TOKEN=ccce002e30fe16a31a6c9d5a414740af2f72a582

View File

@@ -1,5 +1,5 @@
# Project # Project
IMAGE_TAG=v1.8.11 IMAGE_TAG=v1.8.15
PROJECT_NAME=sample-website PROJECT_NAME=sample-website
PROJECT_COLOR=#82ed20 PROJECT_COLOR=#82ed20

View File

@@ -8,10 +8,15 @@ WORKDIR /app
COPY . . COPY . .
# Note: Canvas needs build tools on Debian # Note: Canvas needs build tools on Debian
RUN apt-get update && apt-get install -y python3 make g++ libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev RUN apt-get update && apt-get install -y python3 make g++ libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
# Delete the prebuilt binary and force a clean rebuild from source for the correct container architecture
ENV npm_config_arch=arm64
ENV npm_config_target_arch=arm64
RUN pnpm install --frozen-lockfile RUN pnpm install --frozen-lockfile
# Force tfjs-node to build the native addon from source so it compiles for arm64 (bypassing pnpm quirks) RUN for dir in $(find /app/node_modules -type d -path "*/@tensorflow/tfjs-node"); do \
RUN for f in $(find /app/node_modules/.pnpm -path "*/@tensorflow/tfjs-node/scripts/install.js"); do cd $(dirname $(dirname $f)) && npm run install -- build-addon-from-source; done cd $dir && \
RUN pnpm install --frozen-lockfile rm -rf lib/napi-v8/* && \
npm_config_build_from_source=true npm_config_arch=arm64 npm_config_target_arch=arm64 npm run install; \
done
# Generate models explicitly for Docker # Generate models explicitly for Docker
RUN ls -la packages/image-processor/scripts || true RUN ls -la packages/image-processor/scripts || true
RUN pnpm dlx tsx packages/image-processor/scripts/download-models.ts RUN pnpm dlx tsx packages/image-processor/scripts/download-models.ts

View File

@@ -1,6 +1,6 @@
{ {
"name": "image-service", "name": "image-service",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@@ -1,6 +1,13 @@
import mintelNextConfig from "@mintel/next-config"; import mintelNextConfig from "@mintel/next-config";
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = {}; const nextConfig = {
serverExternalPackages: [
"@mintel/image-processor",
"@tensorflow/tfjs-node",
"sharp",
"canvas",
],
};
export default mintelNextConfig(nextConfig); export default mintelNextConfig(nextConfig);

View File

@@ -1,6 +1,6 @@
{ {
"name": "sample-website", "name": "sample-website",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@@ -1,45 +1,60 @@
import { NextRequest, NextResponse } from 'next/server'; import { NextRequest, NextResponse } from "next/server";
import { processImageWithSmartCrop } from '@mintel/image-processor';
export const dynamic = "force-dynamic";
export const runtime = "nodejs";
export async function GET(request: NextRequest) { export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url); const { searchParams } = new URL(request.url);
const url = searchParams.get('url'); const url = searchParams.get("url");
let width = parseInt(searchParams.get('w') || '800'); const width = parseInt(searchParams.get("w") || "800");
let height = parseInt(searchParams.get('h') || '600'); const height = parseInt(searchParams.get("h") || "600");
let q = parseInt(searchParams.get('q') || '80'); const q = parseInt(searchParams.get("q") || "80");
if (!url) { if (!url) {
return NextResponse.json({ error: 'Missing url parameter' }, { status: 400 }); return NextResponse.json(
{ error: "Missing url parameter" },
{ status: 400 },
);
}
try {
// 1. Fetch image from original URL
const response = await fetch(url);
if (!response.ok) {
return NextResponse.json(
{ error: "Failed to fetch original image" },
{ status: response.status },
);
} }
try { const arrayBuffer = await response.arrayBuffer();
// 1. Fetch image from original URL const buffer = Buffer.from(arrayBuffer);
const response = await fetch(url);
if (!response.ok) {
return NextResponse.json({ error: 'Failed to fetch original image' }, { status: response.status });
}
const arrayBuffer = await response.arrayBuffer(); // Dynamically import to prevent Next.js from trying to bundle tfjs-node/sharp locally at build time
const buffer = Buffer.from(arrayBuffer); const { processImageWithSmartCrop } =
await import("@mintel/image-processor");
// 2. Process image with Face-API and Sharp // 2. Process image with Face-API and Sharp
const processedBuffer = await processImageWithSmartCrop(buffer, { const processedBuffer = await processImageWithSmartCrop(buffer, {
width, width,
height, height,
format: 'webp', format: "webp",
quality: q, quality: q,
}); });
// 3. Return the processed image // 3. Return the processed image
return new NextResponse(new Uint8Array(processedBuffer), { return new NextResponse(new Uint8Array(processedBuffer), {
status: 200, status: 200,
headers: { headers: {
'Content-Type': 'image/webp', "Content-Type": "image/webp",
'Cache-Control': 'public, max-age=31536000, immutable', "Cache-Control": "public, max-age=31536000, immutable",
}, },
}); });
} catch (error) { } catch (error) {
console.error('Image Processing Error:', error); console.error("Image Processing Error:", error);
return NextResponse.json({ error: 'Failed to process image' }, { status: 500 }); return NextResponse.json(
} { error: "Failed to process image" },
{ status: 500 },
);
}
} }

View File

@@ -57,7 +57,7 @@
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
"require-in-the-middle": "^8.0.1" "require-in-the-middle": "^8.0.1"
}, },
"version": "1.8.11", "version": "1.8.15",
"pnpm": { "pnpm": {
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
"@parcel/watcher", "@parcel/watcher",

View File

@@ -2,7 +2,7 @@
"name": "acquisition-manager", "name": "acquisition-manager",
"description": "Custom High-Fidelity Management for Directus", "description": "Custom High-Fidelity Management for Directus",
"icon": "extension", "icon": "extension",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"keywords": [ "keywords": [
"directus", "directus",

View File

@@ -1,6 +1,6 @@
{ {
"name": "acquisition", "name": "acquisition",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"directus:extension": { "directus:extension": {
"type": "endpoint", "type": "endpoint",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/cli", "name": "@mintel/cli",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/cloner", "name": "@mintel/cloner",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/index.js", "module": "dist/index.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/cms-infra", "name": "@mintel/cms-infra",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@@ -2,7 +2,7 @@
"name": "company-manager", "name": "company-manager",
"description": "Custom High-Fidelity Management for Directus", "description": "Custom High-Fidelity Management for Directus",
"icon": "extension", "icon": "extension",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"keywords": [ "keywords": [
"directus", "directus",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/content-engine", "name": "@mintel/content-engine",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@@ -2,7 +2,7 @@
"name": "customer-manager", "name": "customer-manager",
"description": "Custom High-Fidelity Management for Directus", "description": "Custom High-Fidelity Management for Directus",
"icon": "extension", "icon": "extension",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"keywords": [ "keywords": [
"directus", "directus",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/directus-extension-toolkit", "name": "@mintel/directus-extension-toolkit",
"version": "1.8.11", "version": "1.8.15",
"description": "Shared toolkit for Directus extensions in the Mintel ecosystem", "description": "Shared toolkit for Directus extensions in the Mintel ecosystem",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/eslint-config", "name": "@mintel/eslint-config",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -2,7 +2,7 @@
"name": "feedback-commander", "name": "feedback-commander",
"description": "Custom High-Fidelity Management for Directus", "description": "Custom High-Fidelity Management for Directus",
"icon": "extension", "icon": "extension",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"keywords": [ "keywords": [
"directus", "directus",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/gatekeeper", "name": "@mintel/gatekeeper",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/husky-config", "name": "@mintel/husky-config",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/image-processor", "name": "@mintel/image-processor",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/infra", "name": "@mintel/infra",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/journaling", "name": "@mintel/journaling",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@@ -1,7 +1,7 @@
import OpenAI from "openai"; import OpenAI from "openai";
import { DataCommonsClient } from "./clients/data-commons"; import { DataCommonsClient } from "./clients/data-commons";
import { TrendsClient } from "./clients/trends"; import { TrendsClient } from "./clients/trends";
import { SerperClient, type SerperVideoResult } from "./clients/serper"; import { SerperClient } from "./clients/serper";
export interface Fact { export interface Fact {
statement: string; statement: string;
@@ -54,7 +54,6 @@ export class ResearchAgent {
if (data.length > 0) { if (data.length > 0) {
// Analyze trend // Analyze trend
const latest = data[data.length - 1]; const latest = data[data.length - 1];
const max = Math.max(...data.map((d) => d.value));
facts.push({ facts.push({
statement: `Interest in "${kw}" is currently at ${latest.value}% of peak popularity.`, statement: `Interest in "${kw}" is currently at ${latest.value}% of peak popularity.`,
source: "Google Trends", source: "Google Trends",
@@ -246,7 +245,7 @@ Return a JSON object with a single string field "query". Example: {"query": "cor
const evalPrompt = `You are a strict technical evaluator. You must select the MOST RELEVANT educational tech video from the list below based on this core article context: "${topic.slice(0, 800)}..." const evalPrompt = `You are a strict technical evaluator. You must select the MOST RELEVANT educational tech video from the list below based on this core article context: "${topic.slice(0, 800)}..."
Videos: Videos:
${ytVideos.map((v, i) => `[ID: ${i}] Title: "${v.title}" | Channel: "${v.channel}" | Snippet: "${v.snippet || 'none'}"`).join("\n")} ${ytVideos.map((v, i) => `[ID: ${i}] Title: "${v.title}" | Channel: "${v.channel}" | Snippet: "${v.snippet || "none"}"`).join("\n")}
RULES: RULES:
1. The video MUST be highly relevant to the EXACT technical topic of the context. 1. The video MUST be highly relevant to the EXACT technical topic of the context.
@@ -268,7 +267,7 @@ Return ONLY a JSON object: {"bestVideoId": number}`;
evalResponse.choices[0].message.content || '{"bestVideoId": -1}', evalResponse.choices[0].message.content || '{"bestVideoId": -1}',
); );
bestIdx = evalParsed.bestVideoId; bestIdx = evalParsed.bestVideoId;
} catch (e) { } catch {
console.warn("Failed to parse video evaluation response"); console.warn("Failed to parse video evaluation response");
} }
@@ -343,7 +342,7 @@ CRITICAL: Do NOT provide more than 2 trendsKeywords. Keep it extremely focused.`
try { try {
let parsed = JSON.parse( let parsed = JSON.parse(
response.choices[0].message.content || response.choices[0].message.content ||
'{"trendsKeywords": [], "dcVariables": []}', '{"trendsKeywords": [], "dcVariables": []}',
); );
if (Array.isArray(parsed)) { if (Array.isArray(parsed)) {
parsed = parsed[0] || { trendsKeywords: [], dcVariables: [] }; parsed = parsed[0] || { trendsKeywords: [], dcVariables: [] };

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/mail", "name": "@mintel/mail",
"version": "1.8.11", "version": "1.8.15",
"private": false, "private": false,
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/meme-generator", "name": "@mintel/meme-generator",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@@ -123,7 +123,7 @@ IMPORTANT: Return ONLY the JSON object. No markdown wrappers.`,
let result; let result;
try { try {
result = JSON.parse(body); result = JSON.parse(body);
} catch (e) { } catch {
console.error("Failed to parse AI response", body); console.error("Failed to parse AI response", body);
return []; return [];
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-config", "name": "@mintel/next-config",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-feedback", "name": "@mintel/next-feedback",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-observability", "name": "@mintel/next-observability",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/next-utils", "name": "@mintel/next-utils",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/observability", "name": "@mintel/observability",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/pdf", "name": "@mintel/pdf",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/index.js", "module": "dist/index.js",

View File

@@ -2,7 +2,7 @@
"name": "people-manager", "name": "people-manager",
"description": "Custom High-Fidelity Management for Directus", "description": "Custom High-Fidelity Management for Directus",
"icon": "extension", "icon": "extension",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"keywords": [ "keywords": [
"directus", "directus",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/thumbnail-generator", "name": "@mintel/thumbnail-generator",
"version": "1.8.11", "version": "1.8.15",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mintel/tsconfig", "name": "@mintel/tsconfig",
"version": "1.8.11", "version": "1.8.15",
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://npm.infra.mintel.me" "registry": "https://npm.infra.mintel.me"

View File

@@ -2,7 +2,7 @@
"name": "unified-dashboard", "name": "unified-dashboard",
"description": "Custom High-Fidelity Management for Directus", "description": "Custom High-Fidelity Management for Directus",
"icon": "extension", "icon": "extension",
"version": "1.8.11", "version": "1.8.15",
"type": "module", "type": "module",
"keywords": [ "keywords": [
"directus", "directus",