1
+ import 'package:animate_do/animate_do.dart' ;
1
2
import 'package:femunity/features/posts/screens/feature_box.dart' ;
3
+ import 'package:femunity/features/posts/screens/openai_service.dart' ;
2
4
import 'package:femunity/theme/pallate.dart' ;
3
5
import 'package:flutter/material.dart' ;
6
+ import 'package:flutter_tts/flutter_tts.dart' ;
4
7
import 'package:speech_to_text/speech_recognition_result.dart' ;
5
8
import 'package:speech_to_text/speech_to_text.dart' ;
6
9
@@ -14,11 +17,23 @@ class ChatScreen extends StatefulWidget {
14
17
class _ChatScreenState extends State <ChatScreen > {
15
18
final speechToText = SpeechToText ();
16
19
String lastWords = '' ;
20
+ final OpenAIService openAIService = OpenAIService ();
21
+ final flutterTts = FlutterTts ();
22
+ String ? generatedContent;
23
+ String ? generatedImageUrl;
24
+ int start = 200 ;
25
+ int delay = 200 ;
17
26
18
27
@override
19
28
void initState () {
20
29
super .initState ();
21
30
initSpeechToText ();
31
+ initTextToSpeech ();
32
+ }
33
+
34
+ Future <void > initTextToSpeech () async {
35
+ await flutterTts.setSharedInstance (true );
36
+ setState (() {});
22
37
}
23
38
24
39
Future <void > initSpeechToText () async {
@@ -48,121 +63,175 @@ class _ChatScreenState extends State<ChatScreen> {
48
63
});
49
64
}
50
65
66
+ Future <void > systemSpeak (String content) async {
67
+ await flutterTts.speak (content);
68
+ }
69
+
51
70
@override
52
71
void dispose () {
53
72
super .dispose ();
54
73
speechToText.stop ();
74
+ flutterTts.stop ();
55
75
}
56
76
57
77
@override
58
78
Widget build (BuildContext context) {
59
79
return Scaffold (
60
80
appBar: AppBar (
61
- title: const Text ('Sakhi' ),
81
+ title: Text ('Sakhi' ),
62
82
),
63
83
body: SingleChildScrollView (
64
84
child: Column (
65
85
children: [
66
- Stack (
67
- children: [
68
- Center (
69
- child: Container (
70
- height: 120 ,
71
- width: 120 ,
72
- margin: const EdgeInsets .only (top: 4 ),
86
+ ZoomIn (
87
+ child: Stack (
88
+ children: [
89
+ Center (
90
+ child: Container (
91
+ height: 120 ,
92
+ width: 120 ,
93
+ margin: const EdgeInsets .only (top: 4 ),
94
+ decoration: BoxDecoration (
95
+ color: Colors .black,
96
+ shape: BoxShape .circle,
97
+ ),
98
+ ),
99
+ ),
100
+ Container (
101
+ height: 140 ,
73
102
decoration: BoxDecoration (
74
- color: Colors .black,
75
103
shape: BoxShape .circle,
104
+ image: DecorationImage (
105
+ image: AssetImage (
106
+ "assets/images/sakhi.png" ,
107
+ ),
108
+ ),
76
109
),
77
110
),
78
- ),
79
- Container (
80
- height: 140 ,
111
+ ],
112
+ ),
113
+ ),
114
+ FadeInRight (
115
+ child: Visibility (
116
+ visible: generatedImageUrl == null ,
117
+ child: Container (
118
+ padding: const EdgeInsets .symmetric (
119
+ horizontal: 20 ,
120
+ vertical: 10 ,
121
+ ),
122
+ margin: const EdgeInsets .symmetric (horizontal: 40 )
123
+ .copyWith (top: 30 ),
81
124
decoration: BoxDecoration (
82
- shape: BoxShape .circle,
83
- image: DecorationImage (
84
- image: AssetImage (
85
- "assets/images/sakhi.png" ,
125
+ border: Border .all (color: Colors .white),
126
+ borderRadius: BorderRadius .circular (20 )
127
+ .copyWith (topLeft: const Radius .circular (0 )),
128
+ ),
129
+ child: Padding (
130
+ padding: const EdgeInsets .symmetric (vertical: 10.0 ),
131
+ child: Text (
132
+ generatedContent == null
133
+ ? "Hey! What's on your mind?"
134
+ : generatedContent! ,
135
+ style: TextStyle (
136
+ fontSize: generatedContent == null ? 20 : 15 ,
137
+ fontFamily: 'Times New Roman' ,
86
138
),
87
139
),
88
140
),
89
141
),
90
- ],
91
- ),
92
- Container (
93
- padding: const EdgeInsets .symmetric (
94
- horizontal: 20 ,
95
- vertical: 10 ,
96
142
),
97
- margin:
98
- const EdgeInsets .symmetric (horizontal: 40 ).copyWith (top: 30 ),
99
- decoration: BoxDecoration (
100
- border: Border .all (color: Colors .white),
101
- borderRadius: BorderRadius .circular (20 )
102
- .copyWith (topLeft: const Radius .circular (0 )),
143
+ ),
144
+ if (generatedImageUrl != null )
145
+ Padding (
146
+ padding: const EdgeInsets .all (10.0 ),
147
+ child: ClipRRect (
148
+ borderRadius: BorderRadius .circular (20 ),
149
+ child: Image .network (generatedImageUrl! )),
103
150
),
104
- child: const Padding (
105
- padding: const EdgeInsets .symmetric (vertical: 10.0 ),
106
- child: Text (
107
- "Hey! What's on your mind?" ,
108
- style: TextStyle (
109
- fontSize: 20 ,
110
- fontFamily: 'Times New Roman' ,
151
+ Visibility (
152
+ visible: generatedContent == null && generatedImageUrl == null ,
153
+ child: Container (
154
+ padding: const EdgeInsets .all (10 ),
155
+ alignment: Alignment .centerLeft,
156
+ margin: const EdgeInsets .only (
157
+ top: 8 ,
158
+ left: 10 ,
159
+ ),
160
+ child: SlideInLeft (
161
+ child: Text (
162
+ "Here are a few features" ,
163
+ style: TextStyle (
164
+ fontFamily: "Times New Roman" ,
165
+ fontSize: 18 ,
166
+ fontWeight: FontWeight .bold,
167
+ ),
111
168
),
112
169
),
113
170
),
114
171
),
115
- Container (
116
- padding: const EdgeInsets .all (10 ),
117
- alignment: Alignment .centerLeft,
118
- margin: const EdgeInsets .only (
119
- top: 8 ,
120
- left: 10 ,
121
- ),
122
- child: const Text (
123
- "Here are a few features" ,
124
- style: TextStyle (
125
- fontFamily: "Times New Roman" ,
126
- fontSize: 18 ,
127
- fontWeight: FontWeight .bold,
128
- ),
172
+ Visibility (
173
+ visible: generatedContent == null && generatedImageUrl == null ,
174
+ child: Column (
175
+ children: [
176
+ SlideInLeft (
177
+ delay: Duration (milliseconds: start),
178
+ child: FeatureBox (
179
+ color: Pallete .firstSuggestionBoxColor,
180
+ headerText: 'Share your feelings' ,
181
+ descriptionText:
182
+ "Talk and interact with non-judgmental ears." ,
183
+ ),
184
+ ),
185
+ SlideInRight (
186
+ delay: Duration (milliseconds: start + delay),
187
+ child: FeatureBox (
188
+ color: Pallete .secondSuggestionBoxColor,
189
+ headerText: "headerText" ,
190
+ descriptionText: "descriptionText" ,
191
+ ),
192
+ ),
193
+ SlideInLeft (
194
+ delay: Duration (milliseconds: start + 2 * delay),
195
+ child: FeatureBox (
196
+ color: Pallete .thirdSuggestionBoxColor,
197
+ headerText: "headerText" ,
198
+ descriptionText: "descriptionText" ,
199
+ ),
200
+ ),
201
+ ],
129
202
),
130
203
),
131
- Column (
132
- children: [
133
- FeatureBox (
134
- color: Pallete .firstSuggestionBoxColor,
135
- headerText: 'Share your feelings' ,
136
- descriptionText:
137
- "Talk and interact with non-judgmental ears." ,
138
- ),
139
- FeatureBox (
140
- color: Pallete .secondSuggestionBoxColor,
141
- headerText: "headerText" ,
142
- descriptionText: "descriptionText" ,
143
- ),
144
- FeatureBox (
145
- color: Pallete .thirdSuggestionBoxColor,
146
- headerText: "headerText" ,
147
- descriptionText: "descriptionText" ,
148
- ),
149
- ],
150
- ),
151
204
],
152
205
),
153
206
),
154
- floatingActionButton: FloatingActionButton (
155
- backgroundColor: Colors .yellow,
156
- onPressed: () async {
157
- if (await speechToText.hasPermission && speechToText.isNotListening) {
158
- await startListening ();
159
- } else if (speechToText.isListening) {
160
- await stopListening ();
161
- } else {
162
- initSpeechToText ();
163
- }
164
- },
165
- child: const Icon (Icons .mic),
207
+ floatingActionButton: ZoomIn (
208
+ delay: Duration (milliseconds: start + 3 * delay),
209
+ child: FloatingActionButton (
210
+ backgroundColor: Colors .yellow,
211
+ onPressed: () async {
212
+ if (await speechToText.hasPermission &&
213
+ speechToText.isNotListening) {
214
+ await startListening ();
215
+ } else if (speechToText.isListening) {
216
+ final speech = await openAIService.isArtPromptAPI (lastWords);
217
+ if (speech.contains ('https' )) {
218
+ generatedImageUrl = speech;
219
+ generatedContent = null ;
220
+ setState (() {});
221
+ } else {
222
+ generatedContent = speech;
223
+ generatedImageUrl = null ;
224
+ setState (() {});
225
+ await systemSpeak (speech);
226
+ }
227
+
228
+ await stopListening ();
229
+ } else {
230
+ initSpeechToText ();
231
+ }
232
+ },
233
+ child: Icon (speechToText.isListening ? Icons .stop : Icons .mic),
234
+ ),
166
235
),
167
236
);
168
237
}
0 commit comments