akhaliq HF Staff commited on
Commit
cd2780c
Β·
1 Parent(s): a4d4829

autodeploy apps

Browse files
backend_api.py CHANGED
@@ -820,6 +820,56 @@ async def generate_code(
820
  })
821
  yield f"data: {completion_data}\n\n"
822
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
  except Exception as e:
824
  # Handle rate limiting and other API errors
825
  error_message = str(e)
 
820
  })
821
  yield f"data: {completion_data}\n\n"
822
 
823
+ # Auto-deploy after code generation (if authenticated)
824
+ auth = get_auth_from_header(authorization)
825
+ if auth.is_authenticated() and not (auth.token and auth.token.startswith("dev_token_")):
826
+ try:
827
+ # Send deploying status
828
+ deploying_data = json.dumps({
829
+ "type": "deploying",
830
+ "message": "πŸš€ Deploying your app to HuggingFace Spaces..."
831
+ })
832
+ yield f"data: {deploying_data}\n\n"
833
+
834
+ # Import deployment function
835
+ from backend_deploy import deploy_to_huggingface_space
836
+
837
+ # Convert history to the format expected by deploy function
838
+ history_list = [[msg.get('role', ''), msg.get('content', '')] for msg in (request.history or [])]
839
+
840
+ # Deploy the code
841
+ success, message, space_url = deploy_to_huggingface_space(
842
+ code=generated_code,
843
+ language=language,
844
+ token=auth.token,
845
+ username=auth.username,
846
+ history=history_list
847
+ )
848
+
849
+ if success and space_url:
850
+ # Send deployment success
851
+ deploy_success_data = json.dumps({
852
+ "type": "deployed",
853
+ "message": message,
854
+ "space_url": space_url
855
+ })
856
+ yield f"data: {deploy_success_data}\n\n"
857
+ else:
858
+ # Send deployment error (non-blocking - code generation still succeeded)
859
+ deploy_error_data = json.dumps({
860
+ "type": "deploy_error",
861
+ "message": f"⚠️ Deployment failed: {message}"
862
+ })
863
+ yield f"data: {deploy_error_data}\n\n"
864
+ except Exception as deploy_error:
865
+ # Log deployment error but don't fail the generation
866
+ print(f"[Auto-Deploy] Error: {deploy_error}")
867
+ deploy_error_data = json.dumps({
868
+ "type": "deploy_error",
869
+ "message": f"⚠️ Deployment error: {str(deploy_error)}"
870
+ })
871
+ yield f"data: {deploy_error_data}\n\n"
872
+
873
  except Exception as e:
874
  # Handle rate limiting and other API errors
875
  error_message = str(e)
frontend/src/app/page.tsx CHANGED
@@ -338,6 +338,55 @@ export default function Home() {
338
  };
339
  return newMessages;
340
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  }
342
  );
343
  } catch (error) {
@@ -835,7 +884,6 @@ export default function Home() {
835
  selectedModel={selectedModel}
836
  onLanguageChange={setSelectedLanguage}
837
  onModelChange={setSelectedModel}
838
- onDeploy={handleDeploy}
839
  onClear={handleClear}
840
  onImport={handleImport}
841
  isGenerating={isGenerating}
 
338
  };
339
  return newMessages;
340
  });
341
+ },
342
+ // onDeploying
343
+ (message: string) => {
344
+ console.log('[Deploy] Deployment started:', message);
345
+ // Update message to show deployment in progress
346
+ setMessages((prev) => {
347
+ const newMessages = [...prev];
348
+ newMessages[newMessages.length - 1] = {
349
+ ...assistantMessage,
350
+ content: `βœ… Code generated successfully!\n\n${message}`,
351
+ };
352
+ return newMessages;
353
+ });
354
+ },
355
+ // onDeployed
356
+ (message: string, spaceUrl: string) => {
357
+ console.log('[Deploy] Deployment successful:', spaceUrl);
358
+
359
+ // Extract repo_id from space URL
360
+ const match = spaceUrl.match(/huggingface\.co\/spaces\/([^\/\s\)]+\/[^\/\s\)]+)/);
361
+ if (match) {
362
+ setCurrentRepoId(match[1]);
363
+ }
364
+
365
+ // Update message with deployment success and URL
366
+ setMessages((prev) => {
367
+ const newMessages = [...prev];
368
+ newMessages[newMessages.length - 1] = {
369
+ ...assistantMessage,
370
+ content: `βœ… Code generated and deployed!\n\nπŸš€ **View your app:** [${spaceUrl}](${spaceUrl})`,
371
+ };
372
+ return newMessages;
373
+ });
374
+
375
+ // Open the space URL in a new tab
376
+ window.open(spaceUrl, '_blank');
377
+ },
378
+ // onDeployError
379
+ (message: string) => {
380
+ console.log('[Deploy] Deployment error:', message);
381
+ // Update message to show deployment failed (but code generation succeeded)
382
+ setMessages((prev) => {
383
+ const newMessages = [...prev];
384
+ newMessages[newMessages.length - 1] = {
385
+ ...assistantMessage,
386
+ content: `βœ… Code generated successfully!\n\n${message}\n\nYou can still use the "Publish" button to deploy manually.`,
387
+ };
388
+ return newMessages;
389
+ });
390
  }
391
  );
392
  } catch (error) {
 
884
  selectedModel={selectedModel}
885
  onLanguageChange={setSelectedLanguage}
886
  onModelChange={setSelectedModel}
 
887
  onClear={handleClear}
888
  onImport={handleImport}
889
  isGenerating={isGenerating}
frontend/src/components/ControlPanel.tsx CHANGED
@@ -9,7 +9,6 @@ interface ControlPanelProps {
9
  selectedModel: string;
10
  onLanguageChange: (language: Language) => void;
11
  onModelChange: (modelId: string) => void;
12
- onDeploy: () => void;
13
  onClear: () => void;
14
  onImport?: (code: string, language: Language, importUrl?: string) => void;
15
  isGenerating: boolean;
@@ -20,7 +19,6 @@ export default function ControlPanel({
20
  selectedModel,
21
  onLanguageChange,
22
  onModelChange,
23
- onDeploy,
24
  onClear,
25
  onImport,
26
  isGenerating,
@@ -269,13 +267,6 @@ export default function ControlPanel({
269
  >
270
  Import Project
271
  </button>
272
- <button
273
- onClick={onDeploy}
274
- disabled={isGenerating}
275
- className="w-full px-3 py-2.5 bg-white text-black text-sm rounded-full hover:bg-[#f5f5f7] disabled:opacity-30 disabled:cursor-not-allowed transition-all font-medium flex items-center justify-center active:scale-95"
276
- >
277
- Publish
278
- </button>
279
  <button
280
  onClick={onClear}
281
  disabled={isGenerating}
 
9
  selectedModel: string;
10
  onLanguageChange: (language: Language) => void;
11
  onModelChange: (modelId: string) => void;
 
12
  onClear: () => void;
13
  onImport?: (code: string, language: Language, importUrl?: string) => void;
14
  isGenerating: boolean;
 
19
  selectedModel,
20
  onLanguageChange,
21
  onModelChange,
 
22
  onClear,
23
  onImport,
24
  isGenerating,
 
267
  >
268
  Import Project
269
  </button>
 
 
 
 
 
 
 
270
  <button
271
  onClick={onClear}
272
  disabled={isGenerating}
frontend/src/lib/api.ts CHANGED
@@ -274,7 +274,10 @@ class ApiClient {
274
  request: CodeGenerationRequest,
275
  onChunk: (content: string) => void,
276
  onComplete: (code: string) => void,
277
- onError: (error: string) => void
 
 
 
278
  ): () => void {
279
  // Build the URL correctly whether we have a base URL or not
280
  const baseUrl = API_URL || window.location.origin;
@@ -353,7 +356,22 @@ class ApiClient {
353
  // Use the complete code from the message if available, otherwise use accumulated
354
  const finalCode = data.code || accumulatedCode;
355
  onComplete(finalCode);
356
- return; // Exit the processing loop
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  } else if (data.type === 'error') {
358
  console.error('[Stream] Error:', data.message);
359
  onError(data.message || 'Unknown error occurred');
 
274
  request: CodeGenerationRequest,
275
  onChunk: (content: string) => void,
276
  onComplete: (code: string) => void,
277
+ onError: (error: string) => void,
278
+ onDeploying?: (message: string) => void,
279
+ onDeployed?: (message: string, spaceUrl: string) => void,
280
+ onDeployError?: (message: string) => void
281
  ): () => void {
282
  // Build the URL correctly whether we have a base URL or not
283
  const baseUrl = API_URL || window.location.origin;
 
356
  // Use the complete code from the message if available, otherwise use accumulated
357
  const finalCode = data.code || accumulatedCode;
358
  onComplete(finalCode);
359
+ // Don't return yet - might have deployment events coming
360
+ } else if (data.type === 'deploying') {
361
+ console.log('[Stream] Deployment started:', data.message);
362
+ if (onDeploying) {
363
+ onDeploying(data.message || 'Deploying...');
364
+ }
365
+ } else if (data.type === 'deployed') {
366
+ console.log('[Stream] Deployment successful:', data.space_url);
367
+ if (onDeployed) {
368
+ onDeployed(data.message || 'Deployed!', data.space_url);
369
+ }
370
+ } else if (data.type === 'deploy_error') {
371
+ console.log('[Stream] Deployment error:', data.message);
372
+ if (onDeployError) {
373
+ onDeployError(data.message || 'Deployment failed');
374
+ }
375
  } else if (data.type === 'error') {
376
  console.error('[Stream] Error:', data.message);
377
  onError(data.message || 'Unknown error occurred');