feat: add open ai key to database (#1852)

* feat: add open ai key to database

* chore: refactor code
This commit is contained in:
Lucas.Xu 2023-02-14 10:04:36 +08:00 committed by GitHub
parent 7207e35349
commit 72e155f5b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 125 additions and 15 deletions

View File

@ -191,6 +191,12 @@
"create": "Create",
"folderPath": "Path to store your folder",
"locationCannotBeEmpty": "Path cannot be empty"
},
"user": {
"name": "Name",
"icon": "Icon",
"selectAnIcon": "Select an icon",
"pleaseInputYourOpenAIKey": "please input your OpenAI key"
}
},
"grid": {

View File

@ -21,6 +21,7 @@ class UserService {
String? password,
String? email,
String? iconUrl,
String? openAIKey,
}) {
var payload = UpdateUserProfilePayloadPB.create()..id = userId;
@ -40,6 +41,10 @@ class UserService {
payload.iconUrl = iconUrl;
}
if (openAIKey != null) {
payload.openaiKey = openAIKey;
}
return UserEventUpdateUserProfile(payload).send();
}

View File

@ -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.updateUserIcon(String iconUrl) =
_UpdateUserIcon;
const factory SettingsUserEvent.updateUserOpenaiKey(String openAIKey) =
_UpdateUserOpenaiKey;
const factory SettingsUserEvent.didReceiveUserProfile(
UserProfilePB newUserProfile) = _DidReceiveUserProfile;
}

View File

@ -7,6 +7,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.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';
@ -28,7 +30,9 @@ class SettingsUserView extends StatelessWidget {
children: [
_renderUserNameInput(context),
const VSpace(20),
_renderCurrentIcon(context)
_renderCurrentIcon(context),
const VSpace(20),
_renderCurrentOpenaiKey(context)
],
),
),
@ -49,6 +53,12 @@ class SettingsUserView extends StatelessWidget {
}
return _CurrentIcon(iconUrl);
}
Widget _renderCurrentOpenaiKey(BuildContext context) {
String openAIKey =
context.read<SettingsUserViewBloc>().state.userProfile.openaiKey;
return _OpenaiKeyInput(openAIKey);
}
}
@visibleForTesting
@ -62,15 +72,41 @@ class UserNameInput extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextField(
controller: TextEditingController()..text = name,
decoration: const InputDecoration(
labelText: 'Name',
),
onSubmitted: (val) {
context
.read<SettingsUserViewBloc>()
.add(SettingsUserEvent.updateUserName(val));
});
controller: TextEditingController()..text = name,
decoration: InputDecoration(
labelText: LocaleKeys.settings_user_name.tr(),
),
onSubmitted: (val) {
context
.read<SettingsUserViewBloc>()
.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) {
return SimpleDialog(
title: FlowyText.medium(
'Select an Icon',
LocaleKeys.settings_user_selectAnIcon.tr(),
fontSize: FontSizes.s16,
),
children: <Widget>[
@ -112,11 +148,11 @@ class _CurrentIcon extends StatelessWidget {
},
child: Column(
children: <Widget>[
const Align(
Align(
alignment: Alignment.topLeft,
child: Text(
"Icon",
style: TextStyle(color: Colors.grey),
LocaleKeys.settings_user_icon.tr(),
style: const TextStyle(color: Colors.grey),
)),
Align(
alignment: Alignment.centerLeft,

View File

@ -0,0 +1 @@
ALTER TABLE user_table DROP COLUMN openai_key;

View File

@ -0,0 +1 @@
ALTER TABLE user_table ADD COLUMN openai_key TEXT NOT NULL DEFAULT '';

View File

@ -146,6 +146,7 @@ diesel::table! {
email -> Text,
workspace -> Text,
icon_url -> Text,
openai_key -> Text,
}
}

View File

@ -2,7 +2,8 @@ use crate::errors::ErrorCode;
use flowy_derive::ProtoBuf;
use std::convert::TryInto;
use user_model::{
UpdateUserProfileParams, UserEmail, UserIcon, UserId, UserName, UserPassword, UserProfile,
UpdateUserProfileParams, UserEmail, UserIcon, UserId, UserName, UserOpenaiKey, UserPassword,
UserProfile,
};
#[derive(Default, ProtoBuf)]
@ -33,6 +34,9 @@ pub struct UserProfilePB {
#[pb(index = 5)]
pub icon_url: String,
#[pb(index = 6)]
pub openai_key: String,
}
impl std::convert::From<UserProfile> for UserProfilePB {
@ -43,6 +47,7 @@ impl std::convert::From<UserProfile> for UserProfilePB {
name: user_profile.name,
token: user_profile.token,
icon_url: user_profile.icon_url,
openai_key: user_profile.openai_key,
}
}
}
@ -63,6 +68,9 @@ pub struct UpdateUserProfilePayloadPB {
#[pb(index = 5, one_of)]
pub icon_url: Option<String>,
#[pb(index = 6, one_of)]
pub openai_key: Option<String>,
}
impl UpdateUserProfilePayloadPB {
@ -92,6 +100,11 @@ impl UpdateUserProfilePayloadPB {
self.icon_url = Some(icon_url.to_owned());
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 {
@ -120,12 +133,18 @@ impl TryInto<UpdateUserProfileParams> for UpdateUserProfilePayloadPB {
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 {
id,
name,
email,
password,
icon_url,
openai_key,
})
}
}

View File

@ -84,6 +84,7 @@ pub struct UserTable {
pub(crate) email: String,
pub(crate) workspace: String, // deprecated
pub(crate) icon_url: String,
pub(crate) openai_key: String,
}
impl UserTable {
@ -95,6 +96,7 @@ impl UserTable {
token,
icon_url: "".to_owned(),
workspace: "".to_owned(),
openai_key: "".to_owned(),
}
}
@ -124,6 +126,7 @@ impl std::convert::From<UserTable> for UserProfile {
name: table.name,
token: table.token,
icon_url: table.icon_url,
openai_key: table.openai_key,
}
}
}
@ -136,6 +139,7 @@ pub struct UserTableChangeset {
pub name: Option<String>,
pub email: Option<String>,
pub icon_url: Option<String>,
pub openai_key: Option<String>,
}
impl UserTableChangeset {
@ -146,6 +150,7 @@ impl UserTableChangeset {
name: params.name,
email: params.email,
icon_url: params.icon_url,
openai_key: params.openai_key,
}
}
}

View File

@ -42,6 +42,7 @@ pub struct UserProfile {
pub name: String,
pub token: String,
pub icon_url: String,
pub openai_key: String,
}
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
@ -51,6 +52,7 @@ pub struct UpdateUserProfileParams {
pub email: Option<String>,
pub password: Option<String>,
pub icon_url: Option<String>,
pub openai_key: Option<String>,
}
impl UpdateUserProfileParams {
@ -61,6 +63,7 @@ impl UpdateUserProfileParams {
email: None,
password: None,
icon_url: None,
openai_key: None,
}
}
@ -83,4 +86,9 @@ impl UpdateUserProfileParams {
self.icon_url = Some(icon_url.to_owned());
self
}
pub fn openai_key(mut self, openai_key: &str) -> Self {
self.openai_key = Some(openai_key.to_owned());
self
}
}

View File

@ -3,6 +3,7 @@ mod user_email;
mod user_icon;
mod user_id;
mod user_name;
mod user_openai_key;
mod user_password;
mod user_workspace;
@ -10,5 +11,6 @@ pub use user_email::*;
pub use user_icon::*;
pub use user_id::*;
pub use user_name::*;
pub use user_openai_key::*;
pub use user_password::*;
pub use user_workspace::*;

View 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
}
}