Skip to content

Commit de13b6d

Browse files
author
AI Assistant
committed
Add optional public frontend Gemini fallback key
1 parent 4544025 commit de13b6d

3 files changed

Lines changed: 25 additions & 8 deletions

File tree

‎.env.example‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Copy this file to .env and set your server-side Gemini API key
22
GEMINI_API_KEY=
33

4+
# Risky fallback for static hosting only. This key is public in client bundle.
5+
# Lock it down with strict HTTP referrer + API restrictions.
6+
VITE_PUBLIC_GEMINI_API_KEY=
7+
48
# Optional client-side Sentry DSN for error monitoring
59
VITE_SENTRY_DSN=

‎README.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ API key resolution priority:
123123

124124
1. User-saved key from Settings (optional override)
125125
2. `GEMINI_API_KEY` on backend server (`.env`)
126+
3. `VITE_PUBLIC_GEMINI_API_KEY` frontend fallback (risky; static hosting only)
126127

127128
Notes:
128129

@@ -131,6 +132,15 @@ Notes:
131132
- 🌐 On static hosting without backend (for example GitHub Pages), users must provide their own Gemini key in Settings.
132133
- 🔀 Gateway behavior: app first tries backend proxy, then falls back to direct Gemini calls when a user key is available.
133134

135+
Risky fallback (not truly safe):
136+
137+
- You can set `VITE_PUBLIC_GEMINI_API_KEY` for static hosts.
138+
- This key is public and extractable from the client bundle.
139+
- Apply strict restrictions in Google Cloud:
140+
- API restriction: Generative Language API only.
141+
- HTTP referrer restriction: your exact domains only (for example `https://abdullahmalik-ctrl.github.io/*`).
142+
- Tight quotas and usage alerts.
143+
134144
## ✨ Key Features
135145

136146
### 🎯 Core Experience

‎src/shared/services/geminiGatewayService.js‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const GEMINI_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta';
2+
const PUBLIC_FRONTEND_FALLBACK_KEY = (import.meta.env.VITE_PUBLIC_GEMINI_API_KEY || '').trim();
23

34
const safeJson = async (response) => {
45
const text = await response.text();
@@ -37,11 +38,12 @@ const tryProxyGenerate = async ({ modelName, contents, generationConfig, customA
3738
};
3839

3940
const tryDirectGenerate = async ({ modelName, contents, generationConfig, customApiKey }) => {
40-
if (!customApiKey) {
41+
const resolvedKey = (customApiKey || PUBLIC_FRONTEND_FALLBACK_KEY).trim();
42+
if (!resolvedKey) {
4143
throw new Error('No user API key found for direct Gemini call.');
4244
}
4345

44-
const endpoint = `${GEMINI_BASE_URL}/models/${modelName}:generateContent?key=${encodeURIComponent(customApiKey)}`;
46+
const endpoint = `${GEMINI_BASE_URL}/models/${modelName}:generateContent?key=${encodeURIComponent(resolvedKey)}`;
4547
const payload = generationConfig ? { contents, generationConfig } : { contents };
4648

4749
const response = await fetch(endpoint, {
@@ -62,8 +64,8 @@ export const generateViaGateway = async ({ modelName, contents, generationConfig
6264
try {
6365
return await tryProxyGenerate({ modelName, contents, generationConfig, customApiKey });
6466
} catch (proxyError) {
65-
if (!customApiKey) {
66-
throw new Error('Backend is unavailable and no user API key is set. Add your Gemini API key in Settings for live static hosting.');
67+
if (!customApiKey && !PUBLIC_FRONTEND_FALLBACK_KEY) {
68+
throw new Error('Backend is unavailable and no API key is available. Add your key in Settings or configure VITE_PUBLIC_GEMINI_API_KEY.');
6769
}
6870

6971
try {
@@ -90,11 +92,12 @@ const tryProxyModels = async (customApiKey) => {
9092
};
9193

9294
const tryDirectModels = async (customApiKey) => {
93-
if (!customApiKey) {
95+
const resolvedKey = (customApiKey || PUBLIC_FRONTEND_FALLBACK_KEY).trim();
96+
if (!resolvedKey) {
9497
throw new Error('No API key provided for direct model lookup.');
9598
}
9699

97-
const endpoint = `${GEMINI_BASE_URL}/models?key=${encodeURIComponent(customApiKey)}`;
100+
const endpoint = `${GEMINI_BASE_URL}/models?key=${encodeURIComponent(resolvedKey)}`;
98101
const response = await fetch(endpoint);
99102
const data = await safeJson(response);
100103

@@ -113,8 +116,8 @@ export const fetchModelsViaGateway = async (customApiKey) => {
113116
try {
114117
return await tryProxyModels(customApiKey);
115118
} catch (_proxyError) {
116-
if (!customApiKey) {
117-
throw new Error('Model list requires your API key when backend is not running.');
119+
if (!customApiKey && !PUBLIC_FRONTEND_FALLBACK_KEY) {
120+
throw new Error('Model list requires API key when backend is not running.');
118121
}
119122
return tryDirectModels(customApiKey);
120123
}

0 commit comments

Comments
 (0)