mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add open ai key to database (#1852)
* feat: add open ai key to database * chore: refactor code
This commit is contained in:
parent
7207e35349
commit
72e155f5b9
@ -191,6 +191,12 @@
|
|||||||
"create": "Create",
|
"create": "Create",
|
||||||
"folderPath": "Path to store your folder",
|
"folderPath": "Path to store your folder",
|
||||||
"locationCannotBeEmpty": "Path cannot be empty"
|
"locationCannotBeEmpty": "Path cannot be empty"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"name": "Name",
|
||||||
|
"icon": "Icon",
|
||||||
|
"selectAnIcon": "Select an icon",
|
||||||
|
"pleaseInputYourOpenAIKey": "please input your OpenAI key"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"grid": {
|
"grid": {
|
||||||
|
@ -21,6 +21,7 @@ class UserService {
|
|||||||
String? password,
|
String? password,
|
||||||
String? email,
|
String? email,
|
||||||
String? iconUrl,
|
String? iconUrl,
|
||||||
|
String? openAIKey,
|
||||||
}) {
|
}) {
|
||||||
var payload = UpdateUserProfilePayloadPB.create()..id = userId;
|
var payload = UpdateUserProfilePayloadPB.create()..id = userId;
|
||||||
|
|
||||||
@ -40,6 +41,10 @@ class UserService {
|
|||||||
payload.iconUrl = iconUrl;
|
payload.iconUrl = iconUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (openAIKey != null) {
|
||||||
|
payload.openaiKey = openAIKey;
|
||||||
|
}
|
||||||
|
|
||||||
return UserEventUpdateUserProfile(payload).send();
|
return UserEventUpdateUserProfile(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,14 @@ class SettingsUserViewBloc extends Bloc<SettingsUserEvent, SettingsUserState> {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
updateUserOpenaiKey: (openAIKey) {
|
||||||
|
_userService.updateUserProfile(openAIKey: openAIKey).then((result) {
|
||||||
|
result.fold(
|
||||||
|
(l) => null,
|
||||||
|
(err) => Log.error(err),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -73,6 +81,8 @@ class SettingsUserEvent with _$SettingsUserEvent {
|
|||||||
const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName;
|
const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName;
|
||||||
const factory SettingsUserEvent.updateUserIcon(String iconUrl) =
|
const factory SettingsUserEvent.updateUserIcon(String iconUrl) =
|
||||||
_UpdateUserIcon;
|
_UpdateUserIcon;
|
||||||
|
const factory SettingsUserEvent.updateUserOpenaiKey(String openAIKey) =
|
||||||
|
_UpdateUserOpenaiKey;
|
||||||
const factory SettingsUserEvent.didReceiveUserProfile(
|
const factory SettingsUserEvent.didReceiveUserProfile(
|
||||||
UserProfilePB newUserProfile) = _DidReceiveUserProfile;
|
UserProfilePB newUserProfile) = _DidReceiveUserProfile;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
|
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
@ -28,7 +30,9 @@ class SettingsUserView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_renderUserNameInput(context),
|
_renderUserNameInput(context),
|
||||||
const VSpace(20),
|
const VSpace(20),
|
||||||
_renderCurrentIcon(context)
|
_renderCurrentIcon(context),
|
||||||
|
const VSpace(20),
|
||||||
|
_renderCurrentOpenaiKey(context)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -49,6 +53,12 @@ class SettingsUserView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
return _CurrentIcon(iconUrl);
|
return _CurrentIcon(iconUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _renderCurrentOpenaiKey(BuildContext context) {
|
||||||
|
String openAIKey =
|
||||||
|
context.read<SettingsUserViewBloc>().state.userProfile.openaiKey;
|
||||||
|
return _OpenaiKeyInput(openAIKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
@ -62,15 +72,41 @@ class UserNameInput extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return TextField(
|
||||||
controller: TextEditingController()..text = name,
|
controller: TextEditingController()..text = name,
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Name',
|
labelText: LocaleKeys.settings_user_name.tr(),
|
||||||
),
|
),
|
||||||
onSubmitted: (val) {
|
onSubmitted: (val) {
|
||||||
context
|
context
|
||||||
.read<SettingsUserViewBloc>()
|
.read<SettingsUserViewBloc>()
|
||||||
.add(SettingsUserEvent.updateUserName(val));
|
.add(SettingsUserEvent.updateUserName(val));
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OpenaiKeyInput extends StatelessWidget {
|
||||||
|
final String openAIKey;
|
||||||
|
const _OpenaiKeyInput(
|
||||||
|
this.openAIKey, {
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TextField(
|
||||||
|
controller: TextEditingController()..text = openAIKey,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Openai Key',
|
||||||
|
hintText: LocaleKeys.settings_user_pleaseInputYourOpenAIKey.tr(),
|
||||||
|
),
|
||||||
|
onSubmitted: (val) {
|
||||||
|
// TODO: validate key
|
||||||
|
context
|
||||||
|
.read<SettingsUserViewBloc>()
|
||||||
|
.add(SettingsUserEvent.updateUserOpenaiKey(val));
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +132,7 @@ class _CurrentIcon extends StatelessWidget {
|
|||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return SimpleDialog(
|
return SimpleDialog(
|
||||||
title: FlowyText.medium(
|
title: FlowyText.medium(
|
||||||
'Select an Icon',
|
LocaleKeys.settings_user_selectAnIcon.tr(),
|
||||||
fontSize: FontSizes.s16,
|
fontSize: FontSizes.s16,
|
||||||
),
|
),
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
@ -112,11 +148,11 @@ class _CurrentIcon extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const Align(
|
Align(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Icon",
|
LocaleKeys.settings_user_icon.tr(),
|
||||||
style: TextStyle(color: Colors.grey),
|
style: const TextStyle(color: Colors.grey),
|
||||||
)),
|
)),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE user_table DROP COLUMN openai_key;
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE user_table ADD COLUMN openai_key TEXT NOT NULL DEFAULT '';
|
@ -146,6 +146,7 @@ diesel::table! {
|
|||||||
email -> Text,
|
email -> Text,
|
||||||
workspace -> Text,
|
workspace -> Text,
|
||||||
icon_url -> Text,
|
icon_url -> Text,
|
||||||
|
openai_key -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@ use crate::errors::ErrorCode;
|
|||||||
use flowy_derive::ProtoBuf;
|
use flowy_derive::ProtoBuf;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use user_model::{
|
use user_model::{
|
||||||
UpdateUserProfileParams, UserEmail, UserIcon, UserId, UserName, UserPassword, UserProfile,
|
UpdateUserProfileParams, UserEmail, UserIcon, UserId, UserName, UserOpenaiKey, UserPassword,
|
||||||
|
UserProfile,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default, ProtoBuf)]
|
#[derive(Default, ProtoBuf)]
|
||||||
@ -33,6 +34,9 @@ pub struct UserProfilePB {
|
|||||||
|
|
||||||
#[pb(index = 5)]
|
#[pb(index = 5)]
|
||||||
pub icon_url: String,
|
pub icon_url: String,
|
||||||
|
|
||||||
|
#[pb(index = 6)]
|
||||||
|
pub openai_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<UserProfile> for UserProfilePB {
|
impl std::convert::From<UserProfile> for UserProfilePB {
|
||||||
@ -43,6 +47,7 @@ impl std::convert::From<UserProfile> for UserProfilePB {
|
|||||||
name: user_profile.name,
|
name: user_profile.name,
|
||||||
token: user_profile.token,
|
token: user_profile.token,
|
||||||
icon_url: user_profile.icon_url,
|
icon_url: user_profile.icon_url,
|
||||||
|
openai_key: user_profile.openai_key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,6 +68,9 @@ pub struct UpdateUserProfilePayloadPB {
|
|||||||
|
|
||||||
#[pb(index = 5, one_of)]
|
#[pb(index = 5, one_of)]
|
||||||
pub icon_url: Option<String>,
|
pub icon_url: Option<String>,
|
||||||
|
|
||||||
|
#[pb(index = 6, one_of)]
|
||||||
|
pub openai_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateUserProfilePayloadPB {
|
impl UpdateUserProfilePayloadPB {
|
||||||
@ -92,6 +100,11 @@ impl UpdateUserProfilePayloadPB {
|
|||||||
self.icon_url = Some(icon_url.to_owned());
|
self.icon_url = Some(icon_url.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn openai_key(mut self, openai_key: &str) -> Self {
|
||||||
|
self.openai_key = Some(openai_key.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryInto<UpdateUserProfileParams> for UpdateUserProfilePayloadPB {
|
impl TryInto<UpdateUserProfileParams> for UpdateUserProfilePayloadPB {
|
||||||
@ -120,12 +133,18 @@ impl TryInto<UpdateUserProfileParams> for UpdateUserProfilePayloadPB {
|
|||||||
Some(icon_url) => Some(UserIcon::parse(icon_url)?.0),
|
Some(icon_url) => Some(UserIcon::parse(icon_url)?.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let openai_key = match self.openai_key {
|
||||||
|
None => None,
|
||||||
|
Some(openai_key) => Some(UserOpenaiKey::parse(openai_key)?.0),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(UpdateUserProfileParams {
|
Ok(UpdateUserProfileParams {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
icon_url,
|
icon_url,
|
||||||
|
openai_key,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ pub struct UserTable {
|
|||||||
pub(crate) email: String,
|
pub(crate) email: String,
|
||||||
pub(crate) workspace: String, // deprecated
|
pub(crate) workspace: String, // deprecated
|
||||||
pub(crate) icon_url: String,
|
pub(crate) icon_url: String,
|
||||||
|
pub(crate) openai_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserTable {
|
impl UserTable {
|
||||||
@ -95,6 +96,7 @@ impl UserTable {
|
|||||||
token,
|
token,
|
||||||
icon_url: "".to_owned(),
|
icon_url: "".to_owned(),
|
||||||
workspace: "".to_owned(),
|
workspace: "".to_owned(),
|
||||||
|
openai_key: "".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +126,7 @@ impl std::convert::From<UserTable> for UserProfile {
|
|||||||
name: table.name,
|
name: table.name,
|
||||||
token: table.token,
|
token: table.token,
|
||||||
icon_url: table.icon_url,
|
icon_url: table.icon_url,
|
||||||
|
openai_key: table.openai_key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,6 +139,7 @@ pub struct UserTableChangeset {
|
|||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
pub icon_url: Option<String>,
|
pub icon_url: Option<String>,
|
||||||
|
pub openai_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserTableChangeset {
|
impl UserTableChangeset {
|
||||||
@ -146,6 +150,7 @@ impl UserTableChangeset {
|
|||||||
name: params.name,
|
name: params.name,
|
||||||
email: params.email,
|
email: params.email,
|
||||||
icon_url: params.icon_url,
|
icon_url: params.icon_url,
|
||||||
|
openai_key: params.openai_key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ pub struct UserProfile {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub token: String,
|
pub token: String,
|
||||||
pub icon_url: String,
|
pub icon_url: String,
|
||||||
|
pub openai_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
||||||
@ -51,6 +52,7 @@ pub struct UpdateUserProfileParams {
|
|||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
pub icon_url: Option<String>,
|
pub icon_url: Option<String>,
|
||||||
|
pub openai_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateUserProfileParams {
|
impl UpdateUserProfileParams {
|
||||||
@ -61,6 +63,7 @@ impl UpdateUserProfileParams {
|
|||||||
email: None,
|
email: None,
|
||||||
password: None,
|
password: None,
|
||||||
icon_url: None,
|
icon_url: None,
|
||||||
|
openai_key: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,4 +86,9 @@ impl UpdateUserProfileParams {
|
|||||||
self.icon_url = Some(icon_url.to_owned());
|
self.icon_url = Some(icon_url.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn openai_key(mut self, openai_key: &str) -> Self {
|
||||||
|
self.openai_key = Some(openai_key.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ mod user_email;
|
|||||||
mod user_icon;
|
mod user_icon;
|
||||||
mod user_id;
|
mod user_id;
|
||||||
mod user_name;
|
mod user_name;
|
||||||
|
mod user_openai_key;
|
||||||
mod user_password;
|
mod user_password;
|
||||||
mod user_workspace;
|
mod user_workspace;
|
||||||
|
|
||||||
@ -10,5 +11,6 @@ pub use user_email::*;
|
|||||||
pub use user_icon::*;
|
pub use user_icon::*;
|
||||||
pub use user_id::*;
|
pub use user_id::*;
|
||||||
pub use user_name::*;
|
pub use user_name::*;
|
||||||
|
pub use user_openai_key::*;
|
||||||
pub use user_password::*;
|
pub use user_password::*;
|
||||||
pub use user_workspace::*;
|
pub use user_workspace::*;
|
||||||
|
16
shared-lib/user-model/src/parser/user_openai_key.rs
Normal file
16
shared-lib/user-model/src/parser/user_openai_key.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use crate::errors::UserErrorCode;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UserOpenaiKey(pub String);
|
||||||
|
|
||||||
|
impl UserOpenaiKey {
|
||||||
|
pub fn parse(s: String) -> Result<UserOpenaiKey, UserErrorCode> {
|
||||||
|
Ok(Self(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for UserOpenaiKey {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user