1+ // Copyright 2025 Google LLC
2+ //
3+ // Licensed under the Apache License, Version 2.0 (the "License");
4+ // you may not use this file except in compliance with the License.
5+ // You may obtain a copy of the License at
6+ //
7+ // http://www.apache.org/licenses/LICENSE-2.0
8+ //
9+ // Unless required by applicable law or agreed to in writing, software
10+ // distributed under the License is distributed on an "AS IS" BASIS,
11+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ // See the License for the specific language governing permissions and
13+ // limitations under the License.
14+
15+ import 'dart:typed_data' ;
16+
17+ import 'package:flutter/material.dart' ;
18+ import 'package:firebase_vertexai/firebase_vertexai.dart' ;
19+ import 'package:flutter/services.dart' ;
20+ import '../widgets/message_widget.dart' ;
21+
22+ class VideoPage extends StatefulWidget {
23+ const VideoPage ({super .key, required this .title, required this .model});
24+
25+ final String title;
26+ final GenerativeModel model;
27+
28+ @override
29+ State <VideoPage > createState () => _VideoPageState ();
30+ }
31+
32+ class _VideoPageState extends State <VideoPage > {
33+ ChatSession ? chat;
34+ late final GenerativeModel model;
35+ final List <MessageData > _messages = < MessageData > [];
36+ bool _loading = false ;
37+
38+ @override
39+ void initState () {
40+ super .initState ();
41+ chat = widget.model.startChat ();
42+ }
43+
44+ Future <void > _testVideo (model) async {
45+ try {
46+ ByteData videoBytes =
47+ await rootBundle.load ('assets/videos/landscape.mp4' );
48+
49+ const _prompt =
50+ 'Can you tell me what is in the video?' ;
51+
52+ final prompt = TextPart (_prompt);
53+
54+ setState (() {
55+ _messages.add (MessageData (text: _prompt, fromUser: true ));
56+ });
57+
58+ final videoPart = InlineDataPart ('video/mp4' , videoBytes.buffer.asUint8List ());
59+
60+ final response = await widget.model.generateContent ([
61+ Content .multi ([prompt, videoPart]),
62+ ]);
63+
64+ setState ((){
65+ _messages.add (MessageData (text: response.text, fromUser: false ));
66+ });
67+
68+ } catch (e) {
69+ print ('Error sending video to model: $e ' );
70+ }
71+ }
72+
73+ @override
74+ Widget build (BuildContext context) {
75+ return Scaffold (
76+ appBar: AppBar (
77+ title: Text (widget.title),
78+ ),
79+ body: Padding (
80+ padding: const EdgeInsets .all (8 ),
81+ child: Column (
82+ mainAxisAlignment: MainAxisAlignment .center,
83+ crossAxisAlignment: CrossAxisAlignment .start,
84+ children: [
85+ Expanded (
86+ child: ListView .builder (
87+ itemBuilder: (context, idx) {
88+ return MessageWidget (
89+ text: _messages[idx].text,
90+ isFromUser: _messages[idx].fromUser ?? false ,
91+ );
92+ },
93+ itemCount: _messages.length,
94+ ),
95+ ),
96+ Padding (
97+ padding: const EdgeInsets .symmetric (
98+ vertical: 25 ,
99+ horizontal: 15 ,
100+ ),
101+ child: Row (
102+ children: [
103+ Expanded (
104+ child: ElevatedButton (
105+ onPressed: ! _loading
106+ ? () async {
107+ await _testVideo (widget.model);
108+ }
109+ : null ,
110+ child: const Text ('Test Video Prompt' ),
111+ ),
112+ ),
113+ ],
114+ ),
115+ ),
116+ ],
117+ ),
118+ ),
119+ );
120+ }
121+ }
0 commit comments