jbilcke-hf HF Staff commited on
Commit
8d1d1b5
·
1 Parent(s): cc8c83c

debugigng the simulation loop

Browse files
assets/config/tikslop.yaml CHANGED
@@ -1,6 +1,6 @@
1
  ui:
2
  product_name: "#tikslop"
3
- showChatInVideoView: false
4
 
5
  render_queue:
6
  # how many clips should be stored in advance
@@ -21,9 +21,12 @@ advertising:
21
  link: https://huggingface.co/docs/smolagents/index
22
 
23
  simulation:
 
 
 
24
  # how often the description should evolve (in seconds)
25
  # setting to 0 disables description evolution
26
- sim_loop_frequency_in_sec: 10
27
 
28
  # it's OK to use high values here,
29
  # because some of those values are limited by the backend config,
 
1
  ui:
2
  product_name: "#tikslop"
3
+ showChatInVideoView: true
4
 
5
  render_queue:
6
  # how many clips should be stored in advance
 
21
  link: https://huggingface.co/docs/smolagents/index
22
 
23
  simulation:
24
+ # whether to enable simulation loop to evolve descriptions over time
25
+ enable_sim_loop: true
26
+
27
  # how often the description should evolve (in seconds)
28
  # setting to 0 disables description evolution
29
+ sim_loop_frequency_in_sec: 8
30
 
31
  # it's OK to use high values here,
32
  # because some of those values are limited by the backend config,
build/web/assets/assets/config/tikslop.yaml CHANGED
@@ -1,6 +1,6 @@
1
  ui:
2
  product_name: "#tikslop"
3
- showChatInVideoView: false
4
 
5
  render_queue:
6
  # how many clips should be stored in advance
@@ -21,9 +21,12 @@ advertising:
21
  link: https://huggingface.co/docs/smolagents/index
22
 
23
  simulation:
 
 
 
24
  # how often the description should evolve (in seconds)
25
  # setting to 0 disables description evolution
26
- sim_loop_frequency_in_sec: 10
27
 
28
  # it's OK to use high values here,
29
  # because some of those values are limited by the backend config,
 
1
  ui:
2
  product_name: "#tikslop"
3
+ showChatInVideoView: true
4
 
5
  render_queue:
6
  # how many clips should be stored in advance
 
21
  link: https://huggingface.co/docs/smolagents/index
22
 
23
  simulation:
24
+ # whether to enable simulation loop to evolve descriptions over time
25
+ enable_sim_loop: true
26
+
27
  # how often the description should evolve (in seconds)
28
  # setting to 0 disables description evolution
29
+ sim_loop_frequency_in_sec: 8
30
 
31
  # it's OK to use high values here,
32
  # because some of those values are limited by the backend config,
build/web/flutter_bootstrap.js CHANGED
@@ -39,6 +39,6 @@ _flutter.buildConfig = {"engineRevision":"382be0028d370607f76215a9be322e5514b263
39
 
40
  _flutter.loader.load({
41
  serviceWorkerSettings: {
42
- serviceWorkerVersion: "754772620"
43
  }
44
  });
 
39
 
40
  _flutter.loader.load({
41
  serviceWorkerSettings: {
42
+ serviceWorkerVersion: "2278791886"
43
  }
44
  });
build/web/flutter_service_worker.js CHANGED
@@ -3,12 +3,12 @@ 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": "04ff3a8576d911a2f01466a30986bd48",
7
  "version.json": "68350cac7987de2728345c72918dd067",
8
  "tikslop.png": "570e1db759046e2d224fef729983634e",
9
  "index.html": "3a7029b3672560e7938aab6fa4d30a46",
10
  "/": "3a7029b3672560e7938aab6fa4d30a46",
11
- "main.dart.js": "44d4476ea7e6f9159320973c3d29cbc3",
12
  "tikslop.svg": "26140ba0d153b213b122bc6ebcc17f6c",
13
  "flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
14
  "favicon.png": "c8a183c516004e648a7bac7497c89b97",
@@ -31,7 +31,7 @@ const RESOURCES = {"flutter_bootstrap.js": "04ff3a8576d911a2f01466a30986bd48",
31
  "assets/assets/config/README.md": "07a87720dd00dd1ca98c9d6884440e31",
32
  "assets/assets/config/custom.yaml": "52bd30aa4d8b980626a5eb02d0871c01",
33
  "assets/assets/config/default.yaml": "9ca1d05d06721c2b6f6382a1ba40af48",
34
- "assets/assets/config/tikslop.yaml": "1165218a000aa0c9841e88b072e40756",
35
  "canvaskit/skwasm.js": "ea559890a088fe28b4ddf70e17e60052",
36
  "canvaskit/skwasm.js.symbols": "9fe690d47b904d72c7d020bd303adf16",
37
  "canvaskit/canvaskit.js.symbols": "27361387bc24144b46a745f1afe92b50",
 
3
  const TEMP = 'flutter-temp-cache';
4
  const CACHE_NAME = 'flutter-app-cache';
5
 
6
+ const RESOURCES = {"flutter_bootstrap.js": "c711e457cccbe0bcbccc12f740ac44af",
7
  "version.json": "68350cac7987de2728345c72918dd067",
8
  "tikslop.png": "570e1db759046e2d224fef729983634e",
9
  "index.html": "3a7029b3672560e7938aab6fa4d30a46",
10
  "/": "3a7029b3672560e7938aab6fa4d30a46",
11
+ "main.dart.js": "494e091a049a511f985f81a61cedf669",
12
  "tikslop.svg": "26140ba0d153b213b122bc6ebcc17f6c",
13
  "flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
14
  "favicon.png": "c8a183c516004e648a7bac7497c89b97",
 
31
  "assets/assets/config/README.md": "07a87720dd00dd1ca98c9d6884440e31",
32
  "assets/assets/config/custom.yaml": "52bd30aa4d8b980626a5eb02d0871c01",
33
  "assets/assets/config/default.yaml": "9ca1d05d06721c2b6f6382a1ba40af48",
34
+ "assets/assets/config/tikslop.yaml": "45d535b24df6e81ce983bf4f550c9be7",
35
  "canvaskit/skwasm.js": "ea559890a088fe28b4ddf70e17e60052",
36
  "canvaskit/skwasm.js.symbols": "9fe690d47b904d72c7d020bd303adf16",
37
  "canvaskit/canvaskit.js.symbols": "27361387bc24144b46a745f1afe92b50",
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=1747155709" async></script>
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=1747395579" 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/config/config.dart CHANGED
@@ -129,6 +129,9 @@ class Configuration {
129
  _config['video']['default_negative_prompt'] ?? 'captions, subtitles, logo, text, watermark, low quality, worst quality, gore, sex, blood, nudity, nude, porn, erotic';
130
 
131
  // Simulation settings
 
 
 
132
  int get simLoopFrequencyInSec =>
133
  _config['simulation']?['sim_loop_frequency_in_sec'] ?? 0;
134
 
 
129
  _config['video']['default_negative_prompt'] ?? 'captions, subtitles, logo, text, watermark, low quality, worst quality, gore, sex, blood, nudity, nude, porn, erotic';
130
 
131
  // Simulation settings
132
+ bool get enableSimLoop =>
133
+ _config['simulation']?['enable_sim_loop'] ?? true;
134
+
135
  int get simLoopFrequencyInSec =>
136
  _config['simulation']?['sim_loop_frequency_in_sec'] ?? 0;
137
 
lib/screens/settings_screen.dart CHANGED
@@ -15,6 +15,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
15
  final _negativePromptController = TextEditingController();
16
  final _hfApiKeyController = TextEditingController();
17
  final _settingsService = SettingsService();
 
 
18
 
19
  @override
20
  void initState() {
@@ -22,6 +24,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
22
  _promptController.text = _settingsService.videoPromptPrefix;
23
  _negativePromptController.text = _settingsService.negativeVideoPrompt;
24
  _hfApiKeyController.text = _settingsService.huggingfaceApiKey;
 
 
25
  }
26
 
27
  @override
@@ -161,6 +165,49 @@ class _SettingsScreenState extends State<SettingsScreen> {
161
  ),
162
  ),
163
  const SizedBox(height: 16),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  // Custom Video Model Card
165
  Card(
166
  child: Padding(
 
15
  final _negativePromptController = TextEditingController();
16
  final _hfApiKeyController = TextEditingController();
17
  final _settingsService = SettingsService();
18
+ bool _showSceneDebugInfo = false;
19
+ bool _enableSimulation = true;
20
 
21
  @override
22
  void initState() {
 
24
  _promptController.text = _settingsService.videoPromptPrefix;
25
  _negativePromptController.text = _settingsService.negativeVideoPrompt;
26
  _hfApiKeyController.text = _settingsService.huggingfaceApiKey;
27
+ _showSceneDebugInfo = _settingsService.showSceneDebugInfo;
28
+ _enableSimulation = _settingsService.enableSimulation;
29
  }
30
 
31
  @override
 
165
  ),
166
  ),
167
  const SizedBox(height: 16),
168
+ // Display Options Card
169
+ Card(
170
+ child: Padding(
171
+ padding: const EdgeInsets.all(16),
172
+ child: Column(
173
+ crossAxisAlignment: CrossAxisAlignment.start,
174
+ children: [
175
+ const Text(
176
+ 'Display Options',
177
+ style: TextStyle(
178
+ color: TikSlopColors.onBackground,
179
+ fontSize: 20,
180
+ fontWeight: FontWeight.bold,
181
+ ),
182
+ ),
183
+ const SizedBox(height: 16),
184
+ SwitchListTile(
185
+ title: const Text('Show scene debug information'),
186
+ subtitle: const Text('Display initial, current, and last description in video view'),
187
+ value: _showSceneDebugInfo,
188
+ onChanged: (value) {
189
+ setState(() {
190
+ _showSceneDebugInfo = value;
191
+ });
192
+ _settingsService.setShowSceneDebugInfo(value);
193
+ },
194
+ ),
195
+ SwitchListTile(
196
+ title: const Text('Enable simulation'),
197
+ subtitle: const Text('Allow video descriptions to evolve over time'),
198
+ value: _enableSimulation,
199
+ onChanged: (value) {
200
+ setState(() {
201
+ _enableSimulation = value;
202
+ });
203
+ _settingsService.setEnableSimulation(value);
204
+ },
205
+ ),
206
+ ],
207
+ ),
208
+ ),
209
+ ),
210
+ const SizedBox(height: 16),
211
  // Custom Video Model Card
212
  Card(
213
  child: Padding(
lib/screens/video_screen.dart CHANGED
@@ -1,5 +1,6 @@
1
  // lib/screens/video_screen.dart
2
  import 'dart:async';
 
3
 
4
  import 'package:tikslop/screens/home_screen.dart';
5
  import 'package:tikslop/widgets/chat_widget.dart';
@@ -39,6 +40,9 @@ class _VideoScreenState extends State<VideoScreen> {
39
  // Subscription for limit statuses
40
  StreamSubscription? _anonLimitSubscription;
41
  StreamSubscription? _deviceLimitSubscription;
 
 
 
42
 
43
  @override
44
  void initState() {
@@ -484,6 +488,19 @@ class _VideoScreenState extends State<VideoScreen> {
484
  video: _videoData,
485
  initialThumbnailUrl: _videoData.thumbnailUrl,
486
  autoPlay: true,
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  ),
488
  const SizedBox(height: 16),
489
 
@@ -496,6 +513,10 @@ class _VideoScreenState extends State<VideoScreen> {
496
  }
497
 
498
  Widget _buildCollapsibleInfoSection() {
 
 
 
 
499
  return ExpansionTile(
500
  initiallyExpanded: false,
501
  tilePadding: EdgeInsets.zero,
@@ -526,16 +547,85 @@ class _VideoScreenState extends State<VideoScreen> {
526
  Column(
527
  crossAxisAlignment: CrossAxisAlignment.start,
528
  children: [
529
- // Description Section
530
- const SizedBox(height: 8),
531
- Text(
532
- _videoData.description,
533
- style: const TextStyle(
534
- color: TikSlopColors.onSurface,
535
- height: 1.5,
 
 
536
  ),
537
- ),
538
- const SizedBox(height: 8),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  ],
540
  ),
541
  ],
 
1
  // lib/screens/video_screen.dart
2
  import 'dart:async';
3
+ import 'dart:math' as math;
4
 
5
  import 'package:tikslop/screens/home_screen.dart';
6
  import 'package:tikslop/widgets/chat_widget.dart';
 
40
  // Subscription for limit statuses
41
  StreamSubscription? _anonLimitSubscription;
42
  StreamSubscription? _deviceLimitSubscription;
43
+
44
+ // Reference to access video player's buffer manager for simulation updates
45
+ StreamSubscription? _videoUpdateSubscription;
46
 
47
  @override
48
  void initState() {
 
488
  video: _videoData,
489
  initialThumbnailUrl: _videoData.thumbnailUrl,
490
  autoPlay: true,
491
+ onVideoUpdated: (updatedVideo) {
492
+ debugPrint('VIDEO_SCREEN: Received updated video data');
493
+ if (updatedVideo.evolvedDescription.isNotEmpty) {
494
+ debugPrint('VIDEO_SCREEN: Evolved description (${updatedVideo.evolvedDescription.length} chars)');
495
+ debugPrint('VIDEO_SCREEN: First 100 chars: ${updatedVideo.evolvedDescription.substring(0, math.min(100, updatedVideo.evolvedDescription.length))}...');
496
+ } else {
497
+ debugPrint('VIDEO_SCREEN: No evolved description received');
498
+ }
499
+
500
+ setState(() {
501
+ _videoData = updatedVideo;
502
+ });
503
+ },
504
  ),
505
  const SizedBox(height: 16),
506
 
 
513
  }
514
 
515
  Widget _buildCollapsibleInfoSection() {
516
+ // Get settings service to check if debug info should be shown
517
+ final settingsService = SettingsService();
518
+ final showDebugInfo = settingsService.showSceneDebugInfo;
519
+
520
  return ExpansionTile(
521
  initiallyExpanded: false,
522
  tilePadding: EdgeInsets.zero,
 
547
  Column(
548
  crossAxisAlignment: CrossAxisAlignment.start,
549
  children: [
550
+ // Regular Description Section
551
+ if (!showDebugInfo) ...[
552
+ const SizedBox(height: 8),
553
+ Text(
554
+ _videoData.description,
555
+ style: const TextStyle(
556
+ color: TikSlopColors.onSurface,
557
+ height: 1.5,
558
+ ),
559
  ),
560
+ const SizedBox(height: 8),
561
+ ],
562
+
563
+ // Debug Information (when enabled)
564
+ if (showDebugInfo) ...[
565
+ const SizedBox(height: 16),
566
+ const Text(
567
+ 'Initial Description:',
568
+ style: TextStyle(
569
+ color: TikSlopColors.primary,
570
+ fontWeight: FontWeight.bold,
571
+ fontSize: 14,
572
+ ),
573
+ ),
574
+ const SizedBox(height: 4),
575
+ Text(
576
+ _videoData.description,
577
+ style: const TextStyle(
578
+ color: TikSlopColors.onSurface,
579
+ height: 1.5,
580
+ fontSize: 13,
581
+ ),
582
+ ),
583
+ const SizedBox(height: 16),
584
+
585
+ // Current Description (Evolved Description) Section
586
+ const Text(
587
+ 'Current Description:',
588
+ style: TextStyle(
589
+ color: TikSlopColors.primary,
590
+ fontWeight: FontWeight.bold,
591
+ fontSize: 14,
592
+ ),
593
+ ),
594
+ const SizedBox(height: 4),
595
+ Text(
596
+ _videoData.evolvedDescription.isNotEmpty
597
+ ? _videoData.evolvedDescription
598
+ : _videoData.description, // If evolved description is empty, show initial
599
+ style: const TextStyle(
600
+ color: TikSlopColors.onSurface,
601
+ height: 1.5,
602
+ fontSize: 13,
603
+ ),
604
+ ),
605
+ const SizedBox(height: 16),
606
+
607
+ // Condensed History (Last Description) Section
608
+ const Text(
609
+ 'Last Description:',
610
+ style: TextStyle(
611
+ color: TikSlopColors.primary,
612
+ fontWeight: FontWeight.bold,
613
+ fontSize: 14,
614
+ ),
615
+ ),
616
+ const SizedBox(height: 4),
617
+ Text(
618
+ _videoData.condensedHistory.isNotEmpty
619
+ ? _videoData.condensedHistory
620
+ : "No history available yet", // Show message if no history
621
+ style: const TextStyle(
622
+ color: TikSlopColors.onSurface,
623
+ height: 1.5,
624
+ fontSize: 13,
625
+ ),
626
+ ),
627
+ const SizedBox(height: 8),
628
+ ],
629
  ],
630
  ),
631
  ],
lib/services/clip_queue/clip_queue_manager.dart CHANGED
@@ -1,7 +1,7 @@
1
  // lib/services/clip_queue/clip_queue_manager.dart
2
 
3
  import 'dart:async';
4
- import 'dart:math';
5
  import 'package:tikslop/config/config.dart';
6
  import 'package:flutter/foundation.dart';
7
  import 'package:collection/collection.dart';
@@ -10,6 +10,7 @@ import '../../models/video_orientation.dart';
10
  import '../../models/chat_message.dart';
11
  import '../websocket_api_service.dart';
12
  import '../chat_service.dart';
 
13
  import '../../utils/seed.dart';
14
  import 'clip_states.dart';
15
  import 'video_clip.dart';
@@ -65,6 +66,12 @@ class ClipQueueManager {
65
 
66
  /// Recent chat messages to include in description evolution
67
  final List<ChatMessage> _recentChatMessages = [];
 
 
 
 
 
 
68
 
69
  /// Constructor
70
  ClipQueueManager({
@@ -213,12 +220,25 @@ class ClipQueueManager {
213
  // Cancel any existing timer
214
  _descriptionEvolutionTimer?.cancel();
215
 
216
- // Only start if simulation frequency is greater than 0
 
 
 
 
 
 
 
 
 
 
217
  if (Configuration.instance.simLoopFrequencyInSec <= 0) {
 
218
  ClipQueueConstants.logEvent('Simulation disabled (frequency is 0)');
219
  return;
220
  }
221
 
 
 
222
  // Adaptive check interval - less frequent checks to reduce overhead
223
  final checkInterval = max(3, Configuration.instance.simLoopFrequencyInSec ~/ 3);
224
 
@@ -228,30 +248,41 @@ class ClipQueueManager {
228
  _descriptionEvolutionTimer = Timer.periodic(
229
  Duration(seconds: checkInterval),
230
  (timer) async {
231
- if (_isDisposed) return;
 
 
 
 
232
 
233
  // Skip if simulation is paused (due to video playback being paused)
234
  if (_isSimulationPaused) {
 
235
  ClipQueueConstants.logEvent('Skipping simulation because it is paused');
236
  return;
237
  }
238
 
239
- // Check if we're currently generating a video - if so, delay simulation
 
240
  final isGenerating = _activeGenerations.isNotEmpty;
241
  if (isGenerating) {
242
- ClipQueueConstants.logEvent('Delaying simulation due to active generations');
243
- return;
 
244
  }
245
 
246
  // Calculate time since last simulation
247
  final now = DateTime.now();
248
  final duration = now.difference(_lastDescriptionEvolutionTime);
 
249
 
250
  // If we've waited long enough, simulate the video
251
  if (duration.inSeconds >= Configuration.instance.simLoopFrequencyInSec) {
 
252
  ClipQueueConstants.logEvent('Triggering simulation after ${duration.inSeconds} seconds');
253
  await _evolveDescription();
254
  _lastDescriptionEvolutionTime = now;
 
 
255
  }
256
  },
257
  );
@@ -260,13 +291,16 @@ class ClipQueueManager {
260
 
261
  /// Simulate the video by evolving the description using the LLM
262
  Future<void> _evolveDescription() async {
 
263
  if (!_websocketService.isConnected) {
 
264
  ClipQueueConstants.logEvent('Cannot simulate video: websocket not connected');
265
  return;
266
  }
267
 
268
  int retryCount = 0;
269
  const maxRetries = 2;
 
270
 
271
  // Function to get chat message string
272
  String getChatMessagesString() {
@@ -297,13 +331,25 @@ class ClipQueueManager {
297
  );
298
 
299
  // Update the video with the evolved description
 
 
 
 
 
 
300
  video = video.copyWith(
301
- evolvedDescription: result['evolved_description'],
302
- condensedHistory: result['condensed_history'],
303
  );
304
 
305
  _evolutionCounter++;
 
306
  ClipQueueConstants.logEvent('Video simulated (iteration $_evolutionCounter)');
 
 
 
 
 
307
  onQueueUpdated?.call();
308
 
309
  // Success, exit retry loop
@@ -658,6 +704,9 @@ class ClipQueueManager {
658
  _websocketService.cancelRequestsForVideo(videoId);
659
  }
660
 
 
 
 
661
  // Clear all collections
662
  _clipBuffer.clear();
663
  _clipHistory.clear();
 
1
  // lib/services/clip_queue/clip_queue_manager.dart
2
 
3
  import 'dart:async';
4
+ import 'dart:math' show max, min;
5
  import 'package:tikslop/config/config.dart';
6
  import 'package:flutter/foundation.dart';
7
  import 'package:collection/collection.dart';
 
10
  import '../../models/chat_message.dart';
11
  import '../websocket_api_service.dart';
12
  import '../chat_service.dart';
13
+ import '../settings_service.dart';
14
  import '../../utils/seed.dart';
15
  import 'clip_states.dart';
16
  import 'video_clip.dart';
 
66
 
67
  /// Recent chat messages to include in description evolution
68
  final List<ChatMessage> _recentChatMessages = [];
69
+
70
+ /// Stream controller for video updates (evolved descriptions)
71
+ final StreamController<VideoResult> _videoUpdateController = StreamController<VideoResult>.broadcast();
72
+
73
+ /// Stream of video updates for subscribers
74
+ Stream<VideoResult> get videoUpdateStream => _videoUpdateController.stream;
75
 
76
  /// Constructor
77
  ClipQueueManager({
 
220
  // Cancel any existing timer
221
  _descriptionEvolutionTimer?.cancel();
222
 
223
+ // Check if simulation is enabled globally in config and from user settings
224
+ final settingsService = SettingsService();
225
+ final isSimulationEnabled = Configuration.instance.enableSimLoop && settingsService.enableSimulation;
226
+
227
+ // Only start if simulation is enabled and frequency is greater than 0
228
+ if (!isSimulationEnabled) {
229
+ debugPrint('SIMULATION: Disabled (enable_sim_loop is false)');
230
+ ClipQueueConstants.logEvent('Simulation disabled (enable_sim_loop is false)');
231
+ return;
232
+ }
233
+
234
  if (Configuration.instance.simLoopFrequencyInSec <= 0) {
235
+ debugPrint('SIMULATION: Disabled (frequency is 0)');
236
  ClipQueueConstants.logEvent('Simulation disabled (frequency is 0)');
237
  return;
238
  }
239
 
240
+ debugPrint('SIMULATION: Starting simulation timer with settings: enableSimLoop=${Configuration.instance.enableSimLoop}, userSetting=${settingsService.enableSimulation}, frequency=${Configuration.instance.simLoopFrequencyInSec}s');
241
+
242
  // Adaptive check interval - less frequent checks to reduce overhead
243
  final checkInterval = max(3, Configuration.instance.simLoopFrequencyInSec ~/ 3);
244
 
 
248
  _descriptionEvolutionTimer = Timer.periodic(
249
  Duration(seconds: checkInterval),
250
  (timer) async {
251
+ debugPrint('SIMULATION: Timer check triggered');
252
+ if (_isDisposed) {
253
+ debugPrint('SIMULATION: Skipping because manager is disposed');
254
+ return;
255
+ }
256
 
257
  // Skip if simulation is paused (due to video playback being paused)
258
  if (_isSimulationPaused) {
259
+ debugPrint('SIMULATION: Skipping because it is paused');
260
  ClipQueueConstants.logEvent('Skipping simulation because it is paused');
261
  return;
262
  }
263
 
264
+ // We previously delayed simulation if clips were being generated,
265
+ // but since clip generation is constant, we'll now run them in parallel
266
  final isGenerating = _activeGenerations.isNotEmpty;
267
  if (isGenerating) {
268
+ debugPrint('SIMULATION: Continuing with simulation despite active generations');
269
+ ClipQueueConstants.logEvent('Running simulation in parallel with active generations');
270
+ // We no longer return early here
271
  }
272
 
273
  // Calculate time since last simulation
274
  final now = DateTime.now();
275
  final duration = now.difference(_lastDescriptionEvolutionTime);
276
+ debugPrint('SIMULATION: Time since last simulation: ${duration.inSeconds}s (frequency: ${Configuration.instance.simLoopFrequencyInSec}s)');
277
 
278
  // If we've waited long enough, simulate the video
279
  if (duration.inSeconds >= Configuration.instance.simLoopFrequencyInSec) {
280
+ debugPrint('SIMULATION: Triggering simulation after ${duration.inSeconds} seconds');
281
  ClipQueueConstants.logEvent('Triggering simulation after ${duration.inSeconds} seconds');
282
  await _evolveDescription();
283
  _lastDescriptionEvolutionTime = now;
284
+ } else {
285
+ debugPrint('SIMULATION: Not enough time elapsed since last simulation');
286
  }
287
  },
288
  );
 
291
 
292
  /// Simulate the video by evolving the description using the LLM
293
  Future<void> _evolveDescription() async {
294
+ debugPrint('SIMULATION: Starting description evolution');
295
  if (!_websocketService.isConnected) {
296
+ debugPrint('SIMULATION: Cannot simulate video - websocket not connected');
297
  ClipQueueConstants.logEvent('Cannot simulate video: websocket not connected');
298
  return;
299
  }
300
 
301
  int retryCount = 0;
302
  const maxRetries = 2;
303
+ debugPrint('SIMULATION: Current video state: title="${video.title}", evolvedDescription length=${video.evolvedDescription.length}, original description length=${video.description.length}');
304
 
305
  // Function to get chat message string
306
  String getChatMessagesString() {
 
331
  );
332
 
333
  // Update the video with the evolved description
334
+ final newEvolvedDescription = result['evolved_description'] as String;
335
+ final newCondensedHistory = result['condensed_history'] as String;
336
+
337
+ debugPrint('SIMULATION: Received evolved description (${newEvolvedDescription.length} chars)');
338
+ debugPrint('SIMULATION: First 100 chars: ${newEvolvedDescription.substring(0, min(100, newEvolvedDescription.length))}...');
339
+
340
  video = video.copyWith(
341
+ evolvedDescription: newEvolvedDescription,
342
+ condensedHistory: newCondensedHistory,
343
  );
344
 
345
  _evolutionCounter++;
346
+ debugPrint('SIMULATION: Video simulated (iteration $_evolutionCounter)');
347
  ClipQueueConstants.logEvent('Video simulated (iteration $_evolutionCounter)');
348
+
349
+ // Emit the updated video to the stream for subscribers
350
+ debugPrint('SIMULATION: Emitting updated video to stream');
351
+ _videoUpdateController.add(video);
352
+
353
  onQueueUpdated?.call();
354
 
355
  // Success, exit retry loop
 
704
  _websocketService.cancelRequestsForVideo(videoId);
705
  }
706
 
707
+ // Close stream controller
708
+ await _videoUpdateController.close();
709
+
710
  // Clear all collections
711
  _clipBuffer.clear();
712
  _clipHistory.clear();
lib/services/settings_service.dart CHANGED
@@ -7,6 +7,8 @@ class SettingsService {
7
  static const String _promptPrefixKey = 'video_prompt_prefix';
8
  static const String _hfApiKeyKey = 'huggingface_api_key';
9
  static const String _negativePromptKey = 'negative_video_prompt';
 
 
10
  static final SettingsService _instance = SettingsService._internal();
11
 
12
  factory SettingsService() => _instance;
@@ -41,6 +43,20 @@ class SettingsService {
41
  await _prefs.setString(_hfApiKeyKey, apiKey);
42
  _settingsController.add(null);
43
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  void dispose() {
46
  _settingsController.close();
 
7
  static const String _promptPrefixKey = 'video_prompt_prefix';
8
  static const String _hfApiKeyKey = 'huggingface_api_key';
9
  static const String _negativePromptKey = 'negative_video_prompt';
10
+ static const String _showSceneDebugInfoKey = 'show_scene_debug_info';
11
+ static const String _enableSimulationKey = 'enable_simulation';
12
  static final SettingsService _instance = SettingsService._internal();
13
 
14
  factory SettingsService() => _instance;
 
43
  await _prefs.setString(_hfApiKeyKey, apiKey);
44
  _settingsController.add(null);
45
  }
46
+
47
+ bool get showSceneDebugInfo => _prefs.getBool(_showSceneDebugInfoKey) ?? false;
48
+
49
+ Future<void> setShowSceneDebugInfo(bool value) async {
50
+ await _prefs.setBool(_showSceneDebugInfoKey, value);
51
+ _settingsController.add(null);
52
+ }
53
+
54
+ bool get enableSimulation => _prefs.getBool(_enableSimulationKey) ?? Configuration.instance.enableSimLoop;
55
+
56
+ Future<void> setEnableSimulation(bool value) async {
57
+ await _prefs.setBool(_enableSimulationKey, value);
58
+ _settingsController.add(null);
59
+ }
60
 
61
  void dispose() {
62
  _settingsController.close();
lib/services/websocket_api_service.dart CHANGED
@@ -1246,6 +1246,8 @@ class WebSocketApiService {
1246
  };
1247
  }
1248
 
 
 
1249
  try {
1250
  final response = await _sendRequest(
1251
  WebSocketRequest(
@@ -1264,12 +1266,18 @@ class WebSocketApiService {
1264
  );
1265
 
1266
  if (!response['success']) {
 
1267
  throw Exception(response['error'] ?? 'Simulation failed');
1268
  }
1269
 
 
 
 
 
 
1270
  return {
1271
- 'evolved_description': response['evolved_description'] as String? ?? currentDescription,
1272
- 'condensed_history': response['condensed_history'] as String? ?? condensedHistory
1273
  };
1274
  } catch (e) {
1275
  debugPrint('WebSocketApiService: Error simulating video: $e');
 
1246
  };
1247
  }
1248
 
1249
+ debugPrint('WebSocketApiService: Sending simulation request for video $videoId (evolution #$evolutionCount)');
1250
+
1251
  try {
1252
  final response = await _sendRequest(
1253
  WebSocketRequest(
 
1266
  );
1267
 
1268
  if (!response['success']) {
1269
+ debugPrint('WebSocketApiService: Simulation API returned error: ${response['error']}');
1270
  throw Exception(response['error'] ?? 'Simulation failed');
1271
  }
1272
 
1273
+ final evolvedDescription = response['evolved_description'] as String? ?? currentDescription;
1274
+ final newHistory = response['condensed_history'] as String? ?? condensedHistory;
1275
+
1276
+ debugPrint('WebSocketApiService: Simulation successful, received ${evolvedDescription.length} chars for evolved description');
1277
+
1278
  return {
1279
+ 'evolved_description': evolvedDescription,
1280
+ 'condensed_history': newHistory
1281
  };
1282
  } catch (e) {
1283
  debugPrint('WebSocketApiService: Error simulating video: $e');
lib/widgets/ad_banner.dart CHANGED
@@ -100,13 +100,13 @@ class _AdBannerState extends State<AdBanner> {
100
  onTap: () => _launchURL(_currentAd!['link'] ?? ''),
101
  child: Image.asset(
102
  _currentAd!['image'] ?? '',
103
- height: 64,
104
  fit: BoxFit.contain,
105
  errorBuilder: (context, error, stackTrace) {
106
  // If image fails to load, show a placeholder
107
  print('Error loading ad image: $error');
108
  return Container(
109
- height: 64,
110
  color: Colors.grey.withOpacity(0.1),
111
  child: const Center(child: Text('Ad')),
112
  );
 
100
  onTap: () => _launchURL(_currentAd!['link'] ?? ''),
101
  child: Image.asset(
102
  _currentAd!['image'] ?? '',
103
+ height: 80,
104
  fit: BoxFit.contain,
105
  errorBuilder: (context, error, stackTrace) {
106
  // If image fails to load, show a placeholder
107
  print('Error loading ad image: $error');
108
  return Container(
109
+ height: 80,
110
  color: Colors.grey.withOpacity(0.1),
111
  child: const Center(child: Text('Ad')),
112
  );
lib/widgets/video_player/video_player_widget.dart CHANGED
@@ -2,6 +2,7 @@
2
 
3
  import 'dart:async';
4
  import 'dart:math' as math;
 
5
  import 'dart:io' show Platform;
6
  import 'package:tikslop/config/config.dart';
7
  import 'package:flutter/material.dart';
@@ -43,6 +44,9 @@ class VideoPlayerWidget extends StatefulWidget {
43
 
44
  /// Callback when video is loaded
45
  final VoidCallback? onVideoLoaded;
 
 
 
46
 
47
  /// Constructor
48
  const VideoPlayerWidget({
@@ -52,6 +56,7 @@ class VideoPlayerWidget extends StatefulWidget {
52
  this.autoPlay = true,
53
  this.borderRadius = 12,
54
  this.onVideoLoaded,
 
55
  });
56
 
57
  @override
@@ -71,6 +76,9 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
71
  /// Whether playback was happening before going to background
72
  bool _wasPlayingBeforeBackground = false;
73
 
 
 
 
74
  /// Current orientation
75
  VideoOrientation _currentOrientation = VideoOrientation.LANDSCAPE;
76
 
@@ -205,6 +213,29 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
205
 
206
  // Update orientation after initialization
207
  await _bufferManager.updateOrientation(_currentOrientation);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
 
210
  if (!_isDisposed && mounted) {
@@ -420,6 +451,9 @@ class _VideoPlayerWidgetState extends State<VideoPlayerWidget> with WidgetsBindi
420
  // Unregister the observer
421
  WidgetsBinding.instance.removeObserver(this);
422
 
 
 
 
423
  // Dispose controllers and timers
424
  _playbackController.dispose();
425
  _bufferManager.dispose();
 
2
 
3
  import 'dart:async';
4
  import 'dart:math' as math;
5
+ import 'dart:math' show min;
6
  import 'dart:io' show Platform;
7
  import 'package:tikslop/config/config.dart';
8
  import 'package:flutter/material.dart';
 
44
 
45
  /// Callback when video is loaded
46
  final VoidCallback? onVideoLoaded;
47
+
48
+ /// Callback when video data is updated (for simulation updates)
49
+ final Function(VideoResult updatedVideo)? onVideoUpdated;
50
 
51
  /// Constructor
52
  const VideoPlayerWidget({
 
56
  this.autoPlay = true,
57
  this.borderRadius = 12,
58
  this.onVideoLoaded,
59
+ this.onVideoUpdated,
60
  });
61
 
62
  @override
 
76
  /// Whether playback was happening before going to background
77
  bool _wasPlayingBeforeBackground = false;
78
 
79
+ /// Subscription to video update stream
80
+ StreamSubscription? _videoUpdateSubscription;
81
+
82
  /// Current orientation
83
  VideoOrientation _currentOrientation = VideoOrientation.LANDSCAPE;
84
 
 
213
 
214
  // Update orientation after initialization
215
  await _bufferManager.updateOrientation(_currentOrientation);
216
+
217
+ // Subscribe to video updates
218
+ _videoUpdateSubscription = _bufferManager.queueManager.videoUpdateStream.listen((updatedVideo) {
219
+ if (!_isDisposed && mounted) {
220
+ // Calling setState to refresh UI with updated video data
221
+ setState(() {
222
+ // Since VideoResult is immutable, we need to use the updated copy
223
+ // that comes from the stream, not create a new one
224
+ // The parent widget should receive this via the onVideoUpdated callback
225
+ if (widget.onVideoUpdated != null) {
226
+ debugPrint('PLAYER: Received video update, evolvedDescription length: ${updatedVideo.evolvedDescription.length}');
227
+
228
+ if (updatedVideo.evolvedDescription.isNotEmpty) {
229
+ debugPrint('PLAYER: First 100 chars: ${updatedVideo.evolvedDescription.substring(0, min(100, updatedVideo.evolvedDescription.length))}...');
230
+ }
231
+
232
+ widget.onVideoUpdated!(updatedVideo);
233
+ } else {
234
+ debugPrint('PLAYER: No video update callback registered');
235
+ }
236
+ });
237
+ }
238
+ });
239
  }
240
 
241
  if (!_isDisposed && mounted) {
 
451
  // Unregister the observer
452
  WidgetsBinding.instance.removeObserver(this);
453
 
454
+ // Cancel the video update subscription
455
+ _videoUpdateSubscription?.cancel();
456
+
457
  // Dispose controllers and timers
458
  _playbackController.dispose();
459
  _bufferManager.dispose();