AI a funcionar
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
class ChatScreen extends StatefulWidget {
|
class ChatScreen extends StatefulWidget {
|
||||||
const ChatScreen({super.key});
|
const ChatScreen({super.key});
|
||||||
@@ -21,9 +23,9 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
bool _isTyping = false;
|
bool _isTyping = false;
|
||||||
|
|
||||||
void _handleSubmitted(String text) {
|
Future<void> _handleSubmitted(String text) async {
|
||||||
if (text.trim().isEmpty) return;
|
if (text.trim().isEmpty) return;
|
||||||
|
|
||||||
_textController.clear();
|
_textController.clear();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -31,18 +33,54 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
_isTyping = true;
|
_isTyping = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Simulate EPVChat! typing delay
|
try {
|
||||||
Future.delayed(const Duration(milliseconds: 1500), () {
|
// Faz o pedido para o IP usando o formato compatível com OpenAI
|
||||||
|
final response = await http
|
||||||
|
.post(
|
||||||
|
Uri.parse('http://192.168.60.134:11434/v1/chat/completions'),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: jsonEncode({
|
||||||
|
'model': 'qwen3:4b', // Um modelo disponível no servidor
|
||||||
|
'messages': [
|
||||||
|
{'role': 'user', 'content': text},
|
||||||
|
],
|
||||||
|
'stream': false,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.timeout(const Duration(seconds: 30));
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
final reply =
|
||||||
|
data['choices'][0]['message']['content'] ??
|
||||||
|
'Sem resposta do modelo.';
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isTyping = false;
|
||||||
|
_messages.insert(0, ChatMessage(text: reply, isAssistant: true));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
'Erro no servidor: HTTP ${response.statusCode} - ${response.body}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isTyping = false;
|
_isTyping = false;
|
||||||
_messages.insert(0, ChatMessage(
|
_messages.insert(
|
||||||
text: "This is a simulated modern response to: \"$text\"",
|
0,
|
||||||
isAssistant: true,
|
ChatMessage(
|
||||||
));
|
text:
|
||||||
|
"Não foi possível comunicar com o modelo.\nVerifique se o IP está acessível.\nDetalhes: $e",
|
||||||
|
isAssistant: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMessage(ChatMessage message) {
|
Widget _buildMessage(ChatMessage message) {
|
||||||
@@ -50,7 +88,9 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: isAssistant ? MainAxisAlignment.start : MainAxisAlignment.end,
|
mainAxisAlignment: isAssistant
|
||||||
|
? MainAxisAlignment.start
|
||||||
|
: MainAxisAlignment.end,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
if (isAssistant)
|
if (isAssistant)
|
||||||
@@ -79,19 +119,28 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 14.0),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20.0,
|
||||||
|
vertical: 14.0,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: isAssistant
|
gradient: isAssistant
|
||||||
? const LinearGradient(
|
? const LinearGradient(
|
||||||
colors: [Color(0xFFF1F5F9), Color(0xFFE2E8F0)], // Light bubbles
|
colors: [
|
||||||
begin: Alignment.topLeft,
|
Color(0xFFF1F5F9),
|
||||||
end: Alignment.bottomRight,
|
Color(0xFFE2E8F0),
|
||||||
)
|
], // Light bubbles
|
||||||
: const LinearGradient(
|
begin: Alignment.topLeft,
|
||||||
colors: [Color(0xFF8ad5c9), Color(0xFF57a7ed)], // Mint & Blue bubbles
|
end: Alignment.bottomRight,
|
||||||
begin: Alignment.centerLeft,
|
)
|
||||||
end: Alignment.centerRight,
|
: const LinearGradient(
|
||||||
),
|
colors: [
|
||||||
|
Color(0xFF8ad5c9),
|
||||||
|
Color(0xFF57a7ed),
|
||||||
|
], // Mint & Blue bubbles
|
||||||
|
begin: Alignment.centerLeft,
|
||||||
|
end: Alignment.centerRight,
|
||||||
|
),
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: const Radius.circular(20),
|
topLeft: const Radius.circular(20),
|
||||||
topRight: const Radius.circular(20),
|
topRight: const Radius.circular(20),
|
||||||
@@ -106,9 +155,11 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isAssistant ? Colors.black.withOpacity(0.05) : Colors.transparent,
|
color: isAssistant
|
||||||
|
? Colors.black.withOpacity(0.05)
|
||||||
|
: Colors.transparent,
|
||||||
width: 1,
|
width: 1,
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
message.text,
|
message.text,
|
||||||
@@ -126,7 +177,10 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
gradient: const LinearGradient(
|
gradient: const LinearGradient(
|
||||||
colors: [Color(0xFF57a7ed), Color(0xFF3A8BD1)], // User avatar gradient
|
colors: [
|
||||||
|
Color(0xFF57a7ed),
|
||||||
|
Color(0xFF3A8BD1),
|
||||||
|
], // User avatar gradient
|
||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
),
|
),
|
||||||
@@ -172,9 +226,14 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16.0,
|
||||||
|
vertical: 12.0,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFFF1F5F9), // Typing bubble matching assistant light bubble
|
color: const Color(
|
||||||
|
0xFFF1F5F9,
|
||||||
|
), // Typing bubble matching assistant light bubble
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(20),
|
topLeft: Radius.circular(20),
|
||||||
topRight: Radius.circular(20),
|
topRight: Radius.circular(20),
|
||||||
@@ -240,7 +299,9 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFFF1F5F9), // Light input box background
|
color: const Color(
|
||||||
|
0xFFF1F5F9,
|
||||||
|
), // Light input box background
|
||||||
borderRadius: BorderRadius.circular(30.0),
|
borderRadius: BorderRadius.circular(30.0),
|
||||||
border: Border.all(color: Colors.black.withOpacity(0.05)),
|
border: Border.all(color: Colors.black.withOpacity(0.05)),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
@@ -257,9 +318,14 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
style: const TextStyle(color: Colors.black87),
|
style: const TextStyle(color: Colors.black87),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Message EPVChat!...",
|
hintText: "Message EPVChat!...",
|
||||||
hintStyle: TextStyle(color: Colors.black.withOpacity(0.4)),
|
hintStyle: TextStyle(
|
||||||
|
color: Colors.black.withOpacity(0.4),
|
||||||
|
),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 14.0),
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 24.0,
|
||||||
|
vertical: 14.0,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -268,7 +334,10 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: const LinearGradient(
|
gradient: const LinearGradient(
|
||||||
colors: [Color(0xFF8ad5c9), Color(0xFF57a7ed)], // Mint & Blue send button
|
colors: [
|
||||||
|
Color(0xFF8ad5c9),
|
||||||
|
Color(0xFF57a7ed),
|
||||||
|
], // Mint & Blue send button
|
||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
),
|
),
|
||||||
@@ -282,7 +351,11 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: const Icon(Icons.send_rounded, color: Colors.white, size: 20),
|
icon: const Icon(
|
||||||
|
Icons.send_rounded,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
onPressed: () => _handleSubmitted(_textController.text),
|
onPressed: () => _handleSubmitted(_textController.text),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -306,7 +379,10 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
child: AppBar(
|
child: AppBar(
|
||||||
title: ShaderMask(
|
title: ShaderMask(
|
||||||
shaderCallback: (bounds) => const LinearGradient(
|
shaderCallback: (bounds) => const LinearGradient(
|
||||||
colors: [Color(0xFF8ad5c9), Color(0xFF57a7ed)], // Text gradient header
|
colors: [
|
||||||
|
Color(0xFF8ad5c9),
|
||||||
|
Color(0xFF57a7ed),
|
||||||
|
], // Text gradient header
|
||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
).createShader(bounds),
|
).createShader(bounds),
|
||||||
@@ -319,7 +395,9 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.white.withOpacity(0.7), // Light Header backgrop
|
backgroundColor: Colors.white.withOpacity(
|
||||||
|
0.7,
|
||||||
|
), // Light Header backgrop
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
bottom: PreferredSize(
|
bottom: PreferredSize(
|
||||||
@@ -342,7 +420,7 @@ class _ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
|
|||||||
Colors.white,
|
Colors.white,
|
||||||
Color(0xFFF8FAFC), // Slate 50
|
Color(0xFFF8FAFC), // Slate 50
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
|
|||||||
32
pubspec.lock
32
pubspec.lock
@@ -75,6 +75,22 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
http:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.6.0"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.2"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -192,6 +208,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.10"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -208,6 +232,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.2"
|
version: "15.0.2"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.11.1 <4.0.0"
|
dart: ">=3.11.1 <4.0.0"
|
||||||
flutter: ">=3.18.0-18.0.pre.54"
|
flutter: ">=3.18.0-18.0.pre.54"
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ dependencies:
|
|||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
|
http: ^1.6.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user