Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
F
flutter-chat
Project
Project
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
Graph
比较
统计图
议题
0
议题
0
列表
看板
标记
Milestones
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
songchuancai
flutter-chat
Commits
13b88ee1
提交
13b88ee1
authored
11月 07, 2024
作者:
songchuancai
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加历史会话功能(目前历史会话保存到本地)
上级
25369ae8
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
402 行增加
和
19 行删除
+402
-19
home_page.dart
lib/home_page.dart
+142
-18
chat_message.dart
lib/models/chat_message.dart
+24
-0
conversation.dart
lib/models/conversation.dart
+32
-0
storage_service.dart
lib/services/storage_service.dart
+47
-0
GeneratedPluginRegistrant.swift
macos/Flutter/GeneratedPluginRegistrant.swift
+2
-0
pubspec.lock
pubspec.lock
+153
-1
pubspec.yaml
pubspec.yaml
+2
-0
没有找到文件。
lib/home_page.dart
浏览文件 @
13b88ee1
import
'package:allen/feature_box.dart'
;
import
'package:allen/openai_service.dart'
;
import
'package:allen/pallete.dart'
;
import
'package:animate_do/animate_do.dart'
;
...
...
@@ -6,18 +5,12 @@ import 'package:flutter/material.dart';
import
'package:flutter_tts/flutter_tts.dart'
;
import
'package:speech_to_text/speech_recognition_result.dart'
;
import
'package:speech_to_text/speech_to_text.dart'
;
import
'dart:io'
show
Platform
;
import
'package:flutter/foundation.dart'
show
kIsWeb
;
class
ChatMessage
{
final
String
text
;
final
bool
isUserMessage
;
ChatMessage
({
required
this
.
text
,
required
this
.
isUserMessage
,
});
}
import
'package:uuid/uuid.dart'
;
import
'models/conversation.dart'
;
import
'services/storage_service.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
import
'models/chat_message.dart'
;
class
HomePage
extends
StatefulWidget
{
const
HomePage
({
super
.
key
});
...
...
@@ -37,19 +30,63 @@ class _HomePageState extends State<HomePage> {
int
delay
=
200
;
final
TextEditingController
_messageController
=
TextEditingController
();
String
currentStreamedContent
=
''
;
final
List
<
ChatMessage
>
messages
=
[];
List
<
ChatMessage
>
messages
=
[];
bool
_isLoading
=
false
;
bool
_isVoiceMode
=
true
;
bool
_isListeningPressed
=
false
;
String
_currentVoiceText
=
''
;
late
StorageService
_storageService
;
late
Conversation
_currentConversation
;
List
<
Conversation
>
_conversations
=
[];
@override
void
initState
()
{
super
.
initState
();
_initializeStorage
();
initSpeechToText
();
_initTts
();
}
Future
<
void
>
_initializeStorage
()
async
{
final
prefs
=
await
SharedPreferences
.
getInstance
();
_storageService
=
StorageService
(
prefs
);
_conversations
=
await
_storageService
.
getConversations
();
if
(
_conversations
.
isEmpty
)
{
_createNewConversation
();
}
else
{
_currentConversation
=
_conversations
.
first
;
setState
(()
{
messages
=
_currentConversation
.
messages
;
});
}
}
Future
<
void
>
_createNewConversation
()
async
{
final
newConversation
=
Conversation
(
id:
const
Uuid
().
v4
(),
title:
'新会话
${_conversations.length + 1}
'
,
createdAt:
DateTime
.
now
(),
messages:
[],
);
await
_storageService
.
addConversation
(
newConversation
);
setState
(()
{
_conversations
.
insert
(
0
,
newConversation
);
_currentConversation
=
newConversation
;
messages
=
[];
});
}
Future
<
void
>
_updateCurrentConversation
()
async
{
_currentConversation
=
Conversation
(
id:
_currentConversation
.
id
,
title:
_currentConversation
.
title
,
createdAt:
_currentConversation
.
createdAt
,
messages:
messages
,
);
await
_storageService
.
updateConversation
(
_currentConversation
);
}
Future
<
void
>
_initTts
()
async
{
if
(!
kIsWeb
)
{
await
flutterTts
.
setSharedInstance
(
true
);
...
...
@@ -128,6 +165,7 @@ class _HomePageState extends State<HomePage> {
});
}
await
systemSpeak
(
fullResponse
);
await
_updateCurrentConversation
();
}
catch
(
e
)
{
setState
(()
{
messages
.
add
(
ChatMessage
(
...
...
@@ -164,6 +202,7 @@ class _HomePageState extends State<HomePage> {
});
}
await
systemSpeak
(
fullResponse
);
await
_updateCurrentConversation
();
}
catch
(
e
)
{
setState
(()
{
messages
.
add
(
ChatMessage
(
...
...
@@ -296,16 +335,101 @@ class _HomePageState extends State<HomePage> {
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
AppBar
_buildAppBar
()
{
return
AppBar
(
title:
BounceInDown
(
child:
const
Text
(
'快际新云'
),
),
leading:
const
Icon
(
Icons
.
menu
),
leading:
Builder
(
builder:
(
context
)
=>
IconButton
(
icon:
const
Icon
(
Icons
.
menu
),
onPressed:
()
=>
Scaffold
.
of
(
context
).
openDrawer
(),
),
),
centerTitle:
true
,
);
}
Widget
_buildDrawer
()
{
return
Drawer
(
child:
Column
(
children:
[
DrawerHeader
(
decoration:
BoxDecoration
(
color:
Pallete
.
firstSuggestionBoxColor
,
),
child:
const
Center
(
child:
Text
(
'会话列表'
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
24
,
),
),
),
),
ListTile
(
leading:
const
Icon
(
Icons
.
add
),
title:
const
Text
(
'新建会话'
),
onTap:
()
{
_createNewConversation
();
Navigator
.
pop
(
context
);
},
),
Expanded
(
child:
ListView
.
builder
(
itemCount:
_conversations
.
length
,
itemBuilder:
(
context
,
index
)
{
final
conversation
=
_conversations
[
index
];
return
ListTile
(
leading:
const
Icon
(
Icons
.
chat
),
title:
Text
(
conversation
.
title
),
subtitle:
Text
(
conversation
.
messages
.
isEmpty
?
'暂无消息'
:
conversation
.
messages
.
last
.
text
,
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
),
selected:
_currentConversation
.
id
==
conversation
.
id
,
onTap:
()
{
setState
(()
{
_currentConversation
=
conversation
;
messages
=
conversation
.
messages
;
});
Navigator
.
pop
(
context
);
},
trailing:
IconButton
(
icon:
const
Icon
(
Icons
.
delete
),
onPressed:
()
async
{
await
_storageService
.
deleteConversation
(
conversation
.
id
);
setState
(()
{
_conversations
.
removeAt
(
index
);
if
(
_currentConversation
.
id
==
conversation
.
id
)
{
if
(
_conversations
.
isEmpty
)
{
_createNewConversation
();
}
else
{
_currentConversation
=
_conversations
.
first
;
messages
=
_currentConversation
.
messages
;
}
}
});
},
),
);
},
),
),
],
),
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
_buildAppBar
(),
drawer:
_buildDrawer
(),
body:
Column
(
children:
[
Expanded
(
...
...
lib/models/chat_message.dart
0 → 100644
浏览文件 @
13b88ee1
class
ChatMessage
{
final
String
text
;
final
bool
isUserMessage
;
final
DateTime
timestamp
;
ChatMessage
({
required
this
.
text
,
required
this
.
isUserMessage
,
DateTime
?
timestamp
,
})
:
timestamp
=
timestamp
??
DateTime
.
now
();
Map
<
String
,
dynamic
>
toJson
()
=>
{
'text'
:
text
,
'isUserMessage'
:
isUserMessage
,
'timestamp'
:
timestamp
.
toIso8601String
(),
};
factory
ChatMessage
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
ChatMessage
(
text:
json
[
'text'
],
isUserMessage:
json
[
'isUserMessage'
],
timestamp:
DateTime
.
parse
(
json
[
'timestamp'
]),
);
}
\ No newline at end of file
lib/models/conversation.dart
0 → 100644
浏览文件 @
13b88ee1
import
'chat_message.dart'
;
class
Conversation
{
final
String
id
;
final
String
title
;
final
DateTime
createdAt
;
final
List
<
ChatMessage
>
messages
;
Conversation
({
required
this
.
id
,
required
this
.
title
,
required
this
.
createdAt
,
required
this
.
messages
,
});
Map
<
String
,
dynamic
>
toJson
()
=>
{
'id'
:
id
,
'title'
:
title
,
'createdAt'
:
createdAt
.
toIso8601String
(),
'messages'
:
messages
.
map
((
msg
)
=>
msg
.
toJson
()).
toList
(),
};
factory
Conversation
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
Conversation
(
id:
json
[
'id'
],
title:
json
[
'title'
],
createdAt:
DateTime
.
parse
(
json
[
'createdAt'
]),
messages:
(
json
[
'messages'
]
as
List
)
.
map
((
msg
)
=>
ChatMessage
.
fromJson
(
msg
))
.
toList
(),
);
}
\ No newline at end of file
lib/services/storage_service.dart
0 → 100644
浏览文件 @
13b88ee1
import
'dart:convert'
;
import
'package:shared_preferences/shared_preferences.dart'
;
import
'../models/conversation.dart'
;
class
StorageService
{
static
const
String
_conversationsKey
=
'conversations'
;
final
SharedPreferences
_prefs
;
StorageService
(
this
.
_prefs
);
Future
<
List
<
Conversation
>>
getConversations
()
async
{
final
String
?
data
=
_prefs
.
getString
(
_conversationsKey
);
if
(
data
==
null
)
return
[];
List
<
dynamic
>
jsonList
=
json
.
decode
(
data
);
return
jsonList
.
map
((
json
)
=>
Conversation
.
fromJson
(
json
)).
toList
();
}
Future
<
void
>
saveConversations
(
List
<
Conversation
>
conversations
)
async
{
final
String
data
=
json
.
encode
(
conversations
.
map
((
conv
)
=>
conv
.
toJson
()).
toList
(),
);
await
_prefs
.
setString
(
_conversationsKey
,
data
);
}
Future
<
void
>
addConversation
(
Conversation
conversation
)
async
{
final
conversations
=
await
getConversations
();
conversations
.
insert
(
0
,
conversation
);
await
saveConversations
(
conversations
);
}
Future
<
void
>
updateConversation
(
Conversation
conversation
)
async
{
final
conversations
=
await
getConversations
();
final
index
=
conversations
.
indexWhere
((
conv
)
=>
conv
.
id
==
conversation
.
id
);
if
(
index
!=
-
1
)
{
conversations
[
index
]
=
conversation
;
await
saveConversations
(
conversations
);
}
}
Future
<
void
>
deleteConversation
(
String
id
)
async
{
final
conversations
=
await
getConversations
();
conversations
.
removeWhere
((
conv
)
=>
conv
.
id
==
id
);
await
saveConversations
(
conversations
);
}
}
macos/Flutter/GeneratedPluginRegistrant.swift
浏览文件 @
13b88ee1
...
...
@@ -6,9 +6,11 @@ import FlutterMacOS
import
Foundation
import
flutter_tts
import
shared_preferences_foundation
import
speech_to_text_macos
func
RegisterGeneratedPlugins
(
registry
:
FlutterPluginRegistry
)
{
FlutterTtsPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FlutterTtsPlugin"
))
SharedPreferencesPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"SharedPreferencesPlugin"
))
SpeechToTextMacosPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"SpeechToTextMacosPlugin"
))
}
pubspec.lock
浏览文件 @
13b88ee1
...
...
@@ -49,6 +49,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.18.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.6"
cupertino_icons:
dependency: "direct main"
description:
...
...
@@ -65,6 +73,30 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.3"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
flutter:
dependency: "direct main"
description: flutter
...
...
@@ -192,6 +224,30 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.0"
pedantic:
dependency: transitive
description:
...
...
@@ -200,6 +256,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.11.1"
platform:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.6"
plugin_platform_interface:
dependency: transitive
description:
...
...
@@ -208,6 +272,62 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.8"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.3"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.5.3"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.2"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
sky_engine:
dependency: transitive
description: flutter
...
...
@@ -245,6 +365,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.0"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.0"
stack_trace:
dependency: transitive
description:
...
...
@@ -293,6 +421,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.0"
uuid:
dependency: "direct main"
description:
name: uuid
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.5.1"
vector_math:
dependency: transitive
description:
...
...
@@ -309,6 +445,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "14.2.5"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.
18.0-18.0.pre.54
"
flutter: ">=3.
24.0
"
pubspec.yaml
浏览文件 @
13b88ee1
...
...
@@ -39,6 +39,8 @@ dependencies:
http
:
^0.13.5
flutter_tts
:
^3.6.3
animate_do
:
^3.0.2
shared_preferences
:
^2.2.2
uuid
:
^4.3.3
dev_dependencies
:
flutter_test
:
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论