Update app.py
Browse files
app.py
CHANGED
@@ -17,8 +17,13 @@ BLOCKED_DOMAINS = [
|
|
17 |
|
18 |
# ββββββββββββββββββββββββββ 2. CURATED CATEGORIES ββββββββββββββββββββββββββ
|
19 |
CATEGORIES = {
|
20 |
-
|
21 |
"Productivity": [
|
|
|
|
|
|
|
|
|
|
|
22 |
"https://huggingface.co/spaces/VIDraft/Robo-Beam",
|
23 |
"https://huggingface.co/spaces/VIDraft/voice-trans",
|
24 |
"https://huggingface.co/spaces/Heartsync/FREE-NSFW-HUB",
|
@@ -42,8 +47,14 @@ CATEGORIES = {
|
|
42 |
"https://huggingface.co/spaces/ginipick/Change-Hair",
|
43 |
],
|
44 |
"Multimodal": [
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
"https://huggingface.co/spaces/ginigen/VEO3-Free",
|
46 |
-
"https://huggingface.co/spaces/ginigen/VEO3-
|
47 |
"https://huggingface.co/spaces/Heartsync/WAN2-1-fast-T2V-FusioniX",
|
48 |
"https://huggingface.co/spaces/Heartsync/adult",
|
49 |
"https://huggingface.co/spaces/Heartsync/NSFW-Uncensored",
|
@@ -64,6 +75,9 @@ CATEGORIES = {
|
|
64 |
"https://huggingface.co/spaces/fantaxy/Remove-Video-Background",
|
65 |
],
|
66 |
"Professional": [
|
|
|
|
|
|
|
67 |
"https://huggingface.co/spaces/Heartsync/Novel-NSFW",
|
68 |
"https://huggingface.co/spaces/fantaxy/fantasy-novel",
|
69 |
"https://huggingface.co/spaces/VIDraft/money-radar",
|
@@ -78,6 +92,7 @@ CATEGORIES = {
|
|
78 |
"https://huggingface.co/spaces/ginigen/multimodal-chat-mbti-korea",
|
79 |
],
|
80 |
"Image": [
|
|
|
81 |
"https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-REAL",
|
82 |
"https://huggingface.co/spaces/ginigen/FLUX-Ghibli-LoRA2",
|
83 |
"https://huggingface.co/spaces/aiqcamp/REMOVAL-TEXT-IMAGE",
|
@@ -111,7 +126,7 @@ CATEGORIES = {
|
|
111 |
"LLM / VLM": [
|
112 |
"https://huggingface.co/spaces/fantaxy/fantasy-novel",
|
113 |
"https://huggingface.co/spaces/ginigen/deepseek-r1-0528-API",
|
114 |
-
"https://huggingface.co/spaces/aiqcamp/Mistral-Devstral-API"
|
115 |
"https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528",
|
116 |
"https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528-qwen3-8b",
|
117 |
"https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528",
|
@@ -496,13 +511,14 @@ body{margin:0;font-family:Nunito,sans-serif;background:#f6f8fb;}
|
|
496 |
</head>
|
497 |
<body>
|
498 |
<header style="text-align: center; padding: 20px; background: linear-gradient(135deg, #f6f8fb, #e2e8f0); border-bottom: 1px solid #ddd;">
|
499 |
-
<h1 style="margin-bottom: 10px;">π
|
500 |
<p>
|
501 |
<a href="https://discord.gg/openfreeai" target="_blank"><img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="badge"></a>
|
502 |
</p>
|
503 |
</header>
|
504 |
<div class="tabs" id="tabs"></div>
|
505 |
<div id="content"></div>
|
|
|
506 |
<script>
|
507 |
// Basic configuration
|
508 |
const cats = {{cats|tojson}};
|
@@ -510,6 +526,7 @@ const tabs = document.getElementById('tabs');
|
|
510 |
const content = document.getElementById('content');
|
511 |
let active = "";
|
512 |
let currentPage = 1;
|
|
|
513 |
// Simple utility functions
|
514 |
function loadHTML(url, callback) {
|
515 |
const xhr = new XMLHttpRequest();
|
@@ -521,6 +538,7 @@ function loadHTML(url, callback) {
|
|
521 |
};
|
522 |
xhr.send();
|
523 |
}
|
|
|
524 |
function makeRequest(url, method, data, callback) {
|
525 |
const xhr = new XMLHttpRequest();
|
526 |
xhr.open(method, url, true);
|
@@ -535,11 +553,13 @@ function makeRequest(url, method, data, callback) {
|
|
535 |
xhr.send();
|
536 |
}
|
537 |
}
|
|
|
538 |
function updateTabs() {
|
539 |
Array.from(tabs.children).forEach(b => {
|
540 |
b.classList.toggle('active', b.dataset.c === active);
|
541 |
});
|
542 |
}
|
|
|
543 |
// Tab handlers
|
544 |
function loadCategory(cat, page) {
|
545 |
if(cat === active && currentPage === page) return;
|
@@ -584,6 +604,7 @@ function loadCategory(cat, page) {
|
|
584 |
content.innerHTML = html;
|
585 |
});
|
586 |
}
|
|
|
587 |
function loadFavorites(page) {
|
588 |
if(active === 'Favorites' && currentPage === page) return;
|
589 |
active = 'Favorites';
|
@@ -641,6 +662,7 @@ function loadFavorites(page) {
|
|
641 |
content.innerHTML = html;
|
642 |
});
|
643 |
}
|
|
|
644 |
function loadManage() {
|
645 |
if(active === 'Manage') return;
|
646 |
active = 'Manage';
|
@@ -663,6 +685,7 @@ function loadManage() {
|
|
663 |
|
664 |
loadUrlList();
|
665 |
}
|
|
|
666 |
// URL management functions
|
667 |
function loadUrlList() {
|
668 |
makeRequest('/api/favorites?per_page=100', 'GET', null, function(data) {
|
@@ -692,6 +715,7 @@ function loadUrlList() {
|
|
692 |
urlList.innerHTML = html;
|
693 |
});
|
694 |
}
|
|
|
695 |
function addUrl() {
|
696 |
const url = document.getElementById('new-url').value.trim();
|
697 |
|
@@ -715,6 +739,7 @@ function addUrl() {
|
|
715 |
}
|
716 |
});
|
717 |
}
|
|
|
718 |
function editUrl(url) {
|
719 |
// Decode URL if it was previously escaped
|
720 |
const decodedUrl = url.replace(/\\'/g, "'");
|
@@ -738,6 +763,7 @@ function editUrl(url) {
|
|
738 |
}
|
739 |
});
|
740 |
}
|
|
|
741 |
function deleteUrl(url) {
|
742 |
// Decode URL if it was previously escaped
|
743 |
const decodedUrl = url.replace(/\\'/g, "'");
|
@@ -758,6 +784,7 @@ function deleteUrl(url) {
|
|
758 |
}
|
759 |
});
|
760 |
}
|
|
|
761 |
function showStatus(id, message, success) {
|
762 |
const status = document.getElementById(id);
|
763 |
status.textContent = message;
|
@@ -766,6 +793,7 @@ function showStatus(id, message, success) {
|
|
766 |
status.className = 'status';
|
767 |
}, 3000);
|
768 |
}
|
|
|
769 |
// Create tabs
|
770 |
// Favorites tab first
|
771 |
const favTab = document.createElement('button');
|
@@ -774,6 +802,7 @@ favTab.textContent = 'Favorites';
|
|
774 |
favTab.dataset.c = 'Favorites';
|
775 |
favTab.onclick = function() { loadFavorites(1); };
|
776 |
tabs.appendChild(favTab);
|
|
|
777 |
// Category tabs
|
778 |
cats.forEach(c => {
|
779 |
const b = document.createElement('button');
|
@@ -783,6 +812,7 @@ cats.forEach(c => {
|
|
783 |
b.onclick = function() { loadCategory(c, 1); };
|
784 |
tabs.appendChild(b);
|
785 |
});
|
|
|
786 |
// Manage tab last
|
787 |
const manageTab = document.createElement('button');
|
788 |
manageTab.className = 'tab manage';
|
@@ -790,6 +820,7 @@ manageTab.textContent = 'Manage';
|
|
790 |
manageTab.dataset.c = 'Manage';
|
791 |
manageTab.onclick = function() { loadManage(); };
|
792 |
tabs.appendChild(manageTab);
|
|
|
793 |
// Start with Favorites tab
|
794 |
loadFavorites(1);
|
795 |
</script>
|
|
|
17 |
|
18 |
# ββββββββββββββββββββββββββ 2. CURATED CATEGORIES ββββββββββββββββββββββββββ
|
19 |
CATEGORIES = {
|
20 |
+
|
21 |
"Productivity": [
|
22 |
+
|
23 |
+
"https://huggingface.co/spaces/aiqtech/Heatmap-Leaderboard",
|
24 |
+
"https://huggingface.co/spaces/VIDraft/DNA-CASINO",
|
25 |
+
|
26 |
+
"https://huggingface.co/spaces/openfree/Open-GAMMA",
|
27 |
"https://huggingface.co/spaces/VIDraft/Robo-Beam",
|
28 |
"https://huggingface.co/spaces/VIDraft/voice-trans",
|
29 |
"https://huggingface.co/spaces/Heartsync/FREE-NSFW-HUB",
|
|
|
47 |
"https://huggingface.co/spaces/ginipick/Change-Hair",
|
48 |
],
|
49 |
"Multimodal": [
|
50 |
+
|
51 |
+
"https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-photo",
|
52 |
+
|
53 |
+
"https://huggingface.co/spaces/fantaxy/YTB-TEST",
|
54 |
+
"https://huggingface.co/spaces/ginigen/Seedance-Free",
|
55 |
+
"https://huggingface.co/spaces/Heartsync/VEO3-RealTime",
|
56 |
"https://huggingface.co/spaces/ginigen/VEO3-Free",
|
57 |
+
"https://huggingface.co/spaces/ginigen/VEO3-Directors",
|
58 |
"https://huggingface.co/spaces/Heartsync/WAN2-1-fast-T2V-FusioniX",
|
59 |
"https://huggingface.co/spaces/Heartsync/adult",
|
60 |
"https://huggingface.co/spaces/Heartsync/NSFW-Uncensored",
|
|
|
75 |
"https://huggingface.co/spaces/fantaxy/Remove-Video-Background",
|
76 |
],
|
77 |
"Professional": [
|
78 |
+
"https://huggingface.co/spaces/Heartsync/NSFW-novels",
|
79 |
+
"https://huggingface.co/spaces/aiqtech/SOMA-Oriental",
|
80 |
+
"https://huggingface.co/spaces/VIDraft/SOMA-AGI",
|
81 |
"https://huggingface.co/spaces/Heartsync/Novel-NSFW",
|
82 |
"https://huggingface.co/spaces/fantaxy/fantasy-novel",
|
83 |
"https://huggingface.co/spaces/VIDraft/money-radar",
|
|
|
92 |
"https://huggingface.co/spaces/ginigen/multimodal-chat-mbti-korea",
|
93 |
],
|
94 |
"Image": [
|
95 |
+
"https://huggingface.co/spaces/ginigen/Flux-Kontext-FaceLORA",
|
96 |
"https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-REAL",
|
97 |
"https://huggingface.co/spaces/ginigen/FLUX-Ghibli-LoRA2",
|
98 |
"https://huggingface.co/spaces/aiqcamp/REMOVAL-TEXT-IMAGE",
|
|
|
126 |
"LLM / VLM": [
|
127 |
"https://huggingface.co/spaces/fantaxy/fantasy-novel",
|
128 |
"https://huggingface.co/spaces/ginigen/deepseek-r1-0528-API",
|
129 |
+
"https://huggingface.co/spaces/aiqcamp/Mistral-Devstral-API",
|
130 |
"https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528",
|
131 |
"https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528-qwen3-8b",
|
132 |
"https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528",
|
|
|
511 |
</head>
|
512 |
<body>
|
513 |
<header style="text-align: center; padding: 20px; background: linear-gradient(135deg, #f6f8fb, #e2e8f0); border-bottom: 1px solid #ddd;">
|
514 |
+
<h1 style="margin-bottom: 10px;">πAI Playground</h1>
|
515 |
<p>
|
516 |
<a href="https://discord.gg/openfreeai" target="_blank"><img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="badge"></a>
|
517 |
</p>
|
518 |
</header>
|
519 |
<div class="tabs" id="tabs"></div>
|
520 |
<div id="content"></div>
|
521 |
+
|
522 |
<script>
|
523 |
// Basic configuration
|
524 |
const cats = {{cats|tojson}};
|
|
|
526 |
const content = document.getElementById('content');
|
527 |
let active = "";
|
528 |
let currentPage = 1;
|
529 |
+
|
530 |
// Simple utility functions
|
531 |
function loadHTML(url, callback) {
|
532 |
const xhr = new XMLHttpRequest();
|
|
|
538 |
};
|
539 |
xhr.send();
|
540 |
}
|
541 |
+
|
542 |
function makeRequest(url, method, data, callback) {
|
543 |
const xhr = new XMLHttpRequest();
|
544 |
xhr.open(method, url, true);
|
|
|
553 |
xhr.send();
|
554 |
}
|
555 |
}
|
556 |
+
|
557 |
function updateTabs() {
|
558 |
Array.from(tabs.children).forEach(b => {
|
559 |
b.classList.toggle('active', b.dataset.c === active);
|
560 |
});
|
561 |
}
|
562 |
+
|
563 |
// Tab handlers
|
564 |
function loadCategory(cat, page) {
|
565 |
if(cat === active && currentPage === page) return;
|
|
|
604 |
content.innerHTML = html;
|
605 |
});
|
606 |
}
|
607 |
+
|
608 |
function loadFavorites(page) {
|
609 |
if(active === 'Favorites' && currentPage === page) return;
|
610 |
active = 'Favorites';
|
|
|
662 |
content.innerHTML = html;
|
663 |
});
|
664 |
}
|
665 |
+
|
666 |
function loadManage() {
|
667 |
if(active === 'Manage') return;
|
668 |
active = 'Manage';
|
|
|
685 |
|
686 |
loadUrlList();
|
687 |
}
|
688 |
+
|
689 |
// URL management functions
|
690 |
function loadUrlList() {
|
691 |
makeRequest('/api/favorites?per_page=100', 'GET', null, function(data) {
|
|
|
715 |
urlList.innerHTML = html;
|
716 |
});
|
717 |
}
|
718 |
+
|
719 |
function addUrl() {
|
720 |
const url = document.getElementById('new-url').value.trim();
|
721 |
|
|
|
739 |
}
|
740 |
});
|
741 |
}
|
742 |
+
|
743 |
function editUrl(url) {
|
744 |
// Decode URL if it was previously escaped
|
745 |
const decodedUrl = url.replace(/\\'/g, "'");
|
|
|
763 |
}
|
764 |
});
|
765 |
}
|
766 |
+
|
767 |
function deleteUrl(url) {
|
768 |
// Decode URL if it was previously escaped
|
769 |
const decodedUrl = url.replace(/\\'/g, "'");
|
|
|
784 |
}
|
785 |
});
|
786 |
}
|
787 |
+
|
788 |
function showStatus(id, message, success) {
|
789 |
const status = document.getElementById(id);
|
790 |
status.textContent = message;
|
|
|
793 |
status.className = 'status';
|
794 |
}, 3000);
|
795 |
}
|
796 |
+
|
797 |
// Create tabs
|
798 |
// Favorites tab first
|
799 |
const favTab = document.createElement('button');
|
|
|
802 |
favTab.dataset.c = 'Favorites';
|
803 |
favTab.onclick = function() { loadFavorites(1); };
|
804 |
tabs.appendChild(favTab);
|
805 |
+
|
806 |
// Category tabs
|
807 |
cats.forEach(c => {
|
808 |
const b = document.createElement('button');
|
|
|
812 |
b.onclick = function() { loadCategory(c, 1); };
|
813 |
tabs.appendChild(b);
|
814 |
});
|
815 |
+
|
816 |
// Manage tab last
|
817 |
const manageTab = document.createElement('button');
|
818 |
manageTab.className = 'tab manage';
|
|
|
820 |
manageTab.dataset.c = 'Manage';
|
821 |
manageTab.onclick = function() { loadManage(); };
|
822 |
tabs.appendChild(manageTab);
|
823 |
+
|
824 |
// Start with Favorites tab
|
825 |
loadFavorites(1);
|
826 |
</script>
|