Ajouter des fonctionnalités IA
Intégrez Claude, OpenAI ou tout autre fournisseur d'IA dans votre SaaS avec les Edge Functions et le système de crédits.
Ajouter des fonctionnalités IA
ScaleRocket n'inclut pas de SDK IA spécifique — c'est intentionnel. Vos utilisateurs peuvent avoir besoin de génération de texte, d'analyse d'images, d'assistance au code, ou de rien du tout lié à l'IA. Ce guide vous montre comment ajouter n'importe quel fournisseur d'IA et le connecter au système de crédits existant.
Architecture
L'utilisateur clique "Générer" dans le dashboard
→ apps/app appelle une Edge Function
→ Edge Function déduit les crédits (use-credits)
→ Edge Function appelle l'API IA (Claude, OpenAI, etc.)
→ Retourne le résultat à l'utilisateurLe pattern clé : les appels IA se font dans les Edge Functions, jamais côté client. Cela garde vos clés API sécurisées et vous permet de contrôler les coûts via les crédits.
Exemple : Claude SDK
1. Importer le SDK
Les Edge Functions tournent sur Deno, vous importez directement depuis npm :
// Pas besoin de npm install — Deno importe depuis npm
import Anthropic from "npm:@anthropic-ai/sdk";2. Définir votre clé API
npx supabase secrets set ANTHROPIC_API_KEY=sk-ant-...3. Créer une Edge Function
// supabase/functions/generate-text/index.ts
import { corsHeaders, supabaseAdmin } from "../_shared/supabase.ts";
import Anthropic from "npm:@anthropic-ai/sdk";
const anthropic = new Anthropic({
apiKey: Deno.env.get("ANTHROPIC_API_KEY"),
});
Deno.serve(async (req) => {
// Gérer le preflight CORS
if (req.method === "OPTIONS") {
return new Response("ok", { headers: corsHeaders });
}
try {
// 1. Authentifier l'utilisateur
const authHeader = req.headers.get("Authorization");
if (!authHeader) {
return new Response(
JSON.stringify({ error: "Not authenticated" }),
{ status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
const token = authHeader.replace("Bearer ", "");
const { data: { user }, error: authError } = await supabaseAdmin.auth.getUser(token);
if (authError || !user) {
return new Response(
JSON.stringify({ error: "Invalid token" }),
{ status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// 2. Parser la requête
const { prompt } = await req.json();
if (!prompt || typeof prompt !== "string") {
return new Response(
JSON.stringify({ error: "Missing prompt" }),
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// 3. Déduire les crédits (1 crédit par génération)
const { data: credits, error: creditError } = await supabaseAdmin
.from("credits")
.update({ balance: supabaseAdmin.rpc("decrement_balance", { amount: 1 }) })
.eq("user_id", user.id)
.gte("balance", 1)
.select()
.single();
if (creditError || !credits) {
return new Response(
JSON.stringify({ error: "Insufficient credits" }),
{ status: 402, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// 4. Appeler Claude
const message = await anthropic.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
});
const text = message.content[0].type === "text" ? message.content[0].text : "";
// 5. Retourner le résultat
return new Response(
JSON.stringify({
result: text,
creditsRemaining: credits.balance,
}),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
} catch (error) {
console.error("Generation error:", error);
return new Response(
JSON.stringify({ error: "Generation failed" }),
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
});4. Appeler depuis le dashboard
// apps/app/src/lib/api.ts — ajoutez cette fonction
export async function generateText(prompt: string) {
return callFunction<{ result: string; creditsRemaining: number }>(
"generate-text",
{ method: "POST", body: { prompt } }
);
}5. Utiliser dans un composant
// apps/app/src/routes/_authenticated/generate.tsx
import { createFileRoute } from "@tanstack/react-router";
import { useState } from "react";
import { Button, Card, CardHeader, CardTitle, CardContent } from "@saas/ui";
import { generateText } from "@/lib/api";
export const Route = createFileRoute("/_authenticated/generate")({
component: GeneratePage,
});
function GeneratePage() {
const [prompt, setPrompt] = useState("");
const [result, setResult] = useState("");
const [loading, setLoading] = useState(false);
const handleGenerate = async () => {
setLoading(true);
const { data, error } = await generateText(prompt);
setLoading(false);
if (error) {
alert(error);
return;
}
setResult(data.result);
};
return (
<div className="p-6 max-w-2xl">
<Card>
<CardHeader>
<CardTitle>Générateur IA</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<textarea
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Entrez votre prompt..."
className="w-full rounded-md border p-3 min-h-[100px]"
/>
<Button onClick={handleGenerate} isLoading={loading}>
Générer (1 crédit)
</Button>
{result && (
<div className="rounded-md bg-muted p-4 whitespace-pre-wrap">
{result}
</div>
)}
</CardContent>
</Card>
</div>
);
}6. Déployer
npx supabase functions deploy generate-textUtiliser OpenAI à la place
Le pattern est identique — changez juste le SDK :
// supabase/functions/generate-text/index.ts
import OpenAI from "npm:openai";
const openai = new OpenAI({
apiKey: Deno.env.get("OPENAI_API_KEY"),
});
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: prompt }],
});
const text = response.choices[0].message.content;Définir la clé :
npx supabase secrets set OPENAI_API_KEY=sk-...Coûts en crédits
Vous pouvez varier le coût en crédits selon l'opération :
// Opération légère : 1 crédit
const CREDIT_COST = {
"text-short": 1, // Génération de texte court
"text-long": 3, // Contenu long format
"image": 5, // Génération d'image
"analysis": 2, // Analyse de document
};
// Déduire le montant approprié
const cost = CREDIT_COST[operationType];Cela s'intègre naturellement au système de crédits existant de ScaleRocket — les utilisateurs achètent un plan avec une allocation mensuelle, et chaque opération IA déduit de leur solde.
Conseils de sécurité
- Ne jamais exposer les clés API IA côté client — toujours passer par les Edge Functions
- Toujours déduire les crédits avant d'appeler l'IA — si l'appel échoue, remboursez les crédits
- Définir des limites d'usage — plafonnez le
max_tokenspour éviter les requêtes coûteuses - Valider les entrées — sanitisez les prompts pour prévenir l'injection de prompt
- Logger l'usage — suivez quels utilisateurs font combien de requêtes pour le monitoring des coûts
Étapes suivantes
- Système de crédits — comment fonctionne la déduction de crédits
- Appels API — comment créer et appeler des Edge Functions
- Déploiement — déployer votre Edge Function IA en production
Fini ? Marquez cette page comme terminée.