Spaces:
Sleeping
Sleeping
github-actions[bot]
commited on
Commit
·
1dda790
1
Parent(s):
d85f622
Deploy from GitHub - 2026-01-21 11:50:26
Browse files- app.py +203 -167
- kernels/__init__.py +24 -4
app.py
CHANGED
|
@@ -126,7 +126,11 @@ def get_device():
|
|
| 126 |
"""
|
| 127 |
global _device_cache
|
| 128 |
if _device_cache is None:
|
| 129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
_device_cache = torch.device('cuda')
|
| 131 |
else:
|
| 132 |
_device_cache = torch.device('cpu')
|
|
@@ -734,7 +738,7 @@ def get_blended_model(style1: str, style2: str, alpha: float, backend: str = 'au
|
|
| 734 |
# Region-based Style Transfer
|
| 735 |
# ============================================================================
|
| 736 |
|
| 737 |
-
def
|
| 738 |
image: Image.Image,
|
| 739 |
mask: Image.Image,
|
| 740 |
style1: str,
|
|
@@ -961,7 +965,7 @@ def get_ai_segmentation_mask(
|
|
| 961 |
# Real Style Extraction Training (VGG-based)
|
| 962 |
# ============================================================================
|
| 963 |
|
| 964 |
-
def
|
| 965 |
style_image: Image.Image,
|
| 966 |
style_name: str,
|
| 967 |
num_iterations: int = 100,
|
|
@@ -1090,7 +1094,7 @@ def train_custom_style(
|
|
| 1090 |
return None, error_msg
|
| 1091 |
|
| 1092 |
|
| 1093 |
-
def
|
| 1094 |
style_image: Image.Image,
|
| 1095 |
content_image: Image.Image,
|
| 1096 |
style_name: str,
|
|
@@ -1556,15 +1560,30 @@ def stylize_image_impl(
|
|
| 1556 |
|
| 1557 |
|
| 1558 |
# Wrap with GPU decorator for ZeroGPU if available
|
| 1559 |
-
# ZeroGPU requires
|
| 1560 |
if SPACES_AVAILABLE:
|
| 1561 |
try:
|
| 1562 |
stylize_image = GPU(stylize_image_impl)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1563 |
except Exception:
|
| 1564 |
# Fallback if GPU decorator fails
|
| 1565 |
stylize_image = stylize_image_impl
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1566 |
else:
|
| 1567 |
stylize_image = stylize_image_impl
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1568 |
|
| 1569 |
|
| 1570 |
def process_webcam_frame(image: Image.Image, style: str, backend: str) -> Image.Image:
|
|
@@ -1614,7 +1633,7 @@ def process_webcam_frame(image: Image.Image, style: str, backend: str) -> Image.
|
|
| 1614 |
return image
|
| 1615 |
|
| 1616 |
|
| 1617 |
-
def
|
| 1618 |
input_image: Image.Image,
|
| 1619 |
mask_type: str,
|
| 1620 |
position: float,
|
|
@@ -1767,7 +1786,7 @@ def run_backend_comparison(style: str) -> str:
|
|
| 1767 |
return output
|
| 1768 |
|
| 1769 |
|
| 1770 |
-
def
|
| 1771 |
input_image: Image.Image,
|
| 1772 |
style1: str,
|
| 1773 |
style2: str,
|
|
@@ -1802,17 +1821,22 @@ def create_style_blend_output(
|
|
| 1802 |
|
| 1803 |
custom_css = """
|
| 1804 |
/* ============================================
|
| 1805 |
-
|
|
|
|
| 1806 |
Gradio 5.x Compatible
|
| 1807 |
============================================ */
|
| 1808 |
|
|
|
|
|
|
|
|
|
|
| 1809 |
/* Animated gradient background */
|
| 1810 |
body {
|
| 1811 |
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
| 1812 |
background-size: 400% 400%;
|
| 1813 |
animation: gradientBG 15s ease infinite;
|
| 1814 |
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
| 1815 |
min-height: 100vh;
|
|
|
|
| 1816 |
}
|
| 1817 |
|
| 1818 |
@keyframes gradientBG {
|
|
@@ -1823,40 +1847,37 @@ body {
|
|
| 1823 |
|
| 1824 |
/* Universal font application */
|
| 1825 |
* {
|
| 1826 |
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
| 1827 |
}
|
| 1828 |
|
| 1829 |
-
/*
|
| 1830 |
-
h1, h2, h3,
|
| 1831 |
-
|
| 1832 |
}
|
| 1833 |
|
| 1834 |
-
/* Main app container -
|
| 1835 |
.gradio-container {
|
| 1836 |
-
|
| 1837 |
-
-
|
| 1838 |
-
|
| 1839 |
-
|
| 1840 |
-
border: 1px solid rgba(255, 255, 255, 0.3);
|
| 1841 |
-
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
|
| 1842 |
max-width: 1400px;
|
| 1843 |
-
margin:
|
| 1844 |
-
padding:
|
| 1845 |
}
|
| 1846 |
|
| 1847 |
-
/* Primary button -
|
| 1848 |
button.primary,
|
| 1849 |
.gr-button-primary,
|
| 1850 |
[class*="primary"] {
|
| 1851 |
-
background:
|
| 1852 |
-
|
| 1853 |
-
|
| 1854 |
-
color: white !important;
|
| 1855 |
font-weight: 600 !important;
|
| 1856 |
-
|
| 1857 |
-
|
| 1858 |
-
|
| 1859 |
-
|
| 1860 |
position: relative;
|
| 1861 |
overflow: hidden;
|
| 1862 |
}
|
|
@@ -1864,71 +1885,80 @@ button.primary,
|
|
| 1864 |
button.primary:hover,
|
| 1865 |
.gr-button-primary:hover,
|
| 1866 |
[class*="primary"]:hover {
|
|
|
|
|
|
|
| 1867 |
transform: translateY(-2px);
|
| 1868 |
-
box-shadow: 0 8px 25px rgba(
|
| 1869 |
}
|
| 1870 |
|
| 1871 |
button.primary:active,
|
| 1872 |
.gr-button-primary:active,
|
| 1873 |
[class*="primary"]:active {
|
| 1874 |
-
transform: translateY(0);
|
| 1875 |
}
|
| 1876 |
|
| 1877 |
-
/* Secondary button -
|
| 1878 |
button.secondary,
|
| 1879 |
.gr-button-secondary,
|
| 1880 |
.download,
|
| 1881 |
[class*="secondary"] {
|
| 1882 |
-
background:
|
| 1883 |
-
|
| 1884 |
-
|
| 1885 |
-
|
| 1886 |
-
|
| 1887 |
-
|
| 1888 |
-
|
| 1889 |
-
font-
|
| 1890 |
}
|
| 1891 |
|
| 1892 |
button.secondary:hover,
|
| 1893 |
.gr-button-secondary:hover,
|
| 1894 |
.download:hover,
|
| 1895 |
[class*="secondary"]:hover {
|
| 1896 |
-
background:
|
| 1897 |
-
|
|
|
|
|
|
|
| 1898 |
}
|
| 1899 |
|
| 1900 |
-
/* All buttons */
|
| 1901 |
button {
|
| 1902 |
-
border-radius:
|
| 1903 |
-
transition: all 0.
|
|
|
|
|
|
|
|
|
|
| 1904 |
}
|
| 1905 |
|
| 1906 |
-
/* Tabs -
|
| 1907 |
.tabs {
|
| 1908 |
-
background:
|
| 1909 |
-
|
| 1910 |
-
|
| 1911 |
-
|
| 1912 |
-
border: 1px solid rgba(255, 255, 255, 0.3) !important;
|
| 1913 |
}
|
| 1914 |
|
| 1915 |
/* Tab buttons */
|
| 1916 |
button.tab-item {
|
| 1917 |
background: transparent !important;
|
| 1918 |
-
border-radius:
|
| 1919 |
-
color: #
|
| 1920 |
-
|
|
|
|
|
|
|
|
|
|
| 1921 |
}
|
| 1922 |
|
| 1923 |
button.tab-item:hover {
|
| 1924 |
-
background: rgba(
|
| 1925 |
}
|
| 1926 |
|
| 1927 |
button.tab-item.selected {
|
| 1928 |
-
background:
|
| 1929 |
-
color: #
|
| 1930 |
-
font-weight:
|
| 1931 |
-
box-shadow: 0 2px
|
| 1932 |
}
|
| 1933 |
|
| 1934 |
/* Input boxes and text areas */
|
|
@@ -1936,99 +1966,106 @@ input[type="text"],
|
|
| 1936 |
input[type="number"],
|
| 1937 |
textarea,
|
| 1938 |
select {
|
| 1939 |
-
background:
|
| 1940 |
-
|
| 1941 |
-
border:
|
| 1942 |
-
|
| 1943 |
-
|
| 1944 |
}
|
| 1945 |
|
| 1946 |
input[type="text"]:focus,
|
| 1947 |
input[type="number"]:focus,
|
| 1948 |
textarea:focus,
|
| 1949 |
select:focus {
|
| 1950 |
-
background:
|
| 1951 |
-
border-color: #
|
| 1952 |
-
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1) !important;
|
| 1953 |
outline: none !important;
|
|
|
|
| 1954 |
}
|
| 1955 |
|
| 1956 |
-
/* Image containers -
|
| 1957 |
.image-container,
|
| 1958 |
[class*="image"] {
|
| 1959 |
-
border-radius:
|
| 1960 |
-
border: 1px solid
|
| 1961 |
overflow: hidden !important;
|
| 1962 |
-
background:
|
| 1963 |
}
|
| 1964 |
|
| 1965 |
-
/* Slider styling */
|
| 1966 |
input[type="range"] {
|
| 1967 |
-webkit-appearance: none;
|
| 1968 |
-
background:
|
| 1969 |
-
|
| 1970 |
-
|
| 1971 |
-
|
| 1972 |
-
border: 1px solid rgba(255, 255, 255, 0.3);
|
| 1973 |
}
|
| 1974 |
|
| 1975 |
input[type="range"]::-webkit-slider-thumb {
|
| 1976 |
-webkit-appearance: none;
|
| 1977 |
-
width:
|
| 1978 |
-
height:
|
| 1979 |
-
background:
|
| 1980 |
-
border: 3px solid
|
| 1981 |
border-radius: 50%;
|
| 1982 |
cursor: pointer;
|
| 1983 |
-
box-shadow: 0 2px
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1984 |
}
|
| 1985 |
|
| 1986 |
input[type="range"]::-moz-range-thumb {
|
| 1987 |
-
width:
|
| 1988 |
-
height:
|
| 1989 |
-
background:
|
| 1990 |
-
border: 3px solid
|
| 1991 |
border-radius: 50%;
|
| 1992 |
cursor: pointer;
|
| 1993 |
-
box-shadow: 0 2px
|
|
|
|
| 1994 |
}
|
| 1995 |
|
| 1996 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1997 |
input[type="checkbox"],
|
| 1998 |
input[type="radio"] {
|
| 1999 |
-
accent-color: #
|
| 2000 |
-
width:
|
| 2001 |
-
height:
|
| 2002 |
}
|
| 2003 |
|
| 2004 |
-
/* Badge styles */
|
| 2005 |
.live-badge {
|
| 2006 |
display: inline-block;
|
| 2007 |
-
padding:
|
| 2008 |
-
background:
|
| 2009 |
-
backdrop-filter: blur(10px);
|
| 2010 |
color: #92400E;
|
| 2011 |
-
border-radius:
|
| 2012 |
-
font-size:
|
| 2013 |
-
font-weight:
|
| 2014 |
-
border: 1px solid
|
| 2015 |
}
|
| 2016 |
|
| 2017 |
.backend-badge {
|
| 2018 |
display: inline-block;
|
| 2019 |
-
padding:
|
| 2020 |
-
background:
|
| 2021 |
-
backdrop-filter: blur(10px);
|
| 2022 |
color: #065F46;
|
| 2023 |
-
border-radius:
|
| 2024 |
-
font-size:
|
| 2025 |
-
font-weight:
|
| 2026 |
-
border: 1px solid
|
| 2027 |
}
|
| 2028 |
|
| 2029 |
/* Markdown content */
|
| 2030 |
.markdown {
|
| 2031 |
-
color: #
|
| 2032 |
}
|
| 2033 |
|
| 2034 |
/* Text visibility fixes */
|
|
@@ -2043,7 +2080,7 @@ input[type="radio"] {
|
|
| 2043 |
.gradio-container p,
|
| 2044 |
.gradio-container span,
|
| 2045 |
.gradio-container label {
|
| 2046 |
-
color: #
|
| 2047 |
}
|
| 2048 |
|
| 2049 |
/* Button text colors */
|
|
@@ -2056,14 +2093,22 @@ button,
|
|
| 2056 |
input,
|
| 2057 |
textarea,
|
| 2058 |
select {
|
| 2059 |
-
color: #
|
| 2060 |
}
|
| 2061 |
|
| 2062 |
-
/* Label colors */
|
| 2063 |
label,
|
| 2064 |
[class*="label"] {
|
| 2065 |
-
color: #
|
| 2066 |
-
font-weight:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2067 |
}
|
| 2068 |
|
| 2069 |
/* Gradio 5.x specific text elements */
|
|
@@ -2075,79 +2120,76 @@ label,
|
|
| 2075 |
.group,
|
| 2076 |
.row,
|
| 2077 |
.column {
|
| 2078 |
-
background:
|
| 2079 |
-
border-radius:
|
| 2080 |
-
padding:
|
| 2081 |
}
|
| 2082 |
|
| 2083 |
-
/* Accordion */
|
| 2084 |
.details {
|
| 2085 |
-
background:
|
| 2086 |
-
|
| 2087 |
-
border
|
| 2088 |
-
border: 1px solid rgba(255, 255, 255, 0.3) !important;
|
| 2089 |
}
|
| 2090 |
|
| 2091 |
-
/* Scrollbar -
|
| 2092 |
::-webkit-scrollbar {
|
| 2093 |
-
width:
|
| 2094 |
-
height:
|
| 2095 |
}
|
| 2096 |
|
| 2097 |
::-webkit-scrollbar-track {
|
| 2098 |
-
background:
|
| 2099 |
-
border-radius: 8px;
|
| 2100 |
}
|
| 2101 |
|
| 2102 |
::-webkit-scrollbar-thumb {
|
| 2103 |
-
background:
|
| 2104 |
-
border-radius:
|
| 2105 |
-
border: 2px solid rgba(255, 255, 255, 0.3);
|
| 2106 |
}
|
| 2107 |
|
| 2108 |
::-webkit-scrollbar-thumb:hover {
|
| 2109 |
-
background:
|
| 2110 |
}
|
| 2111 |
|
| 2112 |
-
/* Progress bar */
|
| 2113 |
progress {
|
| 2114 |
-
background:
|
| 2115 |
-
border-radius:
|
| 2116 |
-
height:
|
| 2117 |
}
|
| 2118 |
|
| 2119 |
progress::-webkit-progress-bar {
|
| 2120 |
-
background:
|
| 2121 |
-
border-radius:
|
| 2122 |
}
|
| 2123 |
|
| 2124 |
progress::-webkit-progress-value {
|
| 2125 |
-
background:
|
| 2126 |
-
border-radius:
|
| 2127 |
}
|
| 2128 |
|
| 2129 |
/* Mobile responsive */
|
| 2130 |
@media (max-width: 768px) {
|
| 2131 |
.gradio-container {
|
| 2132 |
-
margin:
|
| 2133 |
-
padding:
|
| 2134 |
-
border-radius:
|
| 2135 |
}
|
| 2136 |
|
| 2137 |
button.primary,
|
| 2138 |
.gr-button-primary,
|
| 2139 |
[class*="primary"] {
|
| 2140 |
-
padding:
|
| 2141 |
font-size: 14px !important;
|
| 2142 |
}
|
| 2143 |
}
|
| 2144 |
|
| 2145 |
-
/* Loading spinner */
|
| 2146 |
.spinner {
|
| 2147 |
-
border:
|
| 2148 |
-
border-top:
|
| 2149 |
border-radius: 50%;
|
| 2150 |
-
animation: spin
|
| 2151 |
}
|
| 2152 |
|
| 2153 |
@keyframes spin {
|
|
@@ -2159,19 +2201,18 @@ progress::-webkit-progress-value {
|
|
| 2159 |
.gradio-button.primary,
|
| 2160 |
button[class*="Primary"],
|
| 2161 |
[type="button"].primary {
|
| 2162 |
-
background:
|
| 2163 |
-
border: 1px solid
|
| 2164 |
-
color:
|
| 2165 |
-
font-weight:
|
| 2166 |
-
border-radius:
|
| 2167 |
-
box-shadow: 0 4px 15px rgba(99, 102, 241, 0.25) !important;
|
| 2168 |
}
|
| 2169 |
|
| 2170 |
/* Block containers */
|
| 2171 |
.block {
|
| 2172 |
-
background:
|
| 2173 |
-
border-radius:
|
| 2174 |
-
padding:
|
| 2175 |
}
|
| 2176 |
|
| 2177 |
/* Form elements */
|
|
@@ -2183,29 +2224,24 @@ button[class*="Primary"],
|
|
| 2183 |
|
| 2184 |
with gr.Blocks(
|
| 2185 |
title="StyleForge: Neural Style Transfer",
|
| 2186 |
-
theme=gr.themes.
|
| 2187 |
-
primary_hue="indigo",
|
| 2188 |
-
secondary_hue="purple",
|
| 2189 |
font=gr.themes.GoogleFont("Inter"),
|
| 2190 |
-
radius_size="
|
| 2191 |
),
|
| 2192 |
css=custom_css,
|
| 2193 |
) as demo:
|
| 2194 |
|
| 2195 |
-
# Header with
|
| 2196 |
cuda_badge = f"<span class='backend-badge'>CUDA Accelerated</span>" if CUDA_KERNELS_AVAILABLE else ""
|
| 2197 |
gr.Markdown(f"""
|
| 2198 |
-
<div style="text-align: center; padding:
|
| 2199 |
-
<h1 style="font-size:
|
| 2200 |
StyleForge
|
| 2201 |
</h1>
|
| 2202 |
-
<p style="color: #
|
| 2203 |
Neural Style Transfer with Custom CUDA Kernels
|
| 2204 |
</p>
|
| 2205 |
{cuda_badge}
|
| 2206 |
-
<p style="color: #9CA3AF; margin-top: 1rem; font-size: 0.9rem;">
|
| 2207 |
-
Custom Styles • Region Transfer • Style Blending • Real-time Processing
|
| 2208 |
-
</p>
|
| 2209 |
</div>
|
| 2210 |
""")
|
| 2211 |
|
|
|
|
| 126 |
"""
|
| 127 |
global _device_cache
|
| 128 |
if _device_cache is None:
|
| 129 |
+
# On ZeroGPU, always assume CUDA will be available in GPU task
|
| 130 |
+
# Don't call torch.cuda.is_available() at module level
|
| 131 |
+
if _SPACES_ZERO_GPU:
|
| 132 |
+
_device_cache = torch.device('cuda') # Will be resolved in GPU task
|
| 133 |
+
elif torch.cuda.is_available():
|
| 134 |
_device_cache = torch.device('cuda')
|
| 135 |
else:
|
| 136 |
_device_cache = torch.device('cpu')
|
|
|
|
| 738 |
# Region-based Style Transfer
|
| 739 |
# ============================================================================
|
| 740 |
|
| 741 |
+
def apply_region_style_impl(
|
| 742 |
image: Image.Image,
|
| 743 |
mask: Image.Image,
|
| 744 |
style1: str,
|
|
|
|
| 965 |
# Real Style Extraction Training (VGG-based)
|
| 966 |
# ============================================================================
|
| 967 |
|
| 968 |
+
def train_custom_style_impl(
|
| 969 |
style_image: Image.Image,
|
| 970 |
style_name: str,
|
| 971 |
num_iterations: int = 100,
|
|
|
|
| 1094 |
return None, error_msg
|
| 1095 |
|
| 1096 |
|
| 1097 |
+
def extract_style_from_image_impl(
|
| 1098 |
style_image: Image.Image,
|
| 1099 |
content_image: Image.Image,
|
| 1100 |
style_name: str,
|
|
|
|
| 1560 |
|
| 1561 |
|
| 1562 |
# Wrap with GPU decorator for ZeroGPU if available
|
| 1563 |
+
# ZeroGPU requires ALL GPU-using functions to be decorated with @GPU
|
| 1564 |
if SPACES_AVAILABLE:
|
| 1565 |
try:
|
| 1566 |
stylize_image = GPU(stylize_image_impl)
|
| 1567 |
+
train_custom_style = GPU(train_custom_style_impl)
|
| 1568 |
+
extract_style_from_image = GPU(extract_style_from_image_impl)
|
| 1569 |
+
create_style_blend_output = GPU(create_style_blend_output_impl)
|
| 1570 |
+
apply_region_style = GPU(apply_region_style_impl)
|
| 1571 |
+
apply_region_style_ui = GPU(apply_region_style_ui_impl)
|
| 1572 |
except Exception:
|
| 1573 |
# Fallback if GPU decorator fails
|
| 1574 |
stylize_image = stylize_image_impl
|
| 1575 |
+
train_custom_style = train_custom_style_impl
|
| 1576 |
+
extract_style_from_image = extract_style_from_image_impl
|
| 1577 |
+
create_style_blend_output = create_style_blend_output_impl
|
| 1578 |
+
apply_region_style = apply_region_style_impl
|
| 1579 |
+
apply_region_style_ui = apply_region_style_ui_impl
|
| 1580 |
else:
|
| 1581 |
stylize_image = stylize_image_impl
|
| 1582 |
+
train_custom_style = train_custom_style_impl
|
| 1583 |
+
extract_style_from_image = extract_style_from_image_impl
|
| 1584 |
+
create_style_blend_output = create_style_blend_output_impl
|
| 1585 |
+
apply_region_style = apply_region_style_impl
|
| 1586 |
+
apply_region_style_ui = apply_region_style_ui_impl
|
| 1587 |
|
| 1588 |
|
| 1589 |
def process_webcam_frame(image: Image.Image, style: str, backend: str) -> Image.Image:
|
|
|
|
| 1633 |
return image
|
| 1634 |
|
| 1635 |
|
| 1636 |
+
def apply_region_style_ui_impl(
|
| 1637 |
input_image: Image.Image,
|
| 1638 |
mask_type: str,
|
| 1639 |
position: float,
|
|
|
|
| 1786 |
return output
|
| 1787 |
|
| 1788 |
|
| 1789 |
+
def create_style_blend_output_impl(
|
| 1790 |
input_image: Image.Image,
|
| 1791 |
style1: str,
|
| 1792 |
style2: str,
|
|
|
|
| 1821 |
|
| 1822 |
custom_css = """
|
| 1823 |
/* ============================================
|
| 1824 |
+
FLOWLINE-INSPIRED MINIMAL THEME
|
| 1825 |
+
Clean, modern, refined
|
| 1826 |
Gradio 5.x Compatible
|
| 1827 |
============================================ */
|
| 1828 |
|
| 1829 |
+
/* Import fonts - Inter for UI, plus a distinctive display font */
|
| 1830 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap');
|
| 1831 |
+
|
| 1832 |
/* Animated gradient background */
|
| 1833 |
body {
|
| 1834 |
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
| 1835 |
background-size: 400% 400%;
|
| 1836 |
animation: gradientBG 15s ease infinite;
|
| 1837 |
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
| 1838 |
min-height: 100vh;
|
| 1839 |
+
color: #09090B;
|
| 1840 |
}
|
| 1841 |
|
| 1842 |
@keyframes gradientBG {
|
|
|
|
| 1847 |
|
| 1848 |
/* Universal font application */
|
| 1849 |
* {
|
| 1850 |
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
| 1851 |
}
|
| 1852 |
|
| 1853 |
+
/* Headings use Space Grotesk for distinctive look */
|
| 1854 |
+
h1, h2, h3, .gradio-container h1, .gradio-container h2, .gradio-container h3 {
|
| 1855 |
+
font-family: 'Space Grotesk', sans-serif !important;
|
| 1856 |
}
|
| 1857 |
|
| 1858 |
+
/* Main app container - clean, minimal */
|
| 1859 |
.gradio-container {
|
| 1860 |
+
background: #FFFFFF !important;
|
| 1861 |
+
border-radius: 12px;
|
| 1862 |
+
border: 1px solid #E4E4E7;
|
| 1863 |
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
|
|
|
|
|
|
| 1864 |
max-width: 1400px;
|
| 1865 |
+
margin: 24px auto;
|
| 1866 |
+
padding: 32px !important;
|
| 1867 |
}
|
| 1868 |
|
| 1869 |
+
/* Primary button - bigger with smooth hover animation */
|
| 1870 |
button.primary,
|
| 1871 |
.gr-button-primary,
|
| 1872 |
[class*="primary"] {
|
| 1873 |
+
background: #18181B !important;
|
| 1874 |
+
border: 1px solid #18181B !important;
|
| 1875 |
+
color: #FAFAFA !important;
|
|
|
|
| 1876 |
font-weight: 600 !important;
|
| 1877 |
+
font-size: 16px !important;
|
| 1878 |
+
border-radius: 12px !important;
|
| 1879 |
+
padding: 14px 28px !important;
|
| 1880 |
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
| 1881 |
position: relative;
|
| 1882 |
overflow: hidden;
|
| 1883 |
}
|
|
|
|
| 1885 |
button.primary:hover,
|
| 1886 |
.gr-button-primary:hover,
|
| 1887 |
[class*="primary"]:hover {
|
| 1888 |
+
background: #000000 !important;
|
| 1889 |
+
border-color: #000000 !important;
|
| 1890 |
transform: translateY(-2px);
|
| 1891 |
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15) !important;
|
| 1892 |
}
|
| 1893 |
|
| 1894 |
button.primary:active,
|
| 1895 |
.gr-button-primary:active,
|
| 1896 |
[class*="primary"]:active {
|
| 1897 |
+
transform: translateY(0) scale(0.98);
|
| 1898 |
}
|
| 1899 |
|
| 1900 |
+
/* Secondary button - bigger with hover animation */
|
| 1901 |
button.secondary,
|
| 1902 |
.gr-button-secondary,
|
| 1903 |
.download,
|
| 1904 |
[class*="secondary"] {
|
| 1905 |
+
background: #FFFFFF !important;
|
| 1906 |
+
border: 1px solid #E4E4E7 !important;
|
| 1907 |
+
color: #18181B !important;
|
| 1908 |
+
border-radius: 12px !important;
|
| 1909 |
+
padding: 13px 24px !important;
|
| 1910 |
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
| 1911 |
+
font-weight: 600 !important;
|
| 1912 |
+
font-size: 15px !important;
|
| 1913 |
}
|
| 1914 |
|
| 1915 |
button.secondary:hover,
|
| 1916 |
.gr-button-secondary:hover,
|
| 1917 |
.download:hover,
|
| 1918 |
[class*="secondary"]:hover {
|
| 1919 |
+
background: #FAFAFA !important;
|
| 1920 |
+
border-color: #18181B !important;
|
| 1921 |
+
transform: translateY(-1px);
|
| 1922 |
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08) !important;
|
| 1923 |
}
|
| 1924 |
|
| 1925 |
+
/* All buttons - bigger base size */
|
| 1926 |
button {
|
| 1927 |
+
border-radius: 10px !important;
|
| 1928 |
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
| 1929 |
+
font-size: 15px !important;
|
| 1930 |
+
font-weight: 600 !important;
|
| 1931 |
+
padding: 12px 20px !important;
|
| 1932 |
}
|
| 1933 |
|
| 1934 |
+
/* Tabs - clean style */
|
| 1935 |
.tabs {
|
| 1936 |
+
background: #FAFAFA !important;
|
| 1937 |
+
border-radius: 8px !important;
|
| 1938 |
+
padding: 4px !important;
|
| 1939 |
+
border: 1px solid #E4E4E7 !important;
|
|
|
|
| 1940 |
}
|
| 1941 |
|
| 1942 |
/* Tab buttons */
|
| 1943 |
button.tab-item {
|
| 1944 |
background: transparent !important;
|
| 1945 |
+
border-radius: 6px !important;
|
| 1946 |
+
color: #71717A !important;
|
| 1947 |
+
font-size: 14px !important;
|
| 1948 |
+
font-weight: 500 !important;
|
| 1949 |
+
transition: all 0.15s ease !important;
|
| 1950 |
+
padding: 8px 14px !important;
|
| 1951 |
}
|
| 1952 |
|
| 1953 |
button.tab-item:hover {
|
| 1954 |
+
background: rgba(0, 0, 0, 0.04) !important;
|
| 1955 |
}
|
| 1956 |
|
| 1957 |
button.tab-item.selected {
|
| 1958 |
+
background: #FFFFFF !important;
|
| 1959 |
+
color: #18181B !important;
|
| 1960 |
+
font-weight: 500 !important;
|
| 1961 |
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) !important;
|
| 1962 |
}
|
| 1963 |
|
| 1964 |
/* Input boxes and text areas */
|
|
|
|
| 1966 |
input[type="number"],
|
| 1967 |
textarea,
|
| 1968 |
select {
|
| 1969 |
+
background: #FFFFFF !important;
|
| 1970 |
+
border: 1px solid #E4E4E7 !important;
|
| 1971 |
+
border-radius: 8px !important;
|
| 1972 |
+
transition: all 0.15s ease !important;
|
| 1973 |
+
font-size: 14px !important;
|
| 1974 |
}
|
| 1975 |
|
| 1976 |
input[type="text"]:focus,
|
| 1977 |
input[type="number"]:focus,
|
| 1978 |
textarea:focus,
|
| 1979 |
select:focus {
|
| 1980 |
+
background: #FFFFFF !important;
|
| 1981 |
+
border-color: #18181B !important;
|
|
|
|
| 1982 |
outline: none !important;
|
| 1983 |
+
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.05) !important;
|
| 1984 |
}
|
| 1985 |
|
| 1986 |
+
/* Image containers - clean border */
|
| 1987 |
.image-container,
|
| 1988 |
[class*="image"] {
|
| 1989 |
+
border-radius: 8px !important;
|
| 1990 |
+
border: 1px solid #E4E4E7 !important;
|
| 1991 |
overflow: hidden !important;
|
| 1992 |
+
background: #FAFAFA !important;
|
| 1993 |
}
|
| 1994 |
|
| 1995 |
+
/* Slider styling - bigger */
|
| 1996 |
input[type="range"] {
|
| 1997 |
-webkit-appearance: none;
|
| 1998 |
+
background: #E4E4E7;
|
| 1999 |
+
border-radius: 4px;
|
| 2000 |
+
height: 6px;
|
| 2001 |
+
border: none;
|
|
|
|
| 2002 |
}
|
| 2003 |
|
| 2004 |
input[type="range"]::-webkit-slider-thumb {
|
| 2005 |
-webkit-appearance: none;
|
| 2006 |
+
width: 20px;
|
| 2007 |
+
height: 20px;
|
| 2008 |
+
background: #18181B;
|
| 2009 |
+
border: 3px solid #FFFFFF;
|
| 2010 |
border-radius: 50%;
|
| 2011 |
cursor: pointer;
|
| 2012 |
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
| 2013 |
+
transition: transform 0.2s ease;
|
| 2014 |
+
}
|
| 2015 |
+
|
| 2016 |
+
input[type="range"]::-webkit-slider-thumb:hover {
|
| 2017 |
+
transform: scale(1.1);
|
| 2018 |
}
|
| 2019 |
|
| 2020 |
input[type="range"]::-moz-range-thumb {
|
| 2021 |
+
width: 20px;
|
| 2022 |
+
height: 20px;
|
| 2023 |
+
background: #18181B;
|
| 2024 |
+
border: 3px solid #FFFFFF;
|
| 2025 |
border-radius: 50%;
|
| 2026 |
cursor: pointer;
|
| 2027 |
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
| 2028 |
+
transition: transform 0.2s ease;
|
| 2029 |
}
|
| 2030 |
|
| 2031 |
+
input[type="range"]::-moz-range-thumb:hover {
|
| 2032 |
+
transform: scale(1.1);
|
| 2033 |
+
}
|
| 2034 |
+
|
| 2035 |
+
/* Checkbox and radio styling - bigger */
|
| 2036 |
input[type="checkbox"],
|
| 2037 |
input[type="radio"] {
|
| 2038 |
+
accent-color: #18181B !important;
|
| 2039 |
+
width: 20px !important;
|
| 2040 |
+
height: 20px !important;
|
| 2041 |
}
|
| 2042 |
|
| 2043 |
+
/* Badge styles - clean, minimal */
|
| 2044 |
.live-badge {
|
| 2045 |
display: inline-block;
|
| 2046 |
+
padding: 4px 12px;
|
| 2047 |
+
background: #FEF3C7;
|
|
|
|
| 2048 |
color: #92400E;
|
| 2049 |
+
border-radius: 6px;
|
| 2050 |
+
font-size: 12px;
|
| 2051 |
+
font-weight: 500;
|
| 2052 |
+
border: 1px solid #FDE68A;
|
| 2053 |
}
|
| 2054 |
|
| 2055 |
.backend-badge {
|
| 2056 |
display: inline-block;
|
| 2057 |
+
padding: 4px 12px;
|
| 2058 |
+
background: #D1FAE5;
|
|
|
|
| 2059 |
color: #065F46;
|
| 2060 |
+
border-radius: 6px;
|
| 2061 |
+
font-size: 12px;
|
| 2062 |
+
font-weight: 500;
|
| 2063 |
+
border: 1px solid #A7F3D0;
|
| 2064 |
}
|
| 2065 |
|
| 2066 |
/* Markdown content */
|
| 2067 |
.markdown {
|
| 2068 |
+
color: #27272A !important;
|
| 2069 |
}
|
| 2070 |
|
| 2071 |
/* Text visibility fixes */
|
|
|
|
| 2080 |
.gradio-container p,
|
| 2081 |
.gradio-container span,
|
| 2082 |
.gradio-container label {
|
| 2083 |
+
color: #27272A !important;
|
| 2084 |
}
|
| 2085 |
|
| 2086 |
/* Button text colors */
|
|
|
|
| 2093 |
input,
|
| 2094 |
textarea,
|
| 2095 |
select {
|
| 2096 |
+
color: #27272A !important;
|
| 2097 |
}
|
| 2098 |
|
| 2099 |
+
/* Label colors - bigger text */
|
| 2100 |
label,
|
| 2101 |
[class*="label"] {
|
| 2102 |
+
color: #27272A !important;
|
| 2103 |
+
font-weight: 600 !important;
|
| 2104 |
+
font-size: 15px !important;
|
| 2105 |
+
}
|
| 2106 |
+
|
| 2107 |
+
/* General text size increase */
|
| 2108 |
+
.gradio-container p,
|
| 2109 |
+
.gradio-container span,
|
| 2110 |
+
.gradio-container div {
|
| 2111 |
+
font-size: 15px !important;
|
| 2112 |
}
|
| 2113 |
|
| 2114 |
/* Gradio 5.x specific text elements */
|
|
|
|
| 2120 |
.group,
|
| 2121 |
.row,
|
| 2122 |
.column {
|
| 2123 |
+
background: transparent !important;
|
| 2124 |
+
border-radius: 0 !important;
|
| 2125 |
+
padding: 0 !important;
|
| 2126 |
}
|
| 2127 |
|
| 2128 |
+
/* Accordion - clean */
|
| 2129 |
.details {
|
| 2130 |
+
background: #FAFAFA !important;
|
| 2131 |
+
border-radius: 8px !important;
|
| 2132 |
+
border: 1px solid #E4E4E7 !important;
|
|
|
|
| 2133 |
}
|
| 2134 |
|
| 2135 |
+
/* Scrollbar - minimal */
|
| 2136 |
::-webkit-scrollbar {
|
| 2137 |
+
width: 8px;
|
| 2138 |
+
height: 8px;
|
| 2139 |
}
|
| 2140 |
|
| 2141 |
::-webkit-scrollbar-track {
|
| 2142 |
+
background: transparent;
|
|
|
|
| 2143 |
}
|
| 2144 |
|
| 2145 |
::-webkit-scrollbar-thumb {
|
| 2146 |
+
background: #D4D4D8;
|
| 2147 |
+
border-radius: 3px;
|
|
|
|
| 2148 |
}
|
| 2149 |
|
| 2150 |
::-webkit-scrollbar-thumb:hover {
|
| 2151 |
+
background: #A1A1AA;
|
| 2152 |
}
|
| 2153 |
|
| 2154 |
+
/* Progress bar - minimal */
|
| 2155 |
progress {
|
| 2156 |
+
background: #E4E4E7 !important;
|
| 2157 |
+
border-radius: 4px !important;
|
| 2158 |
+
height: 4px !important;
|
| 2159 |
}
|
| 2160 |
|
| 2161 |
progress::-webkit-progress-bar {
|
| 2162 |
+
background: #E4E4E7;
|
| 2163 |
+
border-radius: 4px;
|
| 2164 |
}
|
| 2165 |
|
| 2166 |
progress::-webkit-progress-value {
|
| 2167 |
+
background: #18181B !important;
|
| 2168 |
+
border-radius: 4px;
|
| 2169 |
}
|
| 2170 |
|
| 2171 |
/* Mobile responsive */
|
| 2172 |
@media (max-width: 768px) {
|
| 2173 |
.gradio-container {
|
| 2174 |
+
margin: 12px !important;
|
| 2175 |
+
padding: 20px !important;
|
| 2176 |
+
border-radius: 12px !important;
|
| 2177 |
}
|
| 2178 |
|
| 2179 |
button.primary,
|
| 2180 |
.gr-button-primary,
|
| 2181 |
[class*="primary"] {
|
| 2182 |
+
padding: 9px 16px !important;
|
| 2183 |
font-size: 14px !important;
|
| 2184 |
}
|
| 2185 |
}
|
| 2186 |
|
| 2187 |
+
/* Loading spinner - minimal */
|
| 2188 |
.spinner {
|
| 2189 |
+
border: 2px solid #E4E4E7;
|
| 2190 |
+
border-top: 2px solid #18181B;
|
| 2191 |
border-radius: 50%;
|
| 2192 |
+
animation: spin 0.8s linear infinite;
|
| 2193 |
}
|
| 2194 |
|
| 2195 |
@keyframes spin {
|
|
|
|
| 2201 |
.gradio-button.primary,
|
| 2202 |
button[class*="Primary"],
|
| 2203 |
[type="button"].primary {
|
| 2204 |
+
background: #18181B !important;
|
| 2205 |
+
border: 1px solid #18181B !important;
|
| 2206 |
+
color: #FAFAFA !important;
|
| 2207 |
+
font-weight: 500 !important;
|
| 2208 |
+
border-radius: 8px !important;
|
|
|
|
| 2209 |
}
|
| 2210 |
|
| 2211 |
/* Block containers */
|
| 2212 |
.block {
|
| 2213 |
+
background: transparent !important;
|
| 2214 |
+
border-radius: 0 !important;
|
| 2215 |
+
padding: 0 !important;
|
| 2216 |
}
|
| 2217 |
|
| 2218 |
/* Form elements */
|
|
|
|
| 2224 |
|
| 2225 |
with gr.Blocks(
|
| 2226 |
title="StyleForge: Neural Style Transfer",
|
| 2227 |
+
theme=gr.themes.Base(
|
|
|
|
|
|
|
| 2228 |
font=gr.themes.GoogleFont("Inter"),
|
| 2229 |
+
radius_size="sm",
|
| 2230 |
),
|
| 2231 |
css=custom_css,
|
| 2232 |
) as demo:
|
| 2233 |
|
| 2234 |
+
# Header - bigger text with Space Grotesk font
|
| 2235 |
cuda_badge = f"<span class='backend-badge'>CUDA Accelerated</span>" if CUDA_KERNELS_AVAILABLE else ""
|
| 2236 |
gr.Markdown(f"""
|
| 2237 |
+
<div style="text-align: center; padding: 2.5rem 0 2rem 0;">
|
| 2238 |
+
<h1 style="font-size: 3.5rem; margin-bottom: 0.5rem; color: #18181B; font-weight: 700; letter-spacing: -0.03em; font-family: 'Space Grotesk', sans-serif;">
|
| 2239 |
StyleForge
|
| 2240 |
</h1>
|
| 2241 |
+
<p style="color: #71717A; font-size: 1.15rem; margin-bottom: 1rem; font-weight: 400; letter-spacing: -0.01em;">
|
| 2242 |
Neural Style Transfer with Custom CUDA Kernels
|
| 2243 |
</p>
|
| 2244 |
{cuda_badge}
|
|
|
|
|
|
|
|
|
|
| 2245 |
</div>
|
| 2246 |
""")
|
| 2247 |
|
kernels/__init__.py
CHANGED
|
@@ -122,9 +122,19 @@ def load_prebuilt_kernels():
|
|
| 122 |
kernel_files += list(_PREBUILT_PATH.glob("*.so")) + list(_PREBUILT_PATH.glob("*.pyd"))
|
| 123 |
|
| 124 |
# Try downloading from dataset if not found locally (on ZeroGPU or if CUDA available)
|
|
|
|
| 125 |
if not kernel_files:
|
| 126 |
print(f"No local pre-compiled kernels found. _ZERO_GPU={_ZERO_GPU}")
|
| 127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
print("Trying HuggingFace dataset...")
|
| 129 |
if _download_kernels_from_dataset():
|
| 130 |
# Check again after download - look in kernels directory
|
|
@@ -229,7 +239,12 @@ def compile_kernels():
|
|
| 229 |
print("Using pre-compiled CUDA kernels!")
|
| 230 |
return True
|
| 231 |
|
| 232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
_KERNELS_COMPILED = True
|
| 234 |
return False
|
| 235 |
|
|
@@ -256,8 +271,13 @@ if _ZERO_GPU:
|
|
| 256 |
else:
|
| 257 |
print("No pre-compiled kernels available, using PyTorch GPU fallback")
|
| 258 |
_KERNELS_COMPILED = True
|
| 259 |
-
elif
|
| 260 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
|
| 262 |
|
| 263 |
__all__ = [
|
|
|
|
| 122 |
kernel_files += list(_PREBUILT_PATH.glob("*.so")) + list(_PREBUILT_PATH.glob("*.pyd"))
|
| 123 |
|
| 124 |
# Try downloading from dataset if not found locally (on ZeroGPU or if CUDA available)
|
| 125 |
+
# IMPORTANT: Don't call torch.cuda.is_available() on ZeroGPU at module level!
|
| 126 |
if not kernel_files:
|
| 127 |
print(f"No local pre-compiled kernels found. _ZERO_GPU={_ZERO_GPU}")
|
| 128 |
+
# On ZeroGPU, always try to download without checking CUDA
|
| 129 |
+
# On local, check CUDA first before downloading
|
| 130 |
+
should_download = _ZERO_GPU
|
| 131 |
+
if not _ZERO_GPU:
|
| 132 |
+
try:
|
| 133 |
+
should_download = torch.cuda.is_available()
|
| 134 |
+
except:
|
| 135 |
+
should_download = False
|
| 136 |
+
|
| 137 |
+
if should_download:
|
| 138 |
print("Trying HuggingFace dataset...")
|
| 139 |
if _download_kernels_from_dataset():
|
| 140 |
# Check again after download - look in kernels directory
|
|
|
|
| 239 |
print("Using pre-compiled CUDA kernels!")
|
| 240 |
return True
|
| 241 |
|
| 242 |
+
# Check CUDA availability (safe here since we're not on ZeroGPU)
|
| 243 |
+
try:
|
| 244 |
+
if not torch.cuda.is_available():
|
| 245 |
+
_KERNELS_COMPILED = True
|
| 246 |
+
return False
|
| 247 |
+
except:
|
| 248 |
_KERNELS_COMPILED = True
|
| 249 |
return False
|
| 250 |
|
|
|
|
| 271 |
else:
|
| 272 |
print("No pre-compiled kernels available, using PyTorch GPU fallback")
|
| 273 |
_KERNELS_COMPILED = True
|
| 274 |
+
elif not _ZERO_GPU:
|
| 275 |
+
# On local, check if CUDA is available and compile
|
| 276 |
+
try:
|
| 277 |
+
if torch.cuda.is_available():
|
| 278 |
+
compile_kernels()
|
| 279 |
+
except:
|
| 280 |
+
_KERNELS_COMPILED = True
|
| 281 |
|
| 282 |
|
| 283 |
__all__ = [
|