fix(gemini): budget-check före bildhämtning så spärr triggars tidigt

This commit is contained in:
Sven (AAMOS AI)
2026-08-12 16:30:49 +07:00
parent 6c581bec1a
commit 7dda0fad00
4 changed files with 27 additions and 6 deletions
+1 -1
View File
@@ -232,7 +232,7 @@ export async function authRoutes(app: FastifyInstance) {
// Trial startas först när e-posten är verifierad. En trial per verifierad e-post. // Trial startas först när e-posten är verifierad. En trial per verifierad e-post.
const [existingTrial] = await app.db const [existingTrial] = await app.db
.select({ id: schema.trials.id }) .select({ userId: schema.trials.userId })
.from(schema.trials) .from(schema.trials)
.where(eq(schema.trials.userId, stored.userId)) .where(eq(schema.trials.userId, stored.userId))
.limit(1); .limit(1);
+22 -4
View File
@@ -326,12 +326,21 @@ export class GeminiAamosClient implements AamosClient {
const locale = options.localeContext ?? this.defaultLocale(); const locale = options.localeContext ?? this.defaultLocale();
const started = Date.now(); const started = Date.now();
const imageCount = Math.min(input.imageUrls.length, 6);
const estimatedCostUsd = imageCount * COST_ESTIMATE_PER_IMAGE_USD;
if (await this.isOverBudget(estimatedCostUsd)) {
return {
status: "failed",
output: null,
error: "Global Gemini-dagsbudget är förbrukad.",
};
}
const imageParts = await Promise.all( const imageParts = await Promise.all(
input.imageUrls.slice(0, 6).map((url) => this.fetchOneImage(url, this.cfg.timeoutMs)), input.imageUrls.slice(0, 6).map((url) => this.fetchOneImage(url, this.cfg.timeoutMs)),
); );
const estimatedCostUsd = imageParts.length * COST_ESTIMATE_PER_IMAGE_USD; if (imageParts.length === 0) {
if (await this.isOverBudget(estimatedCostUsd)) {
return { return {
status: "failed", status: "failed",
output: null, output: null,
@@ -416,8 +425,8 @@ export class GeminiAamosClient implements AamosClient {
const locale = options.localeContext ?? this.defaultLocale(); const locale = options.localeContext ?? this.defaultLocale();
const started = Date.now(); const started = Date.now();
const imageParts = await this.fetchImageParts(imageUrls, this.cfg.timeoutMs); const imageCount = Math.min(imageUrls.length, 6);
const estimatedCostUsd = imageParts.length * costEstimatePerImage; const estimatedCostUsd = imageCount * costEstimatePerImage;
if (await this.isOverBudget(estimatedCostUsd)) { if (await this.isOverBudget(estimatedCostUsd)) {
return { return {
status: "failed", status: "failed",
@@ -426,6 +435,15 @@ export class GeminiAamosClient implements AamosClient {
} as AamosResult<T>; } as AamosResult<T>;
} }
const imageParts = await this.fetchImageParts(imageUrls, this.cfg.timeoutMs);
if (imageParts.length === 0) {
return {
status: "failed",
output: null,
error: "Global Gemini-dagsbudget är förbrukad.",
} as AamosResult<T>;
}
const payload = { const payload = {
contents: [{ parts: [{ text: prompt }, ...imageParts] }], contents: [{ parts: [{ text: prompt }, ...imageParts] }],
generationConfig: { generationConfig: {
+2
View File
@@ -15,6 +15,8 @@ import type {
OpsFeedbackBlock, OpsFeedbackBlock,
OpsWallBlock, OpsWallBlock,
OpsWallTile, OpsWallTile,
OpsAlarm,
OpsAlarmBlock,
} from "@app/shared-types"; } from "@app/shared-types";
import { SUBSCRIPTION_PLANS, type SubscriptionPlan } from "@app/shared-types"; import { SUBSCRIPTION_PLANS, type SubscriptionPlan } from "@app/shared-types";
import type { Database } from "./client.js"; import type { Database } from "./client.js";
+2 -1
View File
@@ -139,13 +139,14 @@ describe("buildWall", () => {
expect(brott.tone).toBe("warn"); expect(brott.tone).toBe("warn");
}); });
it("alla sex tiles finns i rätt ordning", () => { it("alla sju tiles finns i rätt ordning", () => {
const tiles = buildWall(baseSummary()).boards[0]!.tiles; const tiles = buildWall(baseSummary()).boards[0]!.tiles;
expect(tiles.map((t) => t.label)).toEqual([ expect(tiles.map((t) => t.label)).toEqual([
"MRR", "MRR",
"Aktiva nu", "Aktiva nu",
"Betalande", "Betalande",
"Trial-konv", "Trial-konv",
"AI-budget",
"Workers", "Workers",
"Allergen-brott", "Allergen-brott",
]); ]);