-
Notifications
You must be signed in to change notification settings - Fork 148
Retry api logic #166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Retry api logic #166
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,7 +73,6 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => { | |
| }); | ||
| } catch (error) { | ||
| console.error("Context menu translation error:", error); | ||
| // Show error in popup | ||
| chrome.scripting.executeScript({ | ||
| target: { tabId: tab.id }, | ||
| func: showErrorPopup, | ||
|
|
@@ -176,7 +175,7 @@ function getTranslationPrompt(style, level) { | |
| } | ||
|
|
||
| // Function to translate text using Groq API | ||
| async function translateText(text) { | ||
| async function translateText(text, retries = 2) { | ||
| const { groqApiKey, translationSettings } = await chrome.storage.local.get([ | ||
| "groqApiKey", | ||
| "translationSettings", | ||
|
|
@@ -190,56 +189,66 @@ async function translateText(text) { | |
| const level = translationSettings?.level || "balanced"; | ||
| const prompt = getTranslationPrompt(style, level); | ||
|
|
||
| try { | ||
| const response = await fetch( | ||
| "https://api.groq.com/openai/v1/chat/completions", | ||
| { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${groqApiKey}`, | ||
| }, | ||
| body: JSON.stringify({ | ||
| messages: [ | ||
| { | ||
| role: "system", | ||
| content: prompt, | ||
| }, | ||
| { | ||
| role: "user", | ||
| content: text, | ||
| }, | ||
| ], | ||
| model: "meta-llama/llama-4-scout-17b-16e-instruct", | ||
| temperature: 0.7, | ||
| max_tokens: 1000, | ||
| }), | ||
| } | ||
| ); | ||
| const payload = { | ||
| messages: [ | ||
| { role: "system", content: prompt }, | ||
| { role: "user", content: text }, | ||
| ], | ||
| model: "meta-llama/llama-4-scout-17b-16e-instruct", | ||
| temperature: 0.7, | ||
| max_tokens: 1000, | ||
| }; | ||
|
|
||
| if (!response.ok) { | ||
| const errorData = await response.json().catch(() => ({})); | ||
| throw new Error( | ||
| errorData.error?.message || `API error: ${response.status}` | ||
| for (let attempt = 0; attempt <= retries; attempt++) { | ||
| try { | ||
| const response = await fetch( | ||
| "https://api.groq.com/openai/v1/chat/completions", | ||
| { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${groqApiKey}`, | ||
| }, | ||
| body: JSON.stringify(payload), | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| const data = await response.json(); | ||
| const translatedText = data.choices[0].message.content.trim(); | ||
| if (!response.ok) { | ||
| const errorData = await response.json().catch(() => ({})); | ||
|
|
||
| if (!translatedText) { | ||
| throw new Error("Empty translation received"); | ||
| } | ||
| // Retry only on server (5xx) errors | ||
| if (response.status >= 500 && attempt < retries) { | ||
| console.warn(`Retrying translateText (attempt ${attempt + 1})`); | ||
| continue; | ||
| } | ||
|
|
||
| return translatedText; | ||
| } catch (error) { | ||
| console.error("Translation error:", error); | ||
| throw error; | ||
| throw new Error( | ||
| errorData.error?.message || `API error: ${response.status}` | ||
| ); | ||
| } | ||
|
|
||
| const data = await response.json(); | ||
| const translatedText = data.choices[0].message.content.trim(); | ||
|
|
||
| if (!translatedText) { | ||
| throw new Error("Empty translation received"); | ||
| } | ||
|
|
||
| return translatedText; | ||
|
|
||
| } catch (error) { | ||
| if (attempt === retries) { | ||
| throw error; | ||
| } | ||
| console.warn(`translateText failed on attempt ${attempt + 1}: ${error.message}`); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| // Function to explain text using Groq API | ||
| async function explainText(text) { | ||
| async function explainText(text, retries = 2) { | ||
| const { groqApiKey, translationSettings } = await chrome.storage.local.get([ | ||
| "groqApiKey", | ||
| "translationSettings", | ||
|
|
@@ -251,68 +260,81 @@ async function explainText(text) { | |
|
|
||
| const style = translationSettings?.style || "hinglish"; | ||
| const level = translationSettings?.level || "balanced"; | ||
|
|
||
| const prompt = `You are an AI assistant that explains concepts in ${ | ||
| style === "hindi" ? "Hindi" : "Hinglish" | ||
| }. | ||
| Provide a clear and detailed explanation of the given text. | ||
| Make it easy to understand and use ${ | ||
| level === "moreHindi" | ||
| ? "more Hindi words" | ||
| : level === "moreEnglish" | ||
| ? "more English words" | ||
| : "a balanced mix of Hindi and English words" | ||
| }. | ||
| Format your response in a clear, structured way with bullet points or short paragraphs. | ||
| Only respond with the explanation, no additional text.`; | ||
|
|
||
| try { | ||
| const response = await fetch( | ||
| "https://api.groq.com/openai/v1/chat/completions", | ||
| { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${groqApiKey}`, | ||
| }, | ||
| body: JSON.stringify({ | ||
| messages: [ | ||
| { | ||
| role: "system", | ||
| content: prompt, | ||
| }, | ||
| { | ||
| role: "user", | ||
| content: text, | ||
| }, | ||
| ], | ||
| model: "meta-llama/llama-4-scout-17b-16e-instruct", | ||
| temperature: 0.7, | ||
| max_tokens: 1000, | ||
| }), | ||
| } | ||
| ); | ||
| Provide a clear and detailed explanation of the given text. | ||
| Make it easy to understand and use ${ | ||
| level === "moreHindi" | ||
| ? "more Hindi words" | ||
| : level === "moreEnglish" | ||
| ? "more English words" | ||
| : "a balanced mix of Hindi and English words" | ||
| }. | ||
| Format your response in a clear, structured way with bullet points or short paragraphs. | ||
| Only respond with the explanation, no additional text.`; | ||
|
|
||
| const payload = { | ||
| messages: [ | ||
| { role: "system", content: prompt }, | ||
| { role: "user", content: text }, | ||
| ], | ||
| model: "meta-llama/llama-4-scout-17b-16e-instruct", | ||
| temperature: 0.7, | ||
| max_tokens: 1000, | ||
| }; | ||
|
|
||
| if (!response.ok) { | ||
| const errorData = await response.json().catch(() => ({})); | ||
| throw new Error( | ||
| errorData.error?.message || `API error: ${response.status}` | ||
| // Retry loop | ||
| for (let attempt = 0; attempt <= retries; attempt++) { | ||
| try { | ||
| const response = await fetch( | ||
| "https://api.groq.com/openai/v1/chat/completions", | ||
| { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${groqApiKey}`, | ||
| }, | ||
| body: JSON.stringify(payload), | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| const data = await response.json(); | ||
| const explanation = data.choices[0].message.content.trim(); | ||
| // If response not OK | ||
| if (!response.ok) { | ||
| const errorData = await response.json().catch(() => ({})); | ||
|
|
||
| if (!explanation) { | ||
| throw new Error("Empty explanation received"); | ||
| } | ||
| // Retry only if server error (5xx) | ||
| if (response.status >= 500 && attempt < retries) { | ||
| console.warn(`Retrying explainText (attempt ${attempt + 1})`); | ||
| continue; | ||
| } | ||
|
|
||
| throw new Error(errorData.error?.message || `API error: ${response.status}`); | ||
| } | ||
|
|
||
| // Successful response | ||
| const data = await response.json(); | ||
| const explanation = data.choices[0].message.content.trim(); | ||
|
|
||
| return explanation; | ||
| } catch (error) { | ||
| console.error("Explanation error:", error); | ||
| throw error; | ||
| if (!explanation) { | ||
| throw new Error("Empty explanation received"); | ||
| } | ||
|
|
||
| return explanation; | ||
|
|
||
| } catch (error) { | ||
| // Retry on failure, unless it's the last attempt | ||
| if (attempt === retries) { | ||
| throw error; | ||
| } | ||
| console.warn(`explainText failed on attempt ${attempt + 1}: ${error.message}`); | ||
| } | ||
| } | ||
|
Comment on lines
+289
to
333
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion Apply the same retry improvements as translateText. The retry logic correctly handles 5xx server errors but has the same enhancement opportunities as the
Apply the same exponential backoff and network error handling improvements as suggested for the π€ Prompt for AI Agents |
||
| } | ||
|
|
||
|
|
||
|
|
||
| // Function to show loading popup | ||
| function showLoadingPopup() { | ||
| const popup = document.createElement("div"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Implement exponential backoff and handle network errors.
The retry logic correctly handles 5xx server errors, but could be enhanced for better resilience:
Consider this enhanced implementation:
for (let attempt = 0; attempt <= retries; attempt++) { try { + // Add exponential backoff delay (except for first attempt) + if (attempt > 0) { + const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000); + await new Promise(resolve => setTimeout(resolve, delay)); + } + const response = await fetch( "https://api.groq.com/openai/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${groqApiKey}`, }, body: JSON.stringify(payload), } ); if (!response.ok) { const errorData = await response.json().catch(() => ({})); // Retry only on server (5xx) errors if (response.status >= 500 && attempt < retries) { console.warn(`Retrying translateText (attempt ${attempt + 1})`); continue; } throw new Error( errorData.error?.message || `API error: ${response.status}` ); } const data = await response.json(); const translatedText = data.choices[0].message.content.trim(); if (!translatedText) { throw new Error("Empty translation received"); } return translatedText; } catch (error) { + // Handle network errors (fetch exceptions) for retries + const isNetworkError = error.name === 'TypeError' || + error.message.includes('fetch') || + error.message.includes('network'); + + if ((isNetworkError || error.message.includes('5')) && attempt < retries) { + console.warn(`translateText failed on attempt ${attempt + 1}: ${error.message}`); + continue; + } + if (attempt === retries) { throw error; } - console.warn(`translateText failed on attempt ${attempt + 1}: ${error.message}`); } }π Committable suggestion
π€ Prompt for AI Agents