page.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. 'use client';
  2. import { useEffect, useState } from 'react';
  3. import Link from 'next/link';
  4. import { Header } from '@/components/header';
  5. import { AppLayout } from '@/components/layout';
  6. import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
  7. import { Button } from '@/components/ui/button';
  8. import { apiClient } from '@/lib/api';
  9. import { ImagePlus, Image, Sparkles, Settings, Activity, ArrowRight, CheckCircle2, XCircle } from 'lucide-react';
  10. const features = [
  11. {
  12. title: 'Text to Image',
  13. description: 'Generate stunning images from text descriptions using Stable Diffusion',
  14. icon: ImagePlus,
  15. href: '/text2img',
  16. color: 'text-blue-500',
  17. },
  18. {
  19. title: 'Image to Image',
  20. description: 'Transform existing images with AI-powered modifications',
  21. icon: Image,
  22. href: '/img2img',
  23. color: 'text-purple-500',
  24. },
  25. {
  26. title: 'Upscaler',
  27. description: 'Enhance and upscale your images for higher quality results',
  28. icon: Sparkles,
  29. href: '/upscaler',
  30. color: 'text-green-500',
  31. },
  32. {
  33. title: 'Model Management',
  34. description: 'Load, unload, and manage your AI models efficiently',
  35. icon: Settings,
  36. href: '/models',
  37. color: 'text-orange-500',
  38. },
  39. {
  40. title: 'Queue Monitor',
  41. description: 'Track and manage your generation jobs in real-time',
  42. icon: Activity,
  43. href: '/queue',
  44. color: 'text-pink-500',
  45. },
  46. ];
  47. export default function HomePage() {
  48. const [health, setHealth] = useState<'checking' | 'healthy' | 'error'>('checking');
  49. const [systemInfo, setSystemInfo] = useState<any>(null);
  50. useEffect(() => {
  51. checkHealth();
  52. loadSystemInfo();
  53. }, []);
  54. const checkHealth = async () => {
  55. try {
  56. await apiClient.getHealth();
  57. setHealth('healthy');
  58. } catch (err) {
  59. setHealth('error');
  60. }
  61. };
  62. const loadSystemInfo = async () => {
  63. try {
  64. const info = await apiClient.getSystemInfo();
  65. setSystemInfo(info);
  66. } catch (err) {
  67. console.error('Failed to load system info:', err);
  68. }
  69. };
  70. return (
  71. <AppLayout>
  72. <Header title="Stable Diffusion REST" description="Modern web interface for AI image generation" />
  73. <div className="container mx-auto p-6">
  74. <div className="space-y-8">
  75. {/* Status Banner */}
  76. <Card>
  77. <CardContent className="flex items-center justify-between p-6">
  78. <div className="flex items-center gap-3">
  79. {health === 'checking' ? (
  80. <>
  81. <div className="h-3 w-3 animate-pulse rounded-full bg-yellow-500" />
  82. <span className="text-sm">Checking API status...</span>
  83. </>
  84. ) : health === 'healthy' ? (
  85. <>
  86. <CheckCircle2 className="h-5 w-5 text-green-500" />
  87. <span className="text-sm font-medium">API is running</span>
  88. </>
  89. ) : (
  90. <>
  91. <XCircle className="h-5 w-5 text-red-500" />
  92. <span className="text-sm font-medium text-destructive">
  93. Cannot connect to API
  94. </span>
  95. </>
  96. )}
  97. </div>
  98. {systemInfo && (
  99. <div className="flex gap-4 text-sm text-muted-foreground">
  100. {systemInfo.version && <span>v{systemInfo.version}</span>}
  101. {systemInfo.cuda_available !== undefined && (
  102. <span>CUDA: {systemInfo.cuda_available ? 'Available' : 'Not Available'}</span>
  103. )}
  104. </div>
  105. )}
  106. </CardContent>
  107. </Card>
  108. {/* Welcome Section */}
  109. <div className="text-center">
  110. <h1 className="text-4xl font-bold tracking-tight">Welcome to SD REST UI</h1>
  111. <p className="mt-4 text-lg text-muted-foreground">
  112. A modern, intuitive interface for Stable Diffusion image generation
  113. </p>
  114. </div>
  115. {/* Features Grid */}
  116. <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
  117. {features.map((feature) => (
  118. <Card key={feature.href} className="group relative overflow-hidden transition-all hover:shadow-lg">
  119. <CardHeader>
  120. <div className="flex items-center gap-3">
  121. <div className={`rounded-lg bg-muted p-2 ${feature.color}`}>
  122. <feature.icon className="h-6 w-6" />
  123. </div>
  124. <CardTitle className="text-xl">{feature.title}</CardTitle>
  125. </div>
  126. <CardDescription className="mt-2">{feature.description}</CardDescription>
  127. </CardHeader>
  128. <CardContent>
  129. <Link href={feature.href}>
  130. <Button variant="ghost" className="w-full justify-between group-hover:bg-accent">
  131. Get Started
  132. <ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-1" />
  133. </Button>
  134. </Link>
  135. </CardContent>
  136. </Card>
  137. ))}
  138. </div>
  139. {/* Quick Start Guide */}
  140. <Card>
  141. <CardHeader>
  142. <CardTitle>Quick Start Guide</CardTitle>
  143. <CardDescription>Get started with image generation in a few simple steps</CardDescription>
  144. </CardHeader>
  145. <CardContent className="space-y-4">
  146. <div className="flex gap-4">
  147. <div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary text-primary-foreground font-semibold">
  148. 1
  149. </div>
  150. <div className="flex-1">
  151. <h4 className="font-medium">Load a Model</h4>
  152. <p className="text-sm text-muted-foreground">
  153. Navigate to <Link href="/models" className="text-primary hover:underline">Model Management</Link> and load your preferred checkpoint
  154. </p>
  155. </div>
  156. </div>
  157. <div className="flex gap-4">
  158. <div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary text-primary-foreground font-semibold">
  159. 2
  160. </div>
  161. <div className="flex-1">
  162. <h4 className="font-medium">Choose Generation Type</h4>
  163. <p className="text-sm text-muted-foreground">
  164. Select <Link href="/text2img" className="text-primary hover:underline">Text to Image</Link>, <Link href="/img2img" className="text-primary hover:underline">Image to Image</Link>, or <Link href="/upscaler" className="text-primary hover:underline">Upscaler</Link>
  165. </p>
  166. </div>
  167. </div>
  168. <div className="flex gap-4">
  169. <div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary text-primary-foreground font-semibold">
  170. 3
  171. </div>
  172. <div className="flex-1">
  173. <h4 className="font-medium">Generate & Monitor</h4>
  174. <p className="text-sm text-muted-foreground">
  175. Start generation and track progress in the <Link href="/queue" className="text-primary hover:underline">Queue Monitor</Link>
  176. </p>
  177. </div>
  178. </div>
  179. </CardContent>
  180. </Card>
  181. {/* API Info */}
  182. <Card>
  183. <CardHeader>
  184. <CardTitle>API Configuration</CardTitle>
  185. <CardDescription>Backend API connection details</CardDescription>
  186. </CardHeader>
  187. <CardContent>
  188. <dl className="grid gap-3 text-sm">
  189. <div className="flex justify-between">
  190. <dt className="text-muted-foreground">API URL:</dt>
  191. <dd className="font-mono">{process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080'}</dd>
  192. </div>
  193. <div className="flex justify-between">
  194. <dt className="text-muted-foreground">Base Path:</dt>
  195. <dd className="font-mono">{process.env.NEXT_PUBLIC_API_BASE_PATH || '/api/v1'}</dd>
  196. </div>
  197. <div className="flex justify-between">
  198. <dt className="text-muted-foreground">Status:</dt>
  199. <dd>
  200. {health === 'healthy' ? (
  201. <span className="text-green-600 dark:text-green-400">Connected</span>
  202. ) : health === 'error' ? (
  203. <span className="text-destructive">Disconnected</span>
  204. ) : (
  205. <span className="text-yellow-600 dark:text-yellow-400">Checking...</span>
  206. )}
  207. </dd>
  208. </div>
  209. </dl>
  210. </CardContent>
  211. </Card>
  212. </div>
  213. </div>
  214. </AppLayout>
  215. );
  216. }