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
02c8e358
提交
02c8e358
authored
11月 11, 2024
作者:
songchuancai
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
对接应用聊天接口
上级
94555935
显示空白字符变更
内嵌
并排
正在显示
14 个修改的文件
包含
474 行增加
和
20 行删除
+474
-20
launch.json
.vscode/launch.json
+26
-0
home_page.dart
lib/home_page.dart
+1
-1
main.dart
lib/main.dart
+28
-3
app_item.dart
lib/models/app_item.dart
+3
-0
apps_page.dart
lib/pages/apps_page.dart
+55
-0
chat_page.dart
lib/pages/chat_page.dart
+42
-6
providers.dart
lib/providers.dart
+16
-0
secrets.dart
lib/secrets.dart
+1
-1
api_service.dart
lib/services/api_service.dart
+31
-1
apps_service.dart
lib/services/apps_service.dart
+1
-1
chat_service.dart
lib/services/chat_service.dart
+12
-6
storage_service.dart
lib/services/storage_service.dart
+33
-0
pubspec.lock
pubspec.lock
+24
-0
pubspec.yaml
pubspec.yaml
+201
-1
没有找到文件。
.vscode/launch.json
0 → 100644
浏览文件 @
02c8e358
{
//
使用
IntelliSense
了解相关属性。
//
悬停以查看现有属性的描述。
//
欲了解更多信息,请访问
:
https
:
//go.microsoft.com/fwlink/?linkid=
830387
"version"
:
"0.2.0"
,
"configurations"
:
[
{
"name"
:
"chatGPT-chatbox-flutter-main"
,
"request"
:
"launch"
,
"type"
:
"dart"
},
{
"name"
:
"chatGPT-chatbox-flutter-main (profile mode)"
,
"request"
:
"launch"
,
"type"
:
"dart"
,
"flutterMode"
:
"profile"
},
{
"name"
:
"chatGPT-chatbox-flutter-main (release mode)"
,
"request"
:
"launch"
,
"type"
:
"dart"
,
"flutterMode"
:
"release"
}
]
}
\ No newline at end of file
lib/home_page.dart
浏览文件 @
02c8e358
...
...
@@ -192,7 +192,7 @@ class _HomePageState extends State<HomePage> {
if
(
kIsWeb
)
{
// 设置语速
await
flutterTts
.
setSpeechRate
(
3
);
await
flutterTts
.
setSpeechRate
(
1
);
// 音调
...
...
lib/main.dart
浏览文件 @
02c8e358
import
'package:allen/home_page.dart'
;
import
'package:allen/pallete.dart'
;
import
'package:allen/providers.dart'
;
import
'package:flutter/material.dart'
;
import
'package:allen/pages/login_page.dart'
;
import
'package:allen/services/storage_service.dart'
;
import
'package:allen/models/user.dart'
;
import
'package:allen/models/app_item.dart'
;
import
'package:allen/pages/chat_page.dart'
;
import
'package:flutter_riverpod/flutter_riverpod.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
void
main
(
)
async
{
WidgetsFlutterBinding
.
ensureInitialized
();
runApp
(
const
MyApp
());
final
prefs
=
await
SharedPreferences
.
getInstance
();
runApp
(
ProviderScope
(
overrides:
[
sharedPreferencesProvider
.
overrideWithValue
(
prefs
),
],
child:
const
MyApp
(),
),
);
}
class
MyApp
extends
StatelessWidget
{
...
...
@@ -33,6 +54,7 @@ class MyApp extends StatelessWidget {
if
(
snapshot
.
connectionState
==
ConnectionState
.
waiting
)
{
return
const
CircularProgressIndicator
();
}
return
snapshot
.
hasData
?
const
HomePage
()
:
const
LoginPage
();
},
),
...
...
@@ -40,21 +62,25 @@ class MyApp extends StatelessWidget {
if
(
settings
.
name
==
'/home'
)
{
return
MaterialPageRoute
(
builder:
(
context
)
=>
const
HomePage
());
}
if
(
settings
.
name
==
'/login'
)
{
return
MaterialPageRoute
(
builder:
(
context
)
=>
const
LoginPage
());
}
if
(
settings
.
name
==
'/chat'
)
{
final
args
=
settings
.
arguments
;
if
(
args
is
AppItem
)
{
return
MaterialPageRoute
(
builder:
(
context
)
=>
ChatPage
(
app:
args
),
);
}
return
MaterialPageRoute
(
builder:
(
context
)
=>
const
HomePage
());
}
return
MaterialPageRoute
(
builder:
(
context
)
=>
const
HomePage
());
},
);
}
}
\ No newline at end of file
lib/models/app_item.dart
浏览文件 @
02c8e358
class
AppItem
{
final
String
id
;
final
String
name
;
final
String
description
;
final
String
iconUrl
;
...
...
@@ -8,6 +9,7 @@ class AppItem {
final
bool
isDefault
;
AppItem
({
required
this
.
id
,
required
this
.
name
,
required
this
.
description
,
required
this
.
iconUrl
,
...
...
@@ -19,6 +21,7 @@ class AppItem {
factory
AppItem
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
AppItem
(
id:
json
[
'id'
]
??
''
,
name:
json
[
'name'
]
??
''
,
description:
json
[
'description'
]
??
''
,
iconUrl:
json
[
'icon_url'
]
??
''
,
...
...
lib/pages/apps_page.dart
浏览文件 @
02c8e358
import
'package:flutter/material.dart'
;
import
'../services/api_service.dart'
;
import
'../services/apps_service.dart'
;
import
'../models/app_item.dart'
;
import
'../pallete.dart'
;
import
'../services/storage_service.dart'
;
import
'../models/user.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
class
AppsPage
extends
StatefulWidget
{
const
AppsPage
({
super
.
key
});
...
...
@@ -14,26 +22,36 @@ class AppsPage extends StatefulWidget {
class
_AppsPageState
extends
State
<
AppsPage
>
{
late
final
AppsService
_appsService
;
List
<
AppItem
>
apps
=
[];
bool
isLoading
=
true
;
String
?
error
;
bool
_isLoadingMore
=
false
;
int
_currentPage
=
1
;
bool
_hasMoreData
=
true
;
final
ScrollController
_scrollController
=
ScrollController
();
static
const
int
_pageSize
=
4
;
@override
void
initState
()
{
super
.
initState
();
_initializeService
();
_scrollController
.
addListener
(
_onScroll
);
}
@override
void
dispose
()
{
_scrollController
.
dispose
();
super
.
dispose
();
}
...
...
@@ -62,6 +80,7 @@ class _AppsPageState extends State<AppsPage> {
}
else
{
setState
(()
{
apps
.
addAll
(
newApps
);
_currentPage
++;
});
}
...
...
@@ -76,7 +95,9 @@ class _AppsPageState extends State<AppsPage> {
Future
<
void
>
_initializeService
()
async
{
final
User
?
user
=
await
StorageService
.
getUser
();
_appsService
=
AppsService
(
token:
user
?.
token
);
fetchApps
();
}
...
...
@@ -86,15 +107,20 @@ class _AppsPageState extends State<AppsPage> {
page:
1
,
pageSize:
_pageSize
,
);
setState
(()
{
apps
=
appsList
;
isLoading
=
false
;
_currentPage
=
1
;
_hasMoreData
=
appsList
.
length
>=
_pageSize
;
});
}
catch
(
e
)
{
setState
(()
{
error
=
e
.
toString
();
isLoading
=
false
;
});
}
...
...
@@ -186,4 +212,33 @@ class _AppsPageState extends State<AppsPage> {
),
);
}
// Future<void> _onAppTap(AppItem app) async {
// try {
// final apiService = ApiService();
// final storageService =
// StorageService(await SharedPreferences.getInstance());
// final workbenchToken = await apiService.getWorkbenchToken(app.id);
// // 存储token
// await storageService.setWorkbenchToken(workbenchToken);
// if (context.mounted) {
// Navigator.pushNamed(
// context,
// '/chat',
// arguments: app,
// );
// }
// } catch (e) {
// if (context.mounted) {
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text('进入聊天失败: $e')),
// );
// }
// }
// }
}
lib/pages/chat_page.dart
浏览文件 @
02c8e358
import
'package:flutter/material.dart'
;
import
'package:flutter_riverpod/flutter_riverpod.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
import
'../models/app_item.dart'
;
import
'../services/storage_service.dart'
;
import
'../home_page.dart'
;
class
ChatPage
extends
StatelessWidget
{
import
'../services/api_service.dart'
;
class
ChatPage
extends
ConsumerStatefulWidget
{
final
AppItem
app
;
const
ChatPage
({
super
.
key
,
required
this
.
app
});
@override
ConsumerState
<
ChatPage
>
createState
()
=>
_ChatPageState
();
}
class
_ChatPageState
extends
ConsumerState
<
ChatPage
>
{
@override
void
initState
()
{
super
.
initState
();
_initChat
();
}
Future
<
void
>
_initChat
()
async
{
try
{
final
apiService
=
ApiService
();
final
workbenchToken
=
await
apiService
.
getWorkbenchToken
(
widget
.
app
.
id
);
final
prefs
=
await
SharedPreferences
.
getInstance
();
final
storageService
=
StorageService
(
prefs
);
await
storageService
.
saveWorkbenchToken
(
workbenchToken
);
}
catch
(
e
)
{
debugPrint
(
'初始化聊天失败:
$e
'
);
}
}
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
...
...
@@ -17,14 +53,14 @@ class ChatPage extends StatelessWidget {
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
app
.
name
,
widget
.
app
.
name
,
style:
const
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
bold
,
),
),
Text
(
app
.
description
,
widget
.
app
.
description
,
style:
const
TextStyle
(
fontSize:
12
,
fontWeight:
FontWeight
.
normal
,
...
...
@@ -38,9 +74,9 @@ class ChatPage extends StatelessWidget {
),
),
body:
HomePage
(
customTitle:
app
.
name
,
customDescription:
app
.
description
,
customImageUrl:
app
.
iconUrl
,
customTitle:
widget
.
app
.
name
,
customDescription:
widget
.
app
.
description
,
customImageUrl:
widget
.
app
.
iconUrl
,
hideNavigation:
true
,
),
);
...
...
lib/providers.dart
0 → 100644
浏览文件 @
02c8e358
import
'package:flutter_riverpod/flutter_riverpod.dart'
;
import
'services/api_service.dart'
;
import
'services/storage_service.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
final
apiServiceProvider
=
Provider
<
ApiService
>((
ref
)
=>
ApiService
());
final
sharedPreferencesProvider
=
Provider
<
SharedPreferences
>((
ref
)
{
throw
UnimplementedError
();
});
final
storageServiceProvider
=
Provider
<
StorageService
>((
ref
)
{
final
prefs
=
ref
.
watch
(
sharedPreferencesProvider
);
return
StorageService
(
prefs
);
});
lib/secrets.dart
浏览文件 @
02c8e358
const
openAIAPIKey
=
'sk-zV0MPjPserDD4gdQ8lE8aUGwxayOwuayogGidos4VO8uxdDL'
;
const
baseUrl
=
'https://knowledge-web.apps.iytcloud.com
/console/api
'
;
const
baseUrl
=
'https://knowledge-web.apps.iytcloud.com'
;
lib/services/api_service.dart
浏览文件 @
02c8e358
import
'dart:convert'
;
import
'package:allen/services/storage_service.dart'
;
import
'package:http/http.dart'
as
http
;
import
'../models/user.dart'
;
import
'../secrets.dart'
;
class
ApiService
{
static
Future
<
Map
<
String
,
dynamic
>>
login
(
String
email
,
String
password
)
async
{
final
response
=
await
http
.
post
(
Uri
.
parse
(
'
$baseUrl
/login/'
),
Uri
.
parse
(
'
$baseUrl
/
console/api/
login/'
),
headers:
{
'Content-Type'
:
'application/json'
,
'Accept'
:
'application/json'
,
...
...
@@ -19,4 +23,30 @@ class ApiService {
return
jsonDecode
(
response
.
body
);
}
Future
<
String
>
getWorkbenchToken
(
String
appId
)
async
{
try
{
User
?
user
=
await
StorageService
.
getUser
();
String
token
=
user
?.
token
??
''
;
final
response
=
await
http
.
post
(
Uri
.
parse
(
'
$baseUrl
/console/api/apps/workbench'
),
headers:
{
'Content-Type'
:
'application/json'
,
'Accept'
:
'application/json'
,
'Authorization'
:
'Bearer
$token
'
,
},
body:
jsonEncode
({
'app_id'
:
appId
,
}),
);
if
(
response
.
statusCode
==
200
)
{
return
jsonDecode
(
response
.
body
)[
'data'
];
}
throw
Exception
(
'获取会话token失败'
);
}
catch
(
e
)
{
throw
Exception
(
'获取会话token失败:
$e
'
);
}
}
}
lib/services/apps_service.dart
浏览文件 @
02c8e358
...
...
@@ -10,7 +10,7 @@ class AppsService {
Future
<
List
<
AppItem
>>
getApps
({
int
page
=
1
,
int
pageSize
=
4
})
async
{
final
response
=
await
http
.
get
(
Uri
.
parse
(
'
$baseUrl
/apps/?page=
$page
&pageSize=
$pageSize
'
),
Uri
.
parse
(
'
$baseUrl
/
console/api/
apps/?page=
$page
&pageSize=
$pageSize
'
),
headers:
{
'Content-Type'
:
'application/json'
,
'Accept'
:
'application/json'
,
...
...
lib/services/chat_service.dart
浏览文件 @
02c8e358
import
'dart:convert'
;
import
'package:allen/services/storage_service.dart'
;
import
'package:http/http.dart'
as
http
;
import
'package:shared_preferences/shared_preferences.dart'
;
import
'../secrets.dart'
;
class
OpenAIService
{
final
String
apiKey
=
'sk-OVjS7VE9mT68Uvg7kSFoMnbU6EU836FO'
;
final
String
appKey
=
'app-FRP2s2wSx01rsE67'
;
//
final String apiKey = 'sk-OVjS7VE9mT68Uvg7kSFoMnbU6EU836FO';
//
final String appKey = 'app-FRP2s2wSx01rsE67';
String
?
conversationId
;
Stream
<
String
>
chatGPTAPI
(
String
message
)
async
*
{
final
client
=
http
.
Client
();
var
buffer
=
StringBuffer
();
var
prefs
=
await
SharedPreferences
.
getInstance
();
var
storageService
=
StorageService
(
prefs
);
String
appKey
=
storageService
.
getWorkbenchToken
()
??
''
;
try
{
final
request
=
http
.
Request
(
'POST'
,
Uri
.
parse
(
'
$baseUrl
/openapi/chat'
));
final
request
=
http
.
Request
(
'POST'
,
Uri
.
parse
(
'
$baseUrl
/api/chat-messages'
));
request
.
headers
.
addAll
({
'Content-Type'
:
'application/json'
,
'Authorization'
:
'Bearer
$ap
i
Key
'
,
'Authorization'
:
'Bearer
$ap
p
Key
'
,
});
Map
<
String
,
dynamic
>
requestBody
=
{
'
app_key'
:
appKey
,
'
inputs'
:
{}
,
'query'
:
message
,
'
stream'
:
true
,
'
response_mode'
:
'streaming'
,
};
if
(
conversationId
!=
null
)
{
...
...
lib/services/storage_service.dart
浏览文件 @
02c8e358
import
'dart:convert'
;
import
'package:shared_preferences/shared_preferences.dart'
;
import
'../models/conversation.dart'
;
import
'package:allen/models/user.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
();
}
...
...
@@ -21,28 +27,36 @@ class StorageService {
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
);
}
...
...
@@ -50,18 +64,37 @@ class StorageService {
static
Future
<
void
>
saveUser
(
User
user
)
async
{
final
prefs
=
await
SharedPreferences
.
getInstance
();
await
prefs
.
setString
(
_userKey
,
jsonEncode
(
user
.
toJson
()));
}
static
Future
<
User
?>
getUser
()
async
{
final
prefs
=
await
SharedPreferences
.
getInstance
();
final
userJson
=
prefs
.
getString
(
_userKey
);
if
(
userJson
==
null
)
return
null
;
return
User
.
fromJson
(
jsonDecode
(
userJson
));
}
static
Future
<
void
>
clearUser
()
async
{
final
prefs
=
await
SharedPreferences
.
getInstance
();
await
prefs
.
remove
(
_userKey
);
}
static
const
String
_workbenchTokenKey
=
'workbench_token'
;
Future
<
void
>
setWorkbenchToken
(
String
token
)
async
{
await
_prefs
.
setString
(
_workbenchTokenKey
,
token
);
}
String
?
getWorkbenchToken
()
{
return
_prefs
.
getString
(
_workbenchTokenKey
);
}
Future
<
void
>
saveWorkbenchToken
(
String
token
)
async
{
await
_prefs
.
setString
(
_workbenchTokenKey
,
token
);
}
}
pubspec.lock
浏览文件 @
02c8e358
...
...
@@ -190,6 +190,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.6.23"
flutter_riverpod:
dependency: "direct main"
description:
name: flutter_riverpod
sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.6.1"
flutter_test:
dependency: "direct dev"
description: flutter
...
...
@@ -392,6 +400,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.8"
riverpod:
dependency: transitive
description:
name: riverpod
sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.6.1"
shared_preferences:
dependency: "direct main"
description:
...
...
@@ -501,6 +517,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.11.1"
state_notifier:
dependency: transitive
description:
name: state_notifier
sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
stream_channel:
dependency: transitive
description:
...
...
pubspec.yaml
浏览文件 @
02c8e358
name
:
allen
description
:
A new Flutter project.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to
:
'
none'
# Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
...
...
@@ -19,80 +21,278 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version
:
1.0.0+1
environment
:
sdk
:
'
>=2.19.5
<3.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies
:
flutter
:
sdk
:
flutter
http
:
^1.1.0
flutter_riverpod
:
^2.5.1
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons
:
^1.0.2
speech_to_text
:
^6.1.1
flutter_tts
:
^3.6.3
animate_do
:
^3.0.2
shared_preferences
:
^2.0.15
uuid
:
^4.3.3
flutter_markdown
:
^0.6.18
flutter_highlight
:
^0.7.0
markdown
:
^7.1.1
audioplayers
:
^5.2.1
dev_dependencies
:
flutter_test
:
sdk
:
flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints
:
^2.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter
:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design
:
true
# To add assets to your application, add an assets section, like this:
assets
:
-
assets/images/
-
assets/sounds/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
fonts
:
-
family
:
Cera Pro
fonts
:
-
asset
:
assets/fonts/Cera-Pro-Bold.otf
-
asset
:
assets/fonts/Cera-Pro-Medium.otf
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论