Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
·
7a46537
1
Parent(s):
3cc7c13
improve orientation switch
Browse files- api_core.py +6 -8
- build/web/flutter_bootstrap.js +1 -1
- build/web/flutter_service_worker.js +2 -2
- build/web/index.html +1 -1
- build/web/main.dart.js +0 -0
- lib/screens/video_screen.dart +23 -17
- lib/widgets/video_player/video_player_widget.dart +133 -30
api_core.py
CHANGED
@@ -619,7 +619,7 @@ Your caption:"""
|
|
619 |
|
620 |
# Use the same logic as regular video generation but with thumbnail settings
|
621 |
try:
|
622 |
-
logger.info(f"[{request_id}] Generating thumbnail for video {video_id} with seed {seed}")
|
623 |
|
624 |
start_time = time.time()
|
625 |
# Rest of thumbnail generation logic same as regular video but with optimized settings
|
@@ -684,16 +684,14 @@ Your caption:"""
|
|
684 |
if orientation == 'PORTRAIT' and width > height:
|
685 |
# Swap width and height for portrait orientation
|
686 |
width, height = height, width
|
687 |
-
logger.info(f"Orientation: {orientation}, swapped dimensions to width={width}, height={height}")
|
688 |
elif orientation == 'LANDSCAPE' and height > width:
|
689 |
# Swap height and width for landscape orientation
|
690 |
height, width = width, height
|
691 |
-
logger.info(f"Orientation: {orientation}, swapped dimensions to width={width}, height={height}")
|
692 |
else:
|
693 |
-
logger.info(f"Orientation: {orientation}, using original dimensions width={width}, height={height}")
|
694 |
-
|
695 |
-
# Log the user role and config values being used
|
696 |
-
logger.info(f"Using config values: width={width}, height={height}, num_frames={num_frames}, steps={num_inference_steps}, fps={frame_rate} | role: {user_role}")
|
697 |
|
698 |
# Generate the video with standard settings
|
699 |
return await self._generate_video_content(
|
@@ -720,7 +718,7 @@ Your caption:"""
|
|
720 |
request_id = options.get('request_id', str(uuid.uuid4())[:8]) # Get or generate request ID
|
721 |
video_id = options.get('video_id', 'unknown')
|
722 |
|
723 |
-
logger.info(f"[{request_id}] Generating {'thumbnail' if is_thumbnail else 'video'} for video {video_id} with seed {seed}")
|
724 |
|
725 |
json_payload = {
|
726 |
"inputs": {
|
|
|
619 |
|
620 |
# Use the same logic as regular video generation but with thumbnail settings
|
621 |
try:
|
622 |
+
# logger.info(f"[{request_id}] Generating thumbnail for video {video_id} with seed {seed}")
|
623 |
|
624 |
start_time = time.time()
|
625 |
# Rest of thumbnail generation logic same as regular video but with optimized settings
|
|
|
684 |
if orientation == 'PORTRAIT' and width > height:
|
685 |
# Swap width and height for portrait orientation
|
686 |
width, height = height, width
|
687 |
+
# logger.info(f"Orientation: {orientation}, swapped dimensions to width={width}, height={height}")
|
688 |
elif orientation == 'LANDSCAPE' and height > width:
|
689 |
# Swap height and width for landscape orientation
|
690 |
height, width = width, height
|
691 |
+
#logger.info(f"Orientation: {orientation}, swapped dimensions to width={width}, height={height}, steps={num_inference_steps}, fps={frame_rate} | role: {user_role}")
|
692 |
else:
|
693 |
+
#logger.info(f"Orientation: {orientation}, using original dimensions width={width}, height={height}, steps={num_inference_steps}, fps={frame_rate} | role: {user_role}")
|
694 |
+
pass
|
|
|
|
|
695 |
|
696 |
# Generate the video with standard settings
|
697 |
return await self._generate_video_content(
|
|
|
718 |
request_id = options.get('request_id', str(uuid.uuid4())[:8]) # Get or generate request ID
|
719 |
video_id = options.get('video_id', 'unknown')
|
720 |
|
721 |
+
# logger.info(f"[{request_id}] Generating {'thumbnail' if is_thumbnail else 'video'} for video {video_id} with seed {seed}")
|
722 |
|
723 |
json_payload = {
|
724 |
"inputs": {
|
build/web/flutter_bootstrap.js
CHANGED
@@ -39,6 +39,6 @@ _flutter.buildConfig = {"engineRevision":"382be0028d370607f76215a9be322e5514b263
|
|
39 |
|
40 |
_flutter.loader.load({
|
41 |
serviceWorkerSettings: {
|
42 |
-
serviceWorkerVersion: "
|
43 |
}
|
44 |
});
|
|
|
39 |
|
40 |
_flutter.loader.load({
|
41 |
serviceWorkerSettings: {
|
42 |
+
serviceWorkerVersion: "1197636580"
|
43 |
}
|
44 |
});
|
build/web/flutter_service_worker.js
CHANGED
@@ -3,11 +3,11 @@ const MANIFEST = 'flutter-app-manifest';
|
|
3 |
const TEMP = 'flutter-temp-cache';
|
4 |
const CACHE_NAME = 'flutter-app-cache';
|
5 |
|
6 |
-
const RESOURCES = {"flutter_bootstrap.js": "
|
7 |
"version.json": "b5eaae4fc120710a3c35125322173615",
|
8 |
"index.html": "cd2094e3989e3eb0424e47d7d188c298",
|
9 |
"/": "cd2094e3989e3eb0424e47d7d188c298",
|
10 |
-
"main.dart.js": "
|
11 |
"flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
|
12 |
"aitube.svg": "26140ba0d153b213b122bc6ebcc17f6c",
|
13 |
"favicon.png": "c8a183c516004e648a7bac7497c89b97",
|
|
|
3 |
const TEMP = 'flutter-temp-cache';
|
4 |
const CACHE_NAME = 'flutter-app-cache';
|
5 |
|
6 |
+
const RESOURCES = {"flutter_bootstrap.js": "2e5faa3ab3c446c3c3eaa2ce252f366a",
|
7 |
"version.json": "b5eaae4fc120710a3c35125322173615",
|
8 |
"index.html": "cd2094e3989e3eb0424e47d7d188c298",
|
9 |
"/": "cd2094e3989e3eb0424e47d7d188c298",
|
10 |
+
"main.dart.js": "14a165f5350b8bcff180f1cf376cf819",
|
11 |
"flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
|
12 |
"aitube.svg": "26140ba0d153b213b122bc6ebcc17f6c",
|
13 |
"favicon.png": "c8a183c516004e648a7bac7497c89b97",
|
build/web/index.html
CHANGED
@@ -156,7 +156,7 @@
|
|
156 |
</script>
|
157 |
|
158 |
<!-- Add version parameter for cache busting -->
|
159 |
-
<script src="flutter_bootstrap.js?v=
|
160 |
|
161 |
<!-- Add cache busting script -->
|
162 |
<script>
|
|
|
156 |
</script>
|
157 |
|
158 |
<!-- Add version parameter for cache busting -->
|
159 |
+
<script src="flutter_bootstrap.js?v=1746641479" async></script>
|
160 |
|
161 |
<!-- Add cache busting script -->
|
162 |
<script>
|
build/web/main.dart.js
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
lib/screens/video_screen.dart
CHANGED
@@ -444,7 +444,9 @@ class _VideoScreenState extends State<VideoScreen> {
|
|
444 |
)
|
445 |
: Column(
|
446 |
children: [
|
447 |
-
|
|
|
|
|
448 |
if (Configuration.instance.showChatInVideoView) ...[
|
449 |
const SizedBox(height: 16),
|
450 |
Expanded(
|
@@ -466,23 +468,27 @@ class _VideoScreenState extends State<VideoScreen> {
|
|
466 |
}
|
467 |
|
468 |
Widget _buildMainContent() {
|
469 |
-
return
|
470 |
-
|
471 |
-
child:
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
|
|
|
|
|
|
482 |
|
483 |
-
|
484 |
-
|
485 |
-
|
|
|
486 |
),
|
487 |
);
|
488 |
}
|
|
|
444 |
)
|
445 |
: Column(
|
446 |
children: [
|
447 |
+
Expanded(
|
448 |
+
child: _buildMainContent(),
|
449 |
+
),
|
450 |
if (Configuration.instance.showChatInVideoView) ...[
|
451 |
const SizedBox(height: 16),
|
452 |
Expanded(
|
|
|
468 |
}
|
469 |
|
470 |
Widget _buildMainContent() {
|
471 |
+
return Container(
|
472 |
+
color: Theme.of(context).scaffoldBackgroundColor,
|
473 |
+
child: SingleChildScrollView(
|
474 |
+
padding: const EdgeInsets.all(16),
|
475 |
+
physics: const AlwaysScrollableScrollPhysics(),
|
476 |
+
child: Column(
|
477 |
+
crossAxisAlignment: CrossAxisAlignment.start,
|
478 |
+
children: [
|
479 |
+
// Video Player with unique key to force recreation when needed
|
480 |
+
VideoPlayerWidget(
|
481 |
+
key: _videoPlayerKey,
|
482 |
+
video: _videoData,
|
483 |
+
initialThumbnailUrl: _videoData.thumbnailUrl,
|
484 |
+
autoPlay: true,
|
485 |
+
),
|
486 |
+
const SizedBox(height: 16),
|
487 |
|
488 |
+
// Collapsible Title and Description Section
|
489 |
+
_buildCollapsibleInfoSection(),
|
490 |
+
],
|
491 |
+
),
|
492 |
),
|
493 |
);
|
494 |
}
|
lib/widgets/video_player/video_player_widget.dart
CHANGED
@@ -73,6 +73,12 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
|
|
73 |
|
74 |
/// Current orientation
|
75 |
VideoOrientation _currentOrientation = VideoOrientation.LANDSCAPE;
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
@override
|
78 |
void initState() {
|
@@ -134,11 +140,33 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
|
|
134 |
Future<void> _initializePlayer() async {
|
135 |
if (_isDisposed) return;
|
136 |
|
137 |
-
//
|
138 |
final mediaQuery = MediaQuery.of(context);
|
139 |
-
|
140 |
-
|
141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
|
143 |
_playbackController = PlaybackController();
|
144 |
_playbackController.isLoading = true;
|
@@ -160,6 +188,9 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
|
|
160 |
|
161 |
// Initialize buffer manager with current orientation
|
162 |
await _bufferManager.initialize();
|
|
|
|
|
|
|
163 |
}
|
164 |
|
165 |
if (!_isDisposed && mounted) {
|
@@ -272,8 +303,8 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
|
|
272 |
debugPrint('Error playing clip: $e');
|
273 |
if (!_isDisposed) {
|
274 |
if (!_isDisposed && mounted) {
|
275 |
-
|
276 |
-
|
277 |
await Future.delayed(const Duration(milliseconds: 500));
|
278 |
}
|
279 |
}
|
@@ -366,35 +397,41 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
|
|
366 |
// Dispose controllers and timers
|
367 |
_playbackController.dispose();
|
368 |
_bufferManager.dispose();
|
|
|
369 |
|
370 |
super.dispose();
|
371 |
}
|
372 |
|
373 |
@override
|
374 |
Widget build(BuildContext context) {
|
|
|
|
|
|
|
|
|
|
|
375 |
return LayoutBuilder(
|
376 |
builder: (context, constraints) {
|
377 |
-
// Determine orientation based on
|
378 |
-
// This
|
379 |
VideoOrientation newOrientation;
|
380 |
|
381 |
-
if (kIsWeb
|
382 |
-
//
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
newOrientation =
|
391 |
-
} else
|
392 |
-
|
393 |
newOrientation = _currentOrientation;
|
394 |
}
|
395 |
} else {
|
396 |
-
// For mobile platforms, use the device orientation
|
397 |
-
final orientation =
|
398 |
newOrientation = orientation == Orientation.landscape
|
399 |
? VideoOrientation.LANDSCAPE
|
400 |
: VideoOrientation.PORTRAIT;
|
@@ -402,21 +439,87 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
|
|
402 |
|
403 |
// Check if orientation changed
|
404 |
if (newOrientation != _currentOrientation) {
|
405 |
-
|
406 |
-
|
|
|
407 |
|
408 |
-
//
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
414 |
}
|
415 |
|
416 |
// Video player layout
|
417 |
final controller = _playbackController.currentController;
|
418 |
final aspectRatio = controller?.value.aspectRatio ?? 16/9;
|
419 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
420 |
|
421 |
return SizedBox(
|
422 |
width: constraints.maxWidth,
|
|
|
73 |
|
74 |
/// Current orientation
|
75 |
VideoOrientation _currentOrientation = VideoOrientation.LANDSCAPE;
|
76 |
+
|
77 |
+
/// Last time orientation was changed
|
78 |
+
DateTime _lastOrientationChange = DateTime.now();
|
79 |
+
|
80 |
+
/// Timer for debouncing orientation changes
|
81 |
+
Timer? _orientationDebounceTimer;
|
82 |
|
83 |
@override
|
84 |
void initState() {
|
|
|
140 |
Future<void> _initializePlayer() async {
|
141 |
if (_isDisposed) return;
|
142 |
|
143 |
+
// Determine initial orientation based on platform
|
144 |
final mediaQuery = MediaQuery.of(context);
|
145 |
+
if (kIsWeb) {
|
146 |
+
// For web, use screen dimensions to determine initial orientation
|
147 |
+
final screenWidth = mediaQuery.size.width;
|
148 |
+
final screenHeight = mediaQuery.size.height;
|
149 |
+
final aspectRatio = screenWidth / screenHeight;
|
150 |
+
|
151 |
+
// debugPrint('Initial screen size: ${screenWidth.toInt()}x${screenHeight.toInt()}, aspect ratio: ${aspectRatio.toStringAsFixed(2)}');
|
152 |
+
|
153 |
+
// Set initial orientation based on aspect ratio
|
154 |
+
if (aspectRatio > 1.2) {
|
155 |
+
_currentOrientation = VideoOrientation.LANDSCAPE;
|
156 |
+
} else if (aspectRatio < 0.8) {
|
157 |
+
_currentOrientation = VideoOrientation.PORTRAIT;
|
158 |
+
} else {
|
159 |
+
// Default to landscape for square-ish windows
|
160 |
+
_currentOrientation = VideoOrientation.LANDSCAPE;
|
161 |
+
}
|
162 |
+
|
163 |
+
// debugPrint('Initial orientation set to: ${_currentOrientation.name}');
|
164 |
+
} else {
|
165 |
+
// For mobile, use device orientation
|
166 |
+
_currentOrientation = mediaQuery.orientation == Orientation.landscape
|
167 |
+
? VideoOrientation.LANDSCAPE
|
168 |
+
: VideoOrientation.PORTRAIT;
|
169 |
+
}
|
170 |
|
171 |
_playbackController = PlaybackController();
|
172 |
_playbackController.isLoading = true;
|
|
|
188 |
|
189 |
// Initialize buffer manager with current orientation
|
190 |
await _bufferManager.initialize();
|
191 |
+
|
192 |
+
// Update orientation after initialization
|
193 |
+
await _bufferManager.updateOrientation(_currentOrientation);
|
194 |
}
|
195 |
|
196 |
if (!_isDisposed && mounted) {
|
|
|
303 |
debugPrint('Error playing clip: $e');
|
304 |
if (!_isDisposed) {
|
305 |
if (!_isDisposed && mounted) {
|
306 |
+
setState(() => _playbackController.isLoading = true);
|
307 |
+
}
|
308 |
await Future.delayed(const Duration(milliseconds: 500));
|
309 |
}
|
310 |
}
|
|
|
397 |
// Dispose controllers and timers
|
398 |
_playbackController.dispose();
|
399 |
_bufferManager.dispose();
|
400 |
+
_orientationDebounceTimer?.cancel();
|
401 |
|
402 |
super.dispose();
|
403 |
}
|
404 |
|
405 |
@override
|
406 |
Widget build(BuildContext context) {
|
407 |
+
// Get the actual screen/window dimensions from MediaQuery
|
408 |
+
final mediaQuery = MediaQuery.of(context);
|
409 |
+
final screenWidth = mediaQuery.size.width;
|
410 |
+
final screenHeight = mediaQuery.size.height;
|
411 |
+
|
412 |
return LayoutBuilder(
|
413 |
builder: (context, constraints) {
|
414 |
+
// Determine orientation based on the screen dimensions rather than the constraints
|
415 |
+
// This avoids issues with infinite heights in ScrollViews
|
416 |
VideoOrientation newOrientation;
|
417 |
|
418 |
+
if (kIsWeb) {
|
419 |
+
// Use the screen dimensions to determine orientation
|
420 |
+
// This is more reliable than constraints in scrollable containers
|
421 |
+
double aspectRatio = screenWidth / screenHeight;
|
422 |
+
// debugPrint('Screen size: ${screenWidth.toInt()}x${screenHeight.toInt()}, aspect ratio: ${aspectRatio.toStringAsFixed(2)}');
|
423 |
|
424 |
+
if (aspectRatio > 1.2) {
|
425 |
+
newOrientation = VideoOrientation.LANDSCAPE;
|
426 |
+
} else if (aspectRatio < 0.8) {
|
427 |
+
newOrientation = VideoOrientation.PORTRAIT;
|
428 |
+
} else {
|
429 |
+
// In middle zone (near square), maintain current orientation for stability
|
430 |
newOrientation = _currentOrientation;
|
431 |
}
|
432 |
} else {
|
433 |
+
// For mobile platforms, still use the device orientation
|
434 |
+
final orientation = mediaQuery.orientation;
|
435 |
newOrientation = orientation == Orientation.landscape
|
436 |
? VideoOrientation.LANDSCAPE
|
437 |
: VideoOrientation.PORTRAIT;
|
|
|
439 |
|
440 |
// Check if orientation changed
|
441 |
if (newOrientation != _currentOrientation) {
|
442 |
+
// Ensure we don't change orientation too frequently
|
443 |
+
final now = DateTime.now();
|
444 |
+
final timeSinceLastChange = now.difference(_lastOrientationChange);
|
445 |
|
446 |
+
// Debug log the orientation change request with more details
|
447 |
+
// debugPrint('Orientation change request: ${_currentOrientation.name} -> ${newOrientation.name}');
|
448 |
+
// debugPrint(' • Current orientation: ${_currentOrientation.name}');
|
449 |
+
// debugPrint(' • New orientation: ${newOrientation.name}');
|
450 |
+
// debugPrint(' • Screen size: ${screenWidth.toInt()}x${screenHeight.toInt()}');
|
451 |
+
// debugPrint(' • Aspect ratio: ${(screenWidth / screenHeight).toStringAsFixed(2)}');
|
452 |
+
// debugPrint(' • Time since last change: ${timeSinceLastChange.inMilliseconds}ms');
|
453 |
+
|
454 |
+
// Cancel any pending orientation change
|
455 |
+
_orientationDebounceTimer?.cancel();
|
456 |
+
|
457 |
+
if (timeSinceLastChange.inMilliseconds >= 500) {
|
458 |
+
// debugPrint('Applying immediate orientation change to ${newOrientation.name}');
|
459 |
+
|
460 |
+
// Force immediate orientation change
|
461 |
+
setState(() {
|
462 |
+
_currentOrientation = newOrientation;
|
463 |
+
_lastOrientationChange = now;
|
464 |
+
});
|
465 |
+
|
466 |
+
// Update buffer manager orientation
|
467 |
+
_bufferManager.updateOrientation(newOrientation);
|
468 |
+
} else {
|
469 |
+
// For recent changes, set a short timer to check if the orientation remains stable
|
470 |
+
_orientationDebounceTimer = Timer(const Duration(milliseconds: 800), () {
|
471 |
+
if (!_isDisposed && mounted) {
|
472 |
+
// Get the latest screen dimensions
|
473 |
+
final latestMediaQuery = MediaQuery.of(context);
|
474 |
+
final latestWidth = latestMediaQuery.size.width;
|
475 |
+
final latestHeight = latestMediaQuery.size.height;
|
476 |
+
final latestAspectRatio = latestWidth / latestHeight;
|
477 |
+
|
478 |
+
// debugPrint('Delayed check - screen size: ${latestWidth.toInt()}x${latestHeight.toInt()}, ratio: ${latestAspectRatio.toStringAsFixed(2)}');
|
479 |
+
|
480 |
+
// Determine if the orientation is still requesting the same change
|
481 |
+
VideoOrientation latestOrientation;
|
482 |
+
if (latestAspectRatio > 1.2) {
|
483 |
+
latestOrientation = VideoOrientation.LANDSCAPE;
|
484 |
+
} else if (latestAspectRatio < 0.8) {
|
485 |
+
latestOrientation = VideoOrientation.PORTRAIT;
|
486 |
+
} else {
|
487 |
+
latestOrientation = _currentOrientation;
|
488 |
+
}
|
489 |
+
|
490 |
+
// Only apply the change if the orientation is still the same as requested
|
491 |
+
if (latestOrientation == newOrientation && _currentOrientation != newOrientation) {
|
492 |
+
// debugPrint('Applying delayed orientation change to ${newOrientation.name}');
|
493 |
+
|
494 |
+
if (!_isDisposed && mounted) {
|
495 |
+
setState(() {
|
496 |
+
_currentOrientation = newOrientation;
|
497 |
+
_lastOrientationChange = DateTime.now();
|
498 |
+
});
|
499 |
+
|
500 |
+
// Update buffer manager orientation
|
501 |
+
_bufferManager.updateOrientation(newOrientation);
|
502 |
+
}
|
503 |
+
}
|
504 |
+
}
|
505 |
+
});
|
506 |
+
}
|
507 |
}
|
508 |
|
509 |
// Video player layout
|
510 |
final controller = _playbackController.currentController;
|
511 |
final aspectRatio = controller?.value.aspectRatio ?? 16/9;
|
512 |
+
|
513 |
+
// Calculate player height based on the available width from constraints
|
514 |
+
// (which will be finite in the row/column layout)
|
515 |
+
double playerHeight = constraints.maxWidth / aspectRatio;
|
516 |
+
|
517 |
+
// Safety check - if width was somehow infinite or the result is invalid
|
518 |
+
if (!constraints.maxWidth.isFinite || !playerHeight.isFinite) {
|
519 |
+
// Use a percentage of screen height as fallback
|
520 |
+
playerHeight = screenHeight * 0.4;
|
521 |
+
debugPrint('Using fallback height: $playerHeight (percentage of screen height)');
|
522 |
+
}
|
523 |
|
524 |
return SizedBox(
|
525 |
width: constraints.maxWidth,
|