mirror of
https://github.com/xtekky/gpt4free.git
synced 2025-10-25 01:00:28 +08:00
Add background page
This commit is contained in:
181
g4f/gui/client/background.html
Normal file
181
g4f/gui/client/background.html
Normal file
@@ -0,0 +1,181 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>G4F DEMO</title>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/static/img/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/static/img/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/static/img/favicon-16x16.png">
|
||||
<link rel="manifest" href="/static/img/site.webmanifest">
|
||||
<style>
|
||||
:root {
|
||||
--colour-1: #000000;
|
||||
--colour-2: #ccc;
|
||||
--colour-3: #e4d4ff;
|
||||
--colour-4: #f0f0f0;
|
||||
--colour-5: #181818;
|
||||
--colour-6: #242424;
|
||||
--accent: #8b3dff;
|
||||
--gradient: #1a1a1a;
|
||||
--background: #16101b;
|
||||
--size: 70vw;
|
||||
--top: 50%;
|
||||
--blur: 40px;
|
||||
--opacity: 0.6;
|
||||
}
|
||||
|
||||
.gradient {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
left: 50vw;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at center, var(--accent), var(--gradient));
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
top: var(--top);
|
||||
transform: translate(-50%, -50%);
|
||||
filter: blur(var(--blur)) opacity(var(--opacity));
|
||||
animation: zoom_gradient 6s infinite alternate;
|
||||
display: none;
|
||||
max-height: 100%;
|
||||
transition: max-height 0.25s ease-in;
|
||||
}
|
||||
|
||||
.gradient.hidden {
|
||||
max-height: 0;
|
||||
transition: max-height 0.15s ease-out;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 40em) {
|
||||
body .gradient{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoom_gradient {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Body and text color */
|
||||
body {
|
||||
background: var(--background);
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
iframe {
|
||||
background: transparent;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#background, #image-feed {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
width: 100%;
|
||||
background: black;
|
||||
}
|
||||
|
||||
/* Animation for the gradient circle */
|
||||
@keyframes zoom_gradient {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1.5);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/css/all.min.css">
|
||||
<script>
|
||||
(async () => {
|
||||
const isIframe = window.self !== window.top;
|
||||
const backendUrl = "{{backend_url}}";
|
||||
let url = new URL(window.location.href)
|
||||
if (isIframe && backendUrl) {
|
||||
window.location.replace(`${backendUrl}${url.search}`);
|
||||
return;
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script src="https://unpkg.com/es-module-shims@1.7.0/dist/es-module-shims.js"></script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"@huggingface/hub": "https://cdn.jsdelivr.net/npm/@huggingface/hub@0.21.0/+esm"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<img id="image-feed" class="hidden" alt="Image Feed">
|
||||
|
||||
<!-- Gradient Background Circle -->
|
||||
<div class="gradient"></div></div>
|
||||
<script>
|
||||
(async () => {
|
||||
const url = "https://image.pollinations.ai/feed";
|
||||
const imageFeed = document.getElementById("image-feed");
|
||||
const images = []
|
||||
let es = null;
|
||||
function initES() {
|
||||
if (es == null || es.readyState == EventSource.CLOSED) {
|
||||
const eventSource = new EventSource(url);
|
||||
eventSource.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.nsfw || !data.nologo || data.width < 512 || !data.imageURL || data.isChild || data.status != "end_generating") {
|
||||
return;
|
||||
}
|
||||
const lower = data.prompt.toLowerCase();
|
||||
const tags = ["nsfw", "timeline", "feet", "blood", "soap", "orally", "heel", "latex", "bathroom", "boobs", "charts", "gel", "logo", "infographic", "warts", " bra ", "prostitute", "curvy", "breasts", "written", "bodies", "naked", "classroom", "malone", "dirty", "shoes", "shower", "banner", "fat", "nipples", "couple", "sexual", "sandal", "supplier", "overlord", "succubus", "platinum", "cracy", "crazy", "hemale", "oprah", "lamic", "ropes", "cables", "wires", "dirty", "messy", "cluttered", "chaotic", "disorganized", "disorderly", "untidy", "unorganized", "unorderly", "unsystematic", "disarranged", "disarrayed", "disheveled", "disordered", "jumbled", "muddled", "scattered", "shambolic", "sloppy", "unkept", "unruly"];
|
||||
for (i in tags) {
|
||||
if (lower.indexOf(tags[i]) != -1) {
|
||||
console.log("Skipping image with tag: " + tags[i]);
|
||||
console.debug("Skipping image:", data.imageURL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const landscape = window.innerWidth > window.innerHeight;
|
||||
if (landscape && data.width > data.height) {
|
||||
images.push(data.imageURL);
|
||||
} else if (!landscape && data.width < data.height) {
|
||||
images.push(data.imageURL);
|
||||
}
|
||||
};
|
||||
eventSource.onerror = (event) => {
|
||||
eventSource.close();
|
||||
}
|
||||
imageFeed.onerror = () => {
|
||||
imageFeed.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
initES();
|
||||
setInterval(() => {
|
||||
if (images.length > 0) {
|
||||
imageFeed.classList.remove("hidden");
|
||||
imageFeed.src = images.shift();
|
||||
} else if(imageFeed) {
|
||||
initES();
|
||||
}
|
||||
}, 7000);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -28,43 +28,6 @@
|
||||
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap");
|
||||
|
||||
.gradient {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
left: 50vw;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at center, var(--accent), var(--gradient));
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
top: var(--top);
|
||||
transform: translate(-50%, -50%);
|
||||
filter: blur(var(--blur)) opacity(var(--opacity));
|
||||
animation: zoom_gradient 6s infinite alternate;
|
||||
display: none;
|
||||
max-height: 100%;
|
||||
transition: max-height 0.25s ease-in;
|
||||
}
|
||||
|
||||
.gradient.hidden {
|
||||
max-height: 0;
|
||||
transition: max-height 0.15s ease-out;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 40em) {
|
||||
body .gradient{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoom_gradient {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Body and text color */
|
||||
body {
|
||||
background: var(--background);
|
||||
@@ -188,16 +151,6 @@
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Animation for the gradient circle */
|
||||
@keyframes zoom_gradient {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1.5);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/css/all.min.css">
|
||||
<script>
|
||||
@@ -221,8 +174,7 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="background"></iframe>
|
||||
<img id="image-feed" class="hidden" alt="Image Feed">
|
||||
<iframe id="background" src="/background"></iframe>
|
||||
|
||||
<!-- Gradient Background Circle -->
|
||||
<div class="gradient"></div>
|
||||
@@ -343,6 +295,7 @@
|
||||
const today = new Date().toJSON().slice(0, 10);
|
||||
const max = 6;
|
||||
const cache_id = Math.floor(Math.random() * max);
|
||||
if (cache_id > 3) {
|
||||
let prompt;
|
||||
if (cache_id % 2 == 0) {
|
||||
prompt = `Today is ${new Date().toJSON().slice(0, 10)}.
|
||||
@@ -353,55 +306,12 @@
|
||||
}
|
||||
const response = await fetch(`/backend-api/v2/create?prompt=${prompt}&filter_markdown=html&cache=${cache_id}`);
|
||||
const text = await response.text()
|
||||
if (text) {
|
||||
background.src = `data:text/html;charset=utf-8,${encodeURIComponent(text)}`;
|
||||
const gradient = document.querySelector('.gradient');
|
||||
gradient.classList.add('hidden');
|
||||
|
||||
const url = "https://image.pollinations.ai/feed";
|
||||
const imageFeed = document.getElementById("image-feed");
|
||||
const images = []
|
||||
let es = null;
|
||||
function initES() {
|
||||
if (es == null || es.readyState == EventSource.CLOSED) {
|
||||
const eventSource = new EventSource(url);
|
||||
eventSource.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.nsfw || !data.nologo || data.width < 512 || !data.imageURL || data.isChild || data.status != "end_generating") {
|
||||
return;
|
||||
}
|
||||
const lower = data.prompt.toLowerCase();
|
||||
const tags = ["nsfw", "timeline", "feet", "blood", "soap", "orally", "heel", "latex", "bathroom", "boobs", "charts", "gel", "logo", "infographic", "warts", " bra ", "prostitute", "curvy", "breasts", "written", "bodies", "naked", "classroom", "malone", "dirty", "shoes", "shower", "banner", "fat", "nipples", "couple", "sexual", "sandal", "supplier", "overlord", "succubus", "platinum", "cracy", "crazy", "hemale", "oprah", "lamic", "ropes", "cables", "wires", "dirty", "messy", "cluttered", "chaotic", "disorganized", "disorderly", "untidy", "unorganized", "unorderly", "unsystematic", "disarranged", "disarrayed", "disheveled", "disordered", "jumbled", "muddled", "scattered", "shambolic", "sloppy", "unkept", "unruly"];
|
||||
for (i in tags) {
|
||||
if (lower.indexOf(tags[i]) != -1) {
|
||||
console.log("Skipping image with tag: " + tags[i]);
|
||||
console.debug("Skipping image:", data.imageURL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const landscape = window.innerWidth > window.innerHeight;
|
||||
if (landscape && data.width > data.height) {
|
||||
images.push(data.imageURL);
|
||||
} else if (!landscape && data.width < data.height) {
|
||||
images.push(data.imageURL);
|
||||
}
|
||||
};
|
||||
eventSource.onerror = (event) => {
|
||||
eventSource.close();
|
||||
}
|
||||
imageFeed.onerror = () => {
|
||||
imageFeed.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
initES();
|
||||
setInterval(() => {
|
||||
if (images.length > 0) {
|
||||
imageFeed.classList.remove("hidden");
|
||||
imageFeed.src = images.shift();
|
||||
} else if(imageFeed) {
|
||||
initES();
|
||||
}
|
||||
}, 7000);
|
||||
|
||||
const container = document.querySelector('.container');
|
||||
const button = document.querySelector('.slide-button');
|
||||
|
||||
@@ -27,9 +27,11 @@
|
||||
|
||||
<h2>QR Code</h2>
|
||||
<div id="qrcode"></div>
|
||||
<p id="qrcode-status"></p>
|
||||
<button id="generateQRCode">Generate QR Code</button>
|
||||
|
||||
<script type="module">
|
||||
const conversation_id = "{{conversation_id}}";
|
||||
import QrScanner from 'https://cdn.jsdelivr.net/npm/qr-scanner/qr-scanner.min.js';
|
||||
|
||||
function generate_uuid() {
|
||||
@@ -64,19 +66,29 @@
|
||||
}
|
||||
});
|
||||
|
||||
localStorage.getItem('device_id') || localStorage.setItem('device_id', generate_uuid());
|
||||
document.getElementById('generateQRCode').addEventListener('click', () => {
|
||||
const chat_id = generate_uuid();
|
||||
|
||||
const qrcode = new QRCode(document.getElementById("qrcode"), {
|
||||
text: JSON.stringify({
|
||||
date: Math.floor(Date.now() / 1000),
|
||||
device_id: localStorage.getItem('device_id')
|
||||
}),
|
||||
const url = `/backend-api/v2/chat/${chat_id}`;
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {'content-type': 'application/json'},
|
||||
body: localStorage.getItem(`conversation:${conversation_id}`)
|
||||
});
|
||||
const share = `${new URL(window.location.href).origin}/chat/${encodeURI(chat_id)}/${encodeURI(conversation_id)}`;
|
||||
document.getElementById('qrcode-status').innerText = share;
|
||||
document.getElementById("qrcode").innerHTML = '';
|
||||
const qrcode = new QRCode(
|
||||
document.getElementById("qrcode"),
|
||||
share,
|
||||
{
|
||||
width: 128,
|
||||
height: 128,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.H
|
||||
});
|
||||
});
|
||||
|
||||
const switchButton = document.getElementById('switchCamera');
|
||||
let currentStream = null;
|
||||
|
||||
@@ -592,8 +592,8 @@ input-count .text {
|
||||
display: none;
|
||||
flex-direction: row;
|
||||
height: 36px;
|
||||
width: 120px;
|
||||
margin-right: 130px;
|
||||
width: 140px;
|
||||
margin-right: 150px;
|
||||
z-index: 1005;
|
||||
padding: 10px;
|
||||
margin-top: -4px;
|
||||
|
||||
@@ -439,6 +439,18 @@ const register_message_buttons = async () => {
|
||||
});
|
||||
});
|
||||
|
||||
chatBody.querySelectorAll(".message .fa-qrcode").forEach(async (el) => {
|
||||
if (el.dataset.click) {
|
||||
return
|
||||
}
|
||||
el.dataset.click = true;
|
||||
const message_el = get_message_el(el);
|
||||
el.addEventListener("click", async () => {
|
||||
iframe.src = `/qrcode/${window.conversation_id}#${message_el.dataset.index}`;
|
||||
iframe_container.classList.remove("hidden");
|
||||
});
|
||||
});
|
||||
|
||||
chatBody.querySelectorAll(".message .reasoning_title").forEach(async (el) => {
|
||||
if (el.dataset.click) {
|
||||
return
|
||||
@@ -1446,6 +1458,7 @@ const load_conversation = async (conversation, scroll=true) => {
|
||||
|
||||
add_buttons.push(`<button class="options_button">
|
||||
<div>
|
||||
<span><i class="fa-solid fa-qrcode"></i></span>
|
||||
<span><i class="fa-brands fa-whatsapp"></i></span>
|
||||
<span><i class="fa-solid fa-volume-high"></i></i></span>
|
||||
<span><i class="fa-solid fa-print"></i></span>
|
||||
@@ -2038,7 +2051,7 @@ chatPrompt.addEventListener("input", function() {
|
||||
|
||||
window.addEventListener('load', async function() {
|
||||
if (!window.chat_id) {
|
||||
return;
|
||||
return await load_conversation(JSON.parse(appStorage.getItem(`conversation:${window.conversation_id}`)));
|
||||
}
|
||||
if (!window.conversation_id) {
|
||||
window.conversation_id = window.chat_id;
|
||||
@@ -2046,7 +2059,9 @@ window.addEventListener('load', async function() {
|
||||
const response = await fetch(`/backend-api/v2/chat/${window.chat_id ? window.chat_id : window.conversation_id}`, {
|
||||
headers: {'accept': 'application/json'},
|
||||
});
|
||||
if (response.ok) {
|
||||
if (!response.ok) {
|
||||
return await load_conversation(JSON.parse(appStorage.getItem(`conversation:${window.conversation_id}`)));
|
||||
}
|
||||
let conversation = await response.json();
|
||||
if (!window.conversation_id || conversation.id == window.conversation_id) {
|
||||
window.conversation_id = conversation.id;
|
||||
@@ -2063,8 +2078,12 @@ window.addEventListener('load', async function() {
|
||||
refreshOnHide = true;
|
||||
}
|
||||
});
|
||||
return setInterval(async () => {
|
||||
if (!refreshOnHide || !window.chat_id) {
|
||||
var refreshIntervalId = setInterval(async () => {
|
||||
if (!window.chat_id) {
|
||||
clearInterval(refreshIntervalId);
|
||||
return;
|
||||
}
|
||||
if (!refreshOnHide) {
|
||||
return;
|
||||
}
|
||||
const response = await fetch(`/backend-api/v2/chat/${window.chat_id}`, {
|
||||
@@ -2082,7 +2101,7 @@ window.addEventListener('load', async function() {
|
||||
}
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await safe_load_conversation(window.conversation_id, false);
|
||||
});
|
||||
|
||||
@@ -69,9 +69,9 @@ class Backend_Api(Api):
|
||||
def home():
|
||||
return render_template('home.html')
|
||||
|
||||
@app.route('/qrcode', methods=['GET'])
|
||||
def qrcode():
|
||||
return render_template('qrcode.html')
|
||||
@app.route('/qrcode/<conversation_id>', methods=['GET'])
|
||||
def qrcode(conversation_id: str):
|
||||
return render_template('qrcode.html', conversation_id=conversation_id)
|
||||
|
||||
@app.route('/backend-api/v2/models', methods=['GET'])
|
||||
def jsonify_models(**kwargs):
|
||||
|
||||
@@ -36,6 +36,10 @@ class Website:
|
||||
'function': redirect_home,
|
||||
'methods': ['GET', 'POST']
|
||||
},
|
||||
'/background': {
|
||||
'function': self._background,
|
||||
'methods': ['GET']
|
||||
},
|
||||
}
|
||||
|
||||
def _chat(self, conversation_id):
|
||||
@@ -51,3 +55,6 @@ class Website:
|
||||
|
||||
def _settings(self):
|
||||
return render_template('index.html', conversation_id=str(uuid.uuid4()))
|
||||
|
||||
def _background(self):
|
||||
return render_template('background.html')
|
||||
Reference in New Issue
Block a user