daily bookmarks

This commit is contained in:
2025-12-02 21:21:08 +01:00
parent 3ff25d3f7e
commit 839bd24309
10 changed files with 3303 additions and 49 deletions

View File

@@ -3434,6 +3434,7 @@ let selectionAINoteButton = null;
let selectionAIRaf = null;
let selectionAIHideTimeout = null;
let selectionAIEnabledCached = null;
let selectionAIContextElement = null;
const clearSelectionAIHideTimeout = () => {
if (selectionAIHideTimeout) {
@@ -3447,6 +3448,7 @@ const hideSelectionAIButton = () => {
if (selectionAIContainer) {
selectionAIContainer.style.display = 'none';
}
selectionAIContextElement = null;
if (selectionAIButton) {
selectionAIButton.dataset.selectionText = '';
}
@@ -3511,10 +3513,12 @@ const ensureSelectionAIButton = () => {
showToast('Textauswahl aus Eingabefeldern kann nicht genutzt werden', 'error');
return;
}
const anchorElement = anchorNode && anchorNode.nodeType === Node.TEXT_NODE
? anchorNode.parentElement
: anchorNode;
const postContext = anchorElement ? ensurePrimaryPostElement(anchorElement) : null;
const postContext = selectionAIContextElement
|| (anchorElement ? ensurePrimaryPostElement(anchorElement) : null);
if (!postContext) {
showToast('Keinen zugehörigen Beitrag gefunden', 'error');
return;
@@ -3669,6 +3673,18 @@ const updateSelectionAIButton = async () => {
return;
}
const contextElement = (() => {
const containerNode = range.commonAncestorContainer || anchorNode;
if (!containerNode) {
return null;
}
const element = containerNode.nodeType === Node.TEXT_NODE
? containerNode.parentElement
: containerNode;
return element ? ensurePrimaryPostElement(element) : null;
})();
selectionAIContextElement = contextElement;
const container = ensureSelectionAIButton();
if (!selectionAIButton || !selectionAINoteButton) {
hideSelectionAIButton();
@@ -4636,42 +4652,53 @@ function sanitizeAIComment(comment) {
* Generate AI comment for a post
*/
async function generateAIComment(postText, profileNumber, options = {}) {
const { signal = null, preferredCredentialId = null } = options;
try {
const payload = {
postText,
profileNumber
};
const { signal = null, preferredCredentialId = null, maxAttempts = 3 } = options;
const payload = {
postText,
profileNumber
};
if (typeof preferredCredentialId === 'number') {
payload.preferredCredentialId = preferredCredentialId;
}
const response = await backendFetch(`${API_URL}/ai/generate-comment`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to generate comment');
}
const data = await response.json();
const sanitizedComment = sanitizeAIComment(data.comment);
if (!sanitizedComment) {
throw new Error('AI-Antwort enthält keinen gültigen Text');
}
return sanitizedComment;
} catch (error) {
console.error('[FB Tracker] AI comment generation failed:', error);
throw error;
if (typeof preferredCredentialId === 'number') {
payload.preferredCredentialId = preferredCredentialId;
}
let lastError = null;
const attempts = Math.max(1, maxAttempts);
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
const response = await backendFetch(`${API_URL}/ai/generate-comment`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to generate comment');
}
const data = await response.json();
const sanitizedComment = sanitizeAIComment(data.comment);
if (sanitizedComment) {
return sanitizedComment;
}
lastError = new Error('AI response empty');
} catch (error) {
lastError = error;
}
if (attempt < attempts) {
console.warn(`[FB Tracker] AI comment generation attempt ${attempt} failed, retrying...`, lastError);
await delay(200);
}
}
console.error('[FB Tracker] AI comment generation failed after retries:', lastError);
throw new Error('AI-Antwort konnte nicht erzeugt werden. Bitte später erneut versuchen.');
}
async function handleSelectionAIRequest(selectionText, sendResponse) {