Spaces:
Running
Running
update import and deploy
Browse files
frontend/src/app/page.tsx
CHANGED
|
@@ -17,6 +17,8 @@ export default function Home() {
|
|
| 17 |
const [selectedModel, setSelectedModel] = useState('gemini-3.0-pro');
|
| 18 |
const [isGenerating, setIsGenerating] = useState(false);
|
| 19 |
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
|
|
|
|
|
| 20 |
|
| 21 |
// Mobile view state: 'chat', 'editor', or 'settings'
|
| 22 |
const [mobileView, setMobileView] = useState<'chat' | 'editor' | 'settings'>('editor');
|
|
@@ -28,7 +30,7 @@ export default function Home() {
|
|
| 28 |
return () => clearInterval(interval);
|
| 29 |
}, []);
|
| 30 |
|
| 31 |
-
const checkAuth = () => {
|
| 32 |
const authenticated = checkIsAuthenticated();
|
| 33 |
setIsAuthenticated(authenticated);
|
| 34 |
|
|
@@ -37,6 +39,16 @@ export default function Home() {
|
|
| 37 |
const token = getStoredToken();
|
| 38 |
if (token) {
|
| 39 |
apiClient.setToken(token);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
}
|
| 41 |
}
|
| 42 |
};
|
|
@@ -151,17 +163,60 @@ export default function Home() {
|
|
| 151 |
return;
|
| 152 |
}
|
| 153 |
|
| 154 |
-
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
|
| 157 |
try {
|
| 158 |
const response = await apiClient.deploy({
|
| 159 |
code: generatedCode,
|
| 160 |
-
space_name: spaceName
|
| 161 |
language: selectedLanguage,
|
|
|
|
|
|
|
| 162 |
});
|
| 163 |
|
| 164 |
if (response.success) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
// Open the space URL in a new tab
|
| 166 |
window.open(response.space_url, '_blank');
|
| 167 |
|
|
@@ -169,7 +224,9 @@ export default function Home() {
|
|
| 169 |
const isDev = response.dev_mode;
|
| 170 |
const message = isDev
|
| 171 |
? 'π Opening HuggingFace Spaces creation page...\nPlease complete the space setup in the new tab.'
|
| 172 |
-
:
|
|
|
|
|
|
|
| 173 |
alert(message);
|
| 174 |
} else {
|
| 175 |
alert(`Deployment failed: ${response.message}`);
|
|
@@ -186,14 +243,33 @@ export default function Home() {
|
|
| 186 |
}
|
| 187 |
};
|
| 188 |
|
| 189 |
-
const handleImport = (code: string, language: Language) => {
|
| 190 |
setGeneratedCode(code);
|
| 191 |
setSelectedLanguage(language);
|
| 192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
// Add messages that include the imported code so LLM can see it
|
| 194 |
const userMessage: Message = {
|
| 195 |
role: 'user',
|
| 196 |
-
content:
|
|
|
|
|
|
|
| 197 |
timestamp: new Date().toISOString(),
|
| 198 |
};
|
| 199 |
|
|
|
|
| 17 |
const [selectedModel, setSelectedModel] = useState('gemini-3.0-pro');
|
| 18 |
const [isGenerating, setIsGenerating] = useState(false);
|
| 19 |
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
| 20 |
+
const [currentRepoId, setCurrentRepoId] = useState<string | null>(null); // Track imported/deployed space
|
| 21 |
+
const [username, setUsername] = useState<string | null>(null); // Track current user
|
| 22 |
|
| 23 |
// Mobile view state: 'chat', 'editor', or 'settings'
|
| 24 |
const [mobileView, setMobileView] = useState<'chat' | 'editor' | 'settings'>('editor');
|
|
|
|
| 30 |
return () => clearInterval(interval);
|
| 31 |
}, []);
|
| 32 |
|
| 33 |
+
const checkAuth = async () => {
|
| 34 |
const authenticated = checkIsAuthenticated();
|
| 35 |
setIsAuthenticated(authenticated);
|
| 36 |
|
|
|
|
| 39 |
const token = getStoredToken();
|
| 40 |
if (token) {
|
| 41 |
apiClient.setToken(token);
|
| 42 |
+
|
| 43 |
+
// Get username from auth status
|
| 44 |
+
try {
|
| 45 |
+
const authStatus = await apiClient.getAuthStatus();
|
| 46 |
+
if (authStatus.username) {
|
| 47 |
+
setUsername(authStatus.username);
|
| 48 |
+
}
|
| 49 |
+
} catch (error) {
|
| 50 |
+
console.error('Failed to get username:', error);
|
| 51 |
+
}
|
| 52 |
}
|
| 53 |
}
|
| 54 |
};
|
|
|
|
| 163 |
return;
|
| 164 |
}
|
| 165 |
|
| 166 |
+
// Determine if we're updating an existing space or creating a new one
|
| 167 |
+
let existingRepoId = currentRepoId;
|
| 168 |
+
let actionMessage = 'Deploy';
|
| 169 |
+
|
| 170 |
+
// If we have a current repo, check if user owns it
|
| 171 |
+
if (currentRepoId && username) {
|
| 172 |
+
const ownsSpace = currentRepoId.startsWith(`${username}/`);
|
| 173 |
+
if (ownsSpace) {
|
| 174 |
+
actionMessage = 'Update';
|
| 175 |
+
const confirmUpdate = confirm(`Update existing space: ${currentRepoId}?`);
|
| 176 |
+
if (!confirmUpdate) {
|
| 177 |
+
existingRepoId = null; // Create new space instead
|
| 178 |
+
actionMessage = 'Deploy';
|
| 179 |
+
}
|
| 180 |
+
} else {
|
| 181 |
+
// User doesn't own the imported space, create a new one
|
| 182 |
+
existingRepoId = null;
|
| 183 |
+
actionMessage = 'Deploy';
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
// Only prompt for space name if creating new space
|
| 188 |
+
let spaceName = undefined;
|
| 189 |
+
if (!existingRepoId) {
|
| 190 |
+
const input = prompt('Enter HuggingFace Space name (or leave empty for auto-generated):');
|
| 191 |
+
if (input === null) return; // User cancelled
|
| 192 |
+
spaceName = input || undefined;
|
| 193 |
+
}
|
| 194 |
|
| 195 |
try {
|
| 196 |
const response = await apiClient.deploy({
|
| 197 |
code: generatedCode,
|
| 198 |
+
space_name: spaceName,
|
| 199 |
language: selectedLanguage,
|
| 200 |
+
existing_repo_id: existingRepoId || undefined,
|
| 201 |
+
commit_message: existingRepoId ? 'Update via AnyCoder' : undefined,
|
| 202 |
});
|
| 203 |
|
| 204 |
if (response.success) {
|
| 205 |
+
// Update current repo ID if we got one back
|
| 206 |
+
if (response.repo_id) {
|
| 207 |
+
setCurrentRepoId(response.repo_id);
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
// Add deployment message to chat
|
| 211 |
+
const deployMessage: Message = {
|
| 212 |
+
role: 'assistant',
|
| 213 |
+
content: existingRepoId
|
| 214 |
+
? `β
Updated space: ${response.space_url}`
|
| 215 |
+
: `β
Deployed to: ${response.space_url}`,
|
| 216 |
+
timestamp: new Date().toISOString(),
|
| 217 |
+
};
|
| 218 |
+
setMessages((prev) => [...prev, deployMessage]);
|
| 219 |
+
|
| 220 |
// Open the space URL in a new tab
|
| 221 |
window.open(response.space_url, '_blank');
|
| 222 |
|
|
|
|
| 224 |
const isDev = response.dev_mode;
|
| 225 |
const message = isDev
|
| 226 |
? 'π Opening HuggingFace Spaces creation page...\nPlease complete the space setup in the new tab.'
|
| 227 |
+
: existingRepoId
|
| 228 |
+
? `β
Updated successfully!\n\nOpening: ${response.space_url}`
|
| 229 |
+
: `β
Deployed successfully!\n\nOpening: ${response.space_url}`;
|
| 230 |
alert(message);
|
| 231 |
} else {
|
| 232 |
alert(`Deployment failed: ${response.message}`);
|
|
|
|
| 243 |
}
|
| 244 |
};
|
| 245 |
|
| 246 |
+
const handleImport = (code: string, language: Language, importUrl?: string) => {
|
| 247 |
setGeneratedCode(code);
|
| 248 |
setSelectedLanguage(language);
|
| 249 |
|
| 250 |
+
// Extract repo_id from import URL if provided
|
| 251 |
+
if (importUrl) {
|
| 252 |
+
const spaceMatch = importUrl.match(/huggingface\.co\/spaces\/([^\/\s\)]+\/[^\/\s\)]+)/);
|
| 253 |
+
if (spaceMatch) {
|
| 254 |
+
const importedRepoId = spaceMatch[1];
|
| 255 |
+
// Only set as current repo if user owns it
|
| 256 |
+
if (username && importedRepoId.startsWith(`${username}/`)) {
|
| 257 |
+
setCurrentRepoId(importedRepoId);
|
| 258 |
+
console.log('[Import] Set current repo to:', importedRepoId);
|
| 259 |
+
} else {
|
| 260 |
+
// User doesn't own the imported space, clear current repo
|
| 261 |
+
setCurrentRepoId(null);
|
| 262 |
+
console.log('[Import] User does not own imported space:', importedRepoId);
|
| 263 |
+
}
|
| 264 |
+
}
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
// Add messages that include the imported code so LLM can see it
|
| 268 |
const userMessage: Message = {
|
| 269 |
role: 'user',
|
| 270 |
+
content: importUrl
|
| 271 |
+
? `Imported Space from ${importUrl}`
|
| 272 |
+
: `I imported a ${language} project. Here's the code that was imported.`,
|
| 273 |
timestamp: new Date().toISOString(),
|
| 274 |
};
|
| 275 |
|
frontend/src/components/ControlPanel.tsx
CHANGED
|
@@ -11,7 +11,7 @@ interface ControlPanelProps {
|
|
| 11 |
onModelChange: (modelId: string) => void;
|
| 12 |
onDeploy: () => void;
|
| 13 |
onClear: () => void;
|
| 14 |
-
onImport?: (code: string, language: Language) => void;
|
| 15 |
isGenerating: boolean;
|
| 16 |
}
|
| 17 |
|
|
@@ -83,7 +83,7 @@ export default function ControlPanel({
|
|
| 83 |
|
| 84 |
// Call the onImport callback if provided
|
| 85 |
if (onImport && result.code) {
|
| 86 |
-
onImport(result.code, result.language || 'html');
|
| 87 |
}
|
| 88 |
|
| 89 |
// Close modal and reset
|
|
|
|
| 11 |
onModelChange: (modelId: string) => void;
|
| 12 |
onDeploy: () => void;
|
| 13 |
onClear: () => void;
|
| 14 |
+
onImport?: (code: string, language: Language, importUrl?: string) => void;
|
| 15 |
isGenerating: boolean;
|
| 16 |
}
|
| 17 |
|
|
|
|
| 83 |
|
| 84 |
// Call the onImport callback if provided
|
| 85 |
if (onImport && result.code) {
|
| 86 |
+
onImport(result.code, result.language || 'html', importUrl);
|
| 87 |
}
|
| 88 |
|
| 89 |
// Close modal and reset
|
frontend/src/types/index.ts
CHANGED
|
@@ -47,6 +47,8 @@ export interface DeploymentRequest {
|
|
| 47 |
space_name?: string;
|
| 48 |
language: string;
|
| 49 |
requirements?: string;
|
|
|
|
|
|
|
| 50 |
}
|
| 51 |
|
| 52 |
export interface DeploymentResponse {
|
|
@@ -54,6 +56,7 @@ export interface DeploymentResponse {
|
|
| 54 |
space_url?: string;
|
| 55 |
message: string;
|
| 56 |
dev_mode?: boolean;
|
|
|
|
| 57 |
}
|
| 58 |
|
| 59 |
export type Language = 'html' | 'gradio' | 'transformers.js' | 'streamlit' | 'comfyui' | 'react';
|
|
|
|
| 47 |
space_name?: string;
|
| 48 |
language: string;
|
| 49 |
requirements?: string;
|
| 50 |
+
existing_repo_id?: string; // For updating existing spaces
|
| 51 |
+
commit_message?: string;
|
| 52 |
}
|
| 53 |
|
| 54 |
export interface DeploymentResponse {
|
|
|
|
| 56 |
space_url?: string;
|
| 57 |
message: string;
|
| 58 |
dev_mode?: boolean;
|
| 59 |
+
repo_id?: string;
|
| 60 |
}
|
| 61 |
|
| 62 |
export type Language = 'html' | 'gradio' | 'transformers.js' | 'streamlit' | 'comfyui' | 'react';
|