Your task is to review a pull request. Instructions:
- Write in name of g4f copilot. Don't use placeholder.
- Write the review in GitHub Markdown format.
- Thank the author for contributing to the project.

Pull request author: None
Pull request title: [pull] main from xtekky:main
Pull request description:
---
See Commits and Changes for more details.

-----
Created by [<img src="https://prod.download/pull-18h-svg" valign="bottom"/> **pull[bot]**](https://github.com/wei/pull)

_Can you help keep this open source service alive? **[💖 Please sponsor : )](https://prod.download/pull-pr-sponsor)**_
---

Diff:
```diff
diff --git a/g4f/gui/client/static/js/chat.v1.js b/g4f/gui/client/static/js/chat.v1.js
index 9790b261d5..d5a1ffaa85 100644
--- a/g4f/gui/client/static/js/chat.v1.js
+++ b/g4f/gui/client/static/js/chat.v1.js
@@ -57,6 +57,25 @@ function filter_message(text) {
     )
 }
 
+function fallback_clipboard (text) {
+    var textBox = document.createElement("textarea");
+    textBox.value = text;
+    textBox.style.top = "0";
+    textBox.style.left = "0";
+    textBox.style.position = "fixed";
+    document.body.appendChild(textBox);
+    textBox.focus();
+    textBox.select();
+    try {
+        var success = document.execCommand('copy');
+        var msg = success ? 'succeeded' : 'failed';
+        console.log('Clipboard Fallback: Copying text command ' + msg);
+    } catch (e) {
+        console.error('Clipboard Fallback: Unable to copy', e);
+    }
+    document.body.removeChild(textBox);
+}
+
 hljs.addPlugin(new CopyButtonPlugin());
 let typesetPromise = Promise.resolve();
 const highlight = (container) => {
@@ -88,18 +107,31 @@ const register_message_buttons = async () => {
             })
         }
     });
+
     document.querySelectorAll(".message .fa-clipboard").forEach(async (el) => {
         if (!("click" in el.dataset)) {
             el.dataset.click = "true";
             el.addEventListener("click", async () => {
                 const message_el = el.parentElement.parentElement.parentElement;
                 const copyText = await get_message(window.conversation_id, message_el.dataset.index);
-                navigator.clipboard.writeText(copyText);
+               
+            try {        
+                if (!navigator.clipboard) {
+                    throw new Error("navigator.clipboard: Clipboard API unavailable.");
+                }
+                await navigator.clipboard.writeText(copyText);
+            } catch (e) {
+                console.error(e);
+                console.error("Clipboard API writeText() failed! Fallback to document.exec(\"copy\")...");
+                fallback_clipboard(copyText);
+            }
+            
                 el.classList.add("clicked");
                 setTimeout(() => el.classList.remove("clicked"), 1000);
             })
         }
     });
+
     document.querySelectorAll(".message .fa-volume-high").forEach(async (el) => {
         if (!("click" in el.dataset)) {
             el.dataset.click = "true";
@@ -1424,4 +1456,4 @@ if (SpeechRecognition) {
             recognition.start();
         }
     });
-}
\ No newline at end of file
+}
diff --git a/g4f/gui/client/static/js/highlightjs-copy.min.js b/g4f/gui/client/static/js/highlightjs-copy.min.js
index ac11d33ec0..cd8ae9573b 100644
--- a/g4f/gui/client/static/js/highlightjs-copy.min.js
+++ b/g4f/gui/client/static/js/highlightjs-copy.min.js
@@ -1 +1,54 @@
-class CopyButtonPlugin{constructor(options={}){self.hook=options.hook;self.callback=options.callback}"after:highlightElement"({el,text}){let button=Object.assign(document.createElement("button"),{innerHTML:"Copy",className:"hljs-copy-button"});button.dataset.copied=false;el.parentElement.classList.add("hljs-copy-wrapper");el.parentElement.appendChild(button);el.parentElement.style.setProperty("--hljs-theme-background",window.getComputedStyle(el).backgroundColor);button.onclick=function(){if(!navigator.clipboard)return;let newText=text;if(hook&&typeof hook==="function"){newText=hook(text,el)||text}navigator.clipboard.writeText(newText).then(function(){button.innerHTML="Copied!";button.dataset.copied=true;let alert=Object.assign(document.createElement("div"),{role:"status",className:"hljs-copy-alert",innerHTML:"Copied to clipboard"});el.parentElement.appendChild(alert);setTimeout(()=>{button.innerHTML="Copy";button.dataset.copied=false;el.parentElement.removeChild(alert);alert=null},2e3)}).then(function(){if(typeof callback==="function")return callback(newText,el)})}}}
\ No newline at end of file
+class CopyButtonPlugin {
+    constructor(options = {}) {
+        self.hook = options.hook;
+        self.callback = options.callback
+    }
+    "after:highlightElement"({
+        el,
+        text
+    }) {
+        let button = Object.assign(document.createElement("button"), {
+            innerHTML: "Copy",
+            className: "hljs-copy-button"
+        });
+        button.dataset.copied = false;
+        el.parentElement.classList.add("hljs-copy-wrapper");
+        el.parentElement.appendChild(button);
+        el.parentElement.style.setProperty("--hljs-theme-background", window.getComputedStyle(el).backgroundColor);
+        button.onclick = async () => {
+            let newText = text;
+            if (hook && typeof hook === "function") {
+                newText = hook(text, el) || text
+            }
+            try {            
+                if (!navigator.clipboard) {
+                    throw new Error("navigator.clipboard: Clipboard API unavailable.");
+                }
+                await navigator.clipboard.writeText(newText);
+            } catch (e) {
+                console.error(e);
+                console.error("Clipboard API writeText() failed! Fallback to document.exec(\"copy\")...");
+                fallback_clipboard(newText);
+            }
+                button.innerHTML = "Copied!";
+                button.dataset.copied = true;
+                let alert = Object.assign(document.createElement("div"), {
+                    role: "status",
+                    className: "hljs-copy-alert",
+                    innerHTML: "Copied to clipboard"
+                });
+                el.parentElement.appendChild(alert);
+                setTimeout(() => {
+                    button.innerHTML = "Copy";
+                    button.dataset.copied = false;
+                    el.parentElement.removeChild(alert);
+                    alert = null
+                }, 2e3)
+            }
+
+            
+            if (typeof callback === "function") return callback(newText, el);
+            
+        }
+    
+}
diff --git a/g4f/version.py b/g4f/version.py
index eda2b8fe79..403ce37049 100644
--- a/g4f/version.py
+++ b/g4f/version.py
@@ -116,4 +116,4 @@ def check_version(self) -> None:
         except Exception as e:
             print(f'Failed to check g4f version: {e}')
 
-utils = VersionUtils()
\ No newline at end of file
+utils = VersionUtils()

```