Auto-deploy: 2026-05-17 01:38:08

This commit is contained in:
Hamza-Ayed
2026-05-17 01:38:08 +03:00
parent a433b2f7ae
commit d547decc60
3 changed files with 194 additions and 115 deletions

View File

@@ -17,59 +17,66 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// ─── Core API call ───────────────────────────────────────────────────────────
async function handleGeminiRequest({ apiKey, prompt, tab }) {
async function handleGeminiRequest({ apiKey, prompt, tab, action = 'generateText', jobDescription = '' }) {
// Rate limit check
const canProceed = await checkRateLimit();
if (!canProceed) {
throw new Error('Daily limit reached (1,000 requests). Resets at midnight PT.');
}
// Check cache (keyed by tab + prompt hash — different jobs produce different hashes)
const cacheKey = `cache_${tab}_${hashString(prompt)}`;
// Check cache (keyed by tab + prompt hash)
const cacheStr = prompt || jobDescription;
const cacheKey = `cache_${tab}_${action}_${hashString(cacheStr)}`;
const cached = await getCached(cacheKey);
if (cached) {
return { text: cached, fromCache: true };
return cached; // returns either text object or pdf object
}
// Truncate prompt if too long (free tier has strict TPM limits)
const maxPromptChars = 6000;
const trimmedPrompt = prompt.length > maxPromptChars
? prompt.substring(0, maxPromptChars) + '\n\n[Description truncated for length]'
// Truncate text
const maxChars = 6000;
const trimmedPrompt = prompt && prompt.length > maxChars
? prompt.substring(0, maxChars) + '\n\n[Truncated]'
: prompt;
// Retry logic (up to 3 attempts with LONG backoff for free tier)
const MAX_RETRIES = 3;
const RETRY_DELAYS = [2000, 20000, 30000]; // 2s, 20s, 30s
const RETRY_DELAYS = [2000, 20000, 30000];
let lastError = '';
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
await delay(RETRY_DELAYS[attempt]);
try {
const response = await fetch(`${GEMINI_URL}?key=${apiKey}`, {
const response = await fetch('https://cv.intaleqapp.com/cv/server/generate_cv.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
contents: [{ parts: [{ text: trimmedPrompt }] }],
generationConfig: {
temperature: 0.7,
maxOutputTokens: 2048,
topP: 0.9
}
action: action,
apiKey: apiKey,
prompt: trimmedPrompt,
jobDescription: jobDescription
})
});
if (response.ok) {
const data = await response.json();
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
if (!text) {
lastError = 'Empty response from Gemini.';
continue;
if (action === 'generatePdf') {
if (!data.pdf) throw new Error('Empty PDF response from server.');
await incrementUsage();
const result = { pdf: data.pdf, filename: data.filename, fromCache: false };
await setCached(cacheKey, result);
return result;
} else {
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
if (!text) {
lastError = 'Empty response from API.';
continue;
}
await incrementUsage();
const result = { text, fromCache: false };
await setCached(cacheKey, result);
return result;
}
await incrementUsage();
await setCached(cacheKey, text);
return { text, fromCache: false };
}
const status = response.status;