Spaces:
Running
Running
fix
Browse files- backend_api.py +24 -2
- frontend/src/app/page.tsx +11 -4
- frontend/src/lib/api.ts +9 -2
- frontend/src/lib/auth.ts +23 -1
backend_api.py
CHANGED
|
@@ -915,7 +915,19 @@ async def deploy(
|
|
| 915 |
# PRIORITY 1: Check history for deployed/imported spaces (like Gradio version does)
|
| 916 |
# This is more reliable than session tracking since history persists in frontend
|
| 917 |
if request.history and auth.username:
|
| 918 |
-
print(f"[Deploy]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 919 |
for msg in request.history:
|
| 920 |
role = msg.get('role', '')
|
| 921 |
content = msg.get('content', '')
|
|
@@ -923,13 +935,18 @@ async def deploy(
|
|
| 923 |
# Check for deployment confirmations
|
| 924 |
if role == 'assistant' and ('β
Deployed!' in content or 'β
Updated!' in content):
|
| 925 |
import re
|
|
|
|
|
|
|
| 926 |
match = re.search(r'huggingface\.co/spaces/([^/\s\)]+/[^/\s\)]+)', content)
|
| 927 |
if match:
|
| 928 |
history_space_id = match.group(1)
|
| 929 |
-
print(f"[Deploy] β
|
| 930 |
if not existing_repo_id:
|
| 931 |
existing_repo_id = history_space_id
|
|
|
|
| 932 |
break
|
|
|
|
|
|
|
| 933 |
|
| 934 |
# Check for imports
|
| 935 |
elif role == 'user' and 'import' in content.lower():
|
|
@@ -943,6 +960,11 @@ async def deploy(
|
|
| 943 |
if not existing_repo_id:
|
| 944 |
existing_repo_id = imported_space
|
| 945 |
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 946 |
|
| 947 |
# PRIORITY 2: Check session for previously deployed spaces (fallback)
|
| 948 |
# This helps when history isn't passed from frontend
|
|
|
|
| 915 |
# PRIORITY 1: Check history for deployed/imported spaces (like Gradio version does)
|
| 916 |
# This is more reliable than session tracking since history persists in frontend
|
| 917 |
if request.history and auth.username:
|
| 918 |
+
print(f"[Deploy] ========== CHECKING HISTORY ==========")
|
| 919 |
+
print(f"[Deploy] History length: {len(request.history)} messages")
|
| 920 |
+
print(f"[Deploy] Username: {auth.username}")
|
| 921 |
+
|
| 922 |
+
# Log each message in history for debugging
|
| 923 |
+
for i, msg in enumerate(request.history):
|
| 924 |
+
role = msg.get('role', 'unknown')
|
| 925 |
+
content = msg.get('content', '')
|
| 926 |
+
content_preview = content[:100] if content else ''
|
| 927 |
+
print(f"[Deploy] Message {i+1}: role={role}, content_preview='{content_preview}...'")
|
| 928 |
+
|
| 929 |
+
print(f"[Deploy] ==========================================")
|
| 930 |
+
|
| 931 |
for msg in request.history:
|
| 932 |
role = msg.get('role', '')
|
| 933 |
content = msg.get('content', '')
|
|
|
|
| 935 |
# Check for deployment confirmations
|
| 936 |
if role == 'assistant' and ('β
Deployed!' in content or 'β
Updated!' in content):
|
| 937 |
import re
|
| 938 |
+
print(f"[Deploy] π Found deployment message in history!")
|
| 939 |
+
print(f"[Deploy] Content: {content[:200]}")
|
| 940 |
match = re.search(r'huggingface\.co/spaces/([^/\s\)]+/[^/\s\)]+)', content)
|
| 941 |
if match:
|
| 942 |
history_space_id = match.group(1)
|
| 943 |
+
print(f"[Deploy] β
EXTRACTED space ID from history: {history_space_id}")
|
| 944 |
if not existing_repo_id:
|
| 945 |
existing_repo_id = history_space_id
|
| 946 |
+
print(f"[Deploy] β
WILL UPDATE EXISTING SPACE: {existing_repo_id}")
|
| 947 |
break
|
| 948 |
+
else:
|
| 949 |
+
print(f"[Deploy] β οΈ Deployment message found but couldn't extract space ID")
|
| 950 |
|
| 951 |
# Check for imports
|
| 952 |
elif role == 'user' and 'import' in content.lower():
|
|
|
|
| 960 |
if not existing_repo_id:
|
| 961 |
existing_repo_id = imported_space
|
| 962 |
break
|
| 963 |
+
else:
|
| 964 |
+
if not request.history:
|
| 965 |
+
print(f"[Deploy] β οΈ No history provided in request")
|
| 966 |
+
if not auth.username:
|
| 967 |
+
print(f"[Deploy] β οΈ No username available")
|
| 968 |
|
| 969 |
# PRIORITY 2: Check session for previously deployed spaces (fallback)
|
| 970 |
# This helps when history isn't passed from frontend
|
frontend/src/app/page.tsx
CHANGED
|
@@ -433,13 +433,20 @@ export default function Home() {
|
|
| 433 |
console.log('[Deploy] Username:', currentUsername);
|
| 434 |
console.log('[Deploy] Existing space from history:', existingSpace);
|
| 435 |
console.log('[Deploy] Will create new space?', !existingSpace);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 436 |
console.log('[Deploy] =================================================================');
|
| 437 |
|
| 438 |
// Build deploy request, omitting undefined fields
|
| 439 |
const deployRequest: any = {
|
| 440 |
code: generatedCode,
|
| 441 |
language: selectedLanguage,
|
| 442 |
-
history:
|
| 443 |
};
|
| 444 |
|
| 445 |
// Only include optional fields if they have values
|
|
@@ -478,12 +485,12 @@ export default function Home() {
|
|
| 478 |
}
|
| 479 |
}
|
| 480 |
|
| 481 |
-
// Add deployment message to chat (EXACT
|
| 482 |
const deployMessage: Message = {
|
| 483 |
role: 'assistant',
|
| 484 |
content: existingSpace
|
| 485 |
-
?
|
| 486 |
-
:
|
| 487 |
timestamp: new Date().toISOString(),
|
| 488 |
};
|
| 489 |
setMessages((prev) => [...prev, deployMessage]);
|
|
|
|
| 433 |
console.log('[Deploy] Username:', currentUsername);
|
| 434 |
console.log('[Deploy] Existing space from history:', existingSpace);
|
| 435 |
console.log('[Deploy] Will create new space?', !existingSpace);
|
| 436 |
+
console.log('[Deploy] Messages count:', messages.length);
|
| 437 |
+
console.log('[Deploy] Messages (first 3):', messages.slice(0, 3).map(m => ({ role: m.role, content: m.content.substring(0, 100) })));
|
| 438 |
+
|
| 439 |
+
// CRITICAL DEBUG: Check what we're actually sending
|
| 440 |
+
const historyToSend = messages.map(msg => ({ role: msg.role, content: msg.content }));
|
| 441 |
+
console.log('[Deploy] History to send (length):', historyToSend.length);
|
| 442 |
+
console.log('[Deploy] History to send (first 2):', historyToSend.slice(0, 2));
|
| 443 |
console.log('[Deploy] =================================================================');
|
| 444 |
|
| 445 |
// Build deploy request, omitting undefined fields
|
| 446 |
const deployRequest: any = {
|
| 447 |
code: generatedCode,
|
| 448 |
language: selectedLanguage,
|
| 449 |
+
history: historyToSend // Use the variable we just logged
|
| 450 |
};
|
| 451 |
|
| 452 |
// Only include optional fields if they have values
|
|
|
|
| 485 |
}
|
| 486 |
}
|
| 487 |
|
| 488 |
+
// Add deployment message to chat (EXACT format backend expects)
|
| 489 |
const deployMessage: Message = {
|
| 490 |
role: 'assistant',
|
| 491 |
content: existingSpace
|
| 492 |
+
? `β
Updated! View your space at: ${response.space_url}`
|
| 493 |
+
: `β
Deployed! View your space at: ${response.space_url}`,
|
| 494 |
timestamp: new Date().toISOString(),
|
| 495 |
};
|
| 496 |
setMessages((prev) => [...prev, deployMessage]);
|
frontend/src/lib/api.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
// API client for AnyCoder backend
|
| 2 |
|
| 3 |
import axios, { AxiosInstance } from 'axios';
|
|
|
|
| 4 |
import type {
|
| 5 |
Model,
|
| 6 |
AuthStatus,
|
|
@@ -54,7 +55,12 @@ class ApiClient {
|
|
| 54 |
|
| 55 |
// Add auth token to requests if available
|
| 56 |
this.client.interceptors.request.use((config) => {
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
config.headers.Authorization = `Bearer ${this.token}`;
|
| 59 |
}
|
| 60 |
return config;
|
|
@@ -274,7 +280,8 @@ class ApiClient {
|
|
| 274 |
method: 'POST',
|
| 275 |
headers: {
|
| 276 |
'Content-Type': 'application/json',
|
| 277 |
-
...(
|
|
|
|
| 278 |
},
|
| 279 |
body: JSON.stringify(request),
|
| 280 |
signal: abortController.signal,
|
|
|
|
| 1 |
// API client for AnyCoder backend
|
| 2 |
|
| 3 |
import axios, { AxiosInstance } from 'axios';
|
| 4 |
+
import { getStoredSessionToken } from './auth'; // NEW: Import session token
|
| 5 |
import type {
|
| 6 |
Model,
|
| 7 |
AuthStatus,
|
|
|
|
| 55 |
|
| 56 |
// Add auth token to requests if available
|
| 57 |
this.client.interceptors.request.use((config) => {
|
| 58 |
+
// Use session token instead of OAuth token for session tracking
|
| 59 |
+
const sessionToken = getStoredSessionToken();
|
| 60 |
+
if (sessionToken) {
|
| 61 |
+
config.headers.Authorization = `Bearer ${sessionToken}`;
|
| 62 |
+
} else if (this.token) {
|
| 63 |
+
// Fallback to OAuth token if no session token
|
| 64 |
config.headers.Authorization = `Bearer ${this.token}`;
|
| 65 |
}
|
| 66 |
return config;
|
|
|
|
| 280 |
method: 'POST',
|
| 281 |
headers: {
|
| 282 |
'Content-Type': 'application/json',
|
| 283 |
+
...(getStoredSessionToken() ? { 'Authorization': `Bearer ${getStoredSessionToken()}` } :
|
| 284 |
+
this.token ? { 'Authorization': `Bearer ${this.token}` } : {}),
|
| 285 |
},
|
| 286 |
body: JSON.stringify(request),
|
| 287 |
signal: abortController.signal,
|
frontend/src/lib/auth.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
// HuggingFace OAuth authentication utilities (Server-side flow for Docker Spaces)
|
| 2 |
|
| 3 |
const STORAGE_KEY = 'hf_oauth_token';
|
|
|
|
| 4 |
const USER_INFO_KEY = 'hf_user_info';
|
| 5 |
const DEV_MODE_KEY = 'hf_dev_mode';
|
| 6 |
const API_BASE = '/api';
|
|
@@ -71,8 +72,9 @@ export async function initializeOAuth(): Promise<OAuthResult | null> {
|
|
| 71 |
userInfo,
|
| 72 |
};
|
| 73 |
|
| 74 |
-
// Store the OAuth result
|
| 75 |
storeOAuthData(oauthResult);
|
|
|
|
| 76 |
|
| 77 |
// Clean up URL
|
| 78 |
window.history.replaceState({}, document.title, window.location.pathname);
|
|
@@ -129,6 +131,7 @@ export async function loginWithHuggingFace(): Promise<void> {
|
|
| 129 |
export function logout(): void {
|
| 130 |
if (typeof window !== 'undefined') {
|
| 131 |
localStorage.removeItem(STORAGE_KEY);
|
|
|
|
| 132 |
localStorage.removeItem(USER_INFO_KEY);
|
| 133 |
localStorage.removeItem(DEV_MODE_KEY);
|
| 134 |
}
|
|
@@ -144,6 +147,25 @@ function storeOAuthData(result: OAuthResult): void {
|
|
| 144 |
}
|
| 145 |
}
|
| 146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
/**
|
| 148 |
* Get stored access token
|
| 149 |
*/
|
|
|
|
| 1 |
// HuggingFace OAuth authentication utilities (Server-side flow for Docker Spaces)
|
| 2 |
|
| 3 |
const STORAGE_KEY = 'hf_oauth_token';
|
| 4 |
+
const SESSION_KEY = 'hf_session_token'; // NEW: Store session UUID
|
| 5 |
const USER_INFO_KEY = 'hf_user_info';
|
| 6 |
const DEV_MODE_KEY = 'hf_dev_mode';
|
| 7 |
const API_BASE = '/api';
|
|
|
|
| 72 |
userInfo,
|
| 73 |
};
|
| 74 |
|
| 75 |
+
// Store the OAuth result AND session token
|
| 76 |
storeOAuthData(oauthResult);
|
| 77 |
+
storeSessionToken(sessionToken); // NEW: Store session UUID
|
| 78 |
|
| 79 |
// Clean up URL
|
| 80 |
window.history.replaceState({}, document.title, window.location.pathname);
|
|
|
|
| 131 |
export function logout(): void {
|
| 132 |
if (typeof window !== 'undefined') {
|
| 133 |
localStorage.removeItem(STORAGE_KEY);
|
| 134 |
+
localStorage.removeItem(SESSION_KEY); // NEW: Clear session token
|
| 135 |
localStorage.removeItem(USER_INFO_KEY);
|
| 136 |
localStorage.removeItem(DEV_MODE_KEY);
|
| 137 |
}
|
|
|
|
| 147 |
}
|
| 148 |
}
|
| 149 |
|
| 150 |
+
/**
|
| 151 |
+
* Store session token in localStorage
|
| 152 |
+
*/
|
| 153 |
+
function storeSessionToken(sessionToken: string): void {
|
| 154 |
+
if (typeof window !== 'undefined') {
|
| 155 |
+
localStorage.setItem(SESSION_KEY, sessionToken);
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
/**
|
| 160 |
+
* Get stored session token
|
| 161 |
+
*/
|
| 162 |
+
export function getStoredSessionToken(): string | null {
|
| 163 |
+
if (typeof window !== 'undefined') {
|
| 164 |
+
return localStorage.getItem(SESSION_KEY);
|
| 165 |
+
}
|
| 166 |
+
return null;
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
/**
|
| 170 |
* Get stored access token
|
| 171 |
*/
|