fix(audit): prototypes Gemini server-side + retire metrics-token du dépôt
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 5m30s
CI / Deploy production (on server) (push) Successful in 54s

Proxy Gemini côté serveur (plus de clé dans le bundle Vite), port prototype 4000,
et suppression du token métriques placeholder versionné.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Antigravity
2026-06-20 17:11:32 +00:00
parent eab4b3e27b
commit 31e882856c
5 changed files with 152 additions and 19 deletions

View File

@@ -2,7 +2,24 @@
import { GoogleGenAI, Type } from "@google/genai";
import { BrainstormIdea } from "../types";
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
async function generateContent(
request: Parameters<InstanceType<typeof GoogleGenAI>['models']['generateContent']>[0],
) {
if (typeof window !== 'undefined') {
const res = await fetch('/api/gemini/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request),
});
if (!res.ok) throw new Error('Gemini request failed');
const data = await res.json();
return { text: data.text ?? '' };
}
const key = process.env.GEMINI_API_KEY;
if (!key) throw new Error('GEMINI_API_KEY required on server');
const ai = new GoogleGenAI({ apiKey: key });
return ai.models.generateContent(request);
}
const BRAINSTORM_SCHEMA = {
type: Type.OBJECT,
@@ -63,7 +80,7 @@ export async function generateBrainstormWave(
`;
try {
const response = await ai.models.generateContent({
const response = await generateContent({
model: "gemini-3-flash-preview",
contents: [{ role: "user", parts: [{ text: prompt }] }],
config: {
@@ -101,7 +118,7 @@ export async function generateExpansion(parentIdeaTitle: string, parentIdeaDescr
`;
try {
const response = await ai.models.generateContent({
const response = await generateContent({
model: "gemini-3-flash-preview",
contents: [{ role: "user", parts: [{ text: prompt }] }],
config: {
@@ -130,9 +147,27 @@ export async function generateExpansion(parentIdeaTitle: string, parentIdeaDescr
}
}
async function embedContent(
request: Parameters<InstanceType<typeof GoogleGenAI>['models']['embedContent']>[0],
) {
if (typeof window !== 'undefined') {
const res = await fetch('/api/gemini/embed', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request),
});
if (!res.ok) throw new Error('Gemini embed failed');
return res.json();
}
const key = process.env.GEMINI_API_KEY;
if (!key) throw new Error('GEMINI_API_KEY required on server');
const ai = new GoogleGenAI({ apiKey: key });
return ai.models.embedContent(request);
}
export async function getEmbedding(text: string): Promise<number[]> {
try {
const result = await ai.models.embedContent({
const result = await embedContent({
model: 'gemini-embedding-2-preview',
contents: [text],
});
@@ -155,7 +190,7 @@ export function cosineSimilarity(a: number[], b: number[]): number {
export async function nameCluster(noteSummaries: string[]): Promise<string> {
const prompt = `Quel thème commun relie ces notes ? Donne un nom court (2-4 mots).\nNotes :\n${noteSummaries.join('\n- ')}`;
try {
const result = await ai.models.generateContent({
const result = await generateContent({
model: "gemini-3-flash-preview",
contents: prompt
});
@@ -184,7 +219,7 @@ export async function suggestBridgeIdeas(
`;
try {
const response = await ai.models.generateContent({
const response = await generateContent({
model: "gemini-3-flash-preview",
contents: prompt,
config: {
@@ -207,7 +242,7 @@ export async function parseDocument(fileUrl: string, fileName: string): Promise<
try {
// In a real scenario, we would use media upload.
// Here we simulate the extraction.
const response = await ai.models.generateContent({
const response = await generateContent({
model: "gemini-3-flash-preview",
contents: [{ role: "user", parts: [{ text: prompt }] }],
config: {
@@ -236,7 +271,7 @@ export async function extractActionItems(notes: { title: string; content: string
`;
try {
const response = await ai.models.generateContent({
const response = await generateContent({
model: "gemini-3-flash-preview",
contents: prompt,
config: {
@@ -289,7 +324,7 @@ export async function generateFlashcardsForNote(
`;
try {
const response = await ai.models.generateContent({
const response = await generateContent({
model: "gemini-3.5-flash",
contents: [{ role: "user", parts: [{ text: prompt }] }],
config: {