moved status to icon with additional information in tooltip

This commit is contained in:
KCaverly 2023-10-05 16:49:25 +03:00
parent ec1b4e6f85
commit 0666fa80ac
4 changed files with 161 additions and 51 deletions

View File

@ -85,25 +85,6 @@ impl Embedding {
} }
} }
// impl FromSql for Embedding {
// fn column_result(value: ValueRef) -> FromSqlResult<Self> {
// let bytes = value.as_blob()?;
// let embedding: Result<Vec<f32>, Box<bincode::ErrorKind>> = bincode::deserialize(bytes);
// if embedding.is_err() {
// return Err(rusqlite::types::FromSqlError::Other(embedding.unwrap_err()));
// }
// Ok(Embedding(embedding.unwrap()))
// }
// }
// impl ToSql for Embedding {
// fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
// let bytes = bincode::serialize(&self.0)
// .map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?;
// Ok(ToSqlOutput::Owned(rusqlite::types::Value::Blob(bytes)))
// }
// }
#[derive(Clone)] #[derive(Clone)]
pub struct OpenAIEmbeddings { pub struct OpenAIEmbeddings {
pub client: Arc<dyn HttpClient>, pub client: Arc<dyn HttpClient>,
@ -290,7 +271,7 @@ impl EmbeddingProvider for OpenAIEmbeddings {
let mut request_number = 0; let mut request_number = 0;
let mut rate_limiting = false; let mut rate_limiting = false;
let mut request_timeout: u64 = 30; let mut request_timeout: u64 = 15;
let mut response: Response<AsyncBody>; let mut response: Response<AsyncBody>;
while request_number < MAX_RETRIES { while request_number < MAX_RETRIES {
response = self response = self
@ -300,6 +281,7 @@ impl EmbeddingProvider for OpenAIEmbeddings {
request_timeout, request_timeout,
) )
.await?; .await?;
request_number += 1; request_number += 1;
match response.status() { match response.status() {

View File

@ -52,7 +52,7 @@ use std::{
}; };
use theme::{ use theme::{
components::{action_button::Button, ComponentExt}, components::{action_button::Button, ComponentExt},
AssistantStyle, AssistantStyle, Icon,
}; };
use util::{paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt}; use util::{paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt};
use uuid::Uuid; use uuid::Uuid;
@ -2857,10 +2857,7 @@ impl View for InlineAssistant {
.with_children(if self.retrieve_context { .with_children(if self.retrieve_context {
Some( Some(
Flex::row() Flex::row()
.with_child(Label::new( .with_children(self.retrieve_context_status(cx))
self.retrieve_context_status(cx),
theme.assistant.inline.context_status.text.clone(),
))
.flex(1., true) .flex(1., true)
.aligned(), .aligned(),
) )
@ -3110,40 +3107,149 @@ impl InlineAssistant {
anyhow::Ok(()) anyhow::Ok(())
} }
fn retrieve_context_status(&self, cx: &mut ViewContext<Self>) -> String { fn retrieve_context_status(
&self,
cx: &mut ViewContext<Self>,
) -> Option<AnyElement<InlineAssistant>> {
enum ContextStatusIcon {}
let project = self.project.clone(); let project = self.project.clone();
if let Some(semantic_index) = self.semantic_index.clone() { if let Some(semantic_index) = SemanticIndex::global(cx) {
let status = semantic_index.update(cx, |index, cx| index.status(&project)); let status = semantic_index.update(cx, |index, _| index.status(&project));
return match status { let theme = theme::current(cx);
// This theoretically shouldnt be a valid code path match status {
semantic_index::SemanticIndexStatus::NotAuthenticated => { SemanticIndexStatus::NotAuthenticated {} => Some(
"Not Authenticated!\nPlease ensure you have an `OPENAI_API_KEY` in your environment variables.".to_string() Svg::new("icons/error.svg")
} .with_color(theme.assistant.error_icon.color)
semantic_index::SemanticIndexStatus::Indexed => { .constrained()
"Indexing Complete!".to_string() .with_width(theme.assistant.error_icon.width)
} .contained()
semantic_index::SemanticIndexStatus::Indexing { remaining_files, rate_limit_expiry } => { .with_style(theme.assistant.error_icon.container)
.with_tooltip::<ContextStatusIcon>(
self.id,
"Not Authenticated. Please ensure you have a valid 'OPENAI_API_KEY' in your environment variables.",
None,
theme.tooltip.clone(),
cx,
)
.aligned()
.into_any(),
),
SemanticIndexStatus::NotIndexed {} => Some(
Svg::new("icons/error.svg")
.with_color(theme.assistant.inline.context_status.error_icon.color)
.constrained()
.with_width(theme.assistant.inline.context_status.error_icon.width)
.contained()
.with_style(theme.assistant.inline.context_status.error_icon.container)
.with_tooltip::<ContextStatusIcon>(
self.id,
"Not Indexed",
None,
theme.tooltip.clone(),
cx,
)
.aligned()
.into_any(),
),
SemanticIndexStatus::Indexing {
remaining_files,
rate_limit_expiry,
} => {
let mut status = format!("Remaining files to index for Context Retrieval: {remaining_files}"); let mut status_text = if remaining_files == 0 {
"Indexing...".to_string()
} else {
format!("Remaining files to index: {remaining_files}")
};
if let Some(rate_limit_expiry) = rate_limit_expiry { if let Some(rate_limit_expiry) = rate_limit_expiry {
let remaining_seconds = let remaining_seconds = rate_limit_expiry.duration_since(Instant::now());
rate_limit_expiry.duration_since(Instant::now()); if remaining_seconds > Duration::from_secs(0) && remaining_files > 0 {
if remaining_seconds > Duration::from_secs(0) { write!(
write!(status, " (rate limit resets in {}s)", remaining_seconds.as_secs()).unwrap(); status_text,
" (rate limit expires in {}s)",
remaining_seconds.as_secs()
)
.unwrap();
} }
} }
status Some(
Svg::new("icons/bolt.svg")
.with_color(theme.assistant.inline.context_status.in_progress_icon.color)
.constrained()
.with_width(theme.assistant.inline.context_status.in_progress_icon.width)
.contained()
.with_style(theme.assistant.inline.context_status.in_progress_icon.container)
.with_tooltip::<ContextStatusIcon>(
self.id,
status_text,
None,
theme.tooltip.clone(),
cx,
)
.aligned()
.into_any(),
)
} }
semantic_index::SemanticIndexStatus::NotIndexed => { SemanticIndexStatus::Indexed {} => Some(
"Not Indexed for Context Retrieval".to_string() Svg::new("icons/circle_check.svg")
} .with_color(theme.assistant.inline.context_status.complete_icon.color)
}; .constrained()
.with_width(theme.assistant.inline.context_status.complete_icon.width)
.contained()
.with_style(theme.assistant.inline.context_status.complete_icon.container)
.with_tooltip::<ContextStatusIcon>(
self.id,
"Indexing Complete",
None,
theme.tooltip.clone(),
cx,
)
.aligned()
.into_any(),
),
}
} else {
None
} }
"".to_string()
} }
// fn retrieve_context_status(&self, cx: &mut ViewContext<Self>) -> String {
// let project = self.project.clone();
// if let Some(semantic_index) = self.semantic_index.clone() {
// let status = semantic_index.update(cx, |index, cx| index.status(&project));
// return match status {
// // This theoretically shouldnt be a valid code path
// // As the inline assistant cant be launched without an API key
// // We keep it here for safety
// semantic_index::SemanticIndexStatus::NotAuthenticated => {
// "Not Authenticated!\nPlease ensure you have an `OPENAI_API_KEY` in your environment variables.".to_string()
// }
// semantic_index::SemanticIndexStatus::Indexed => {
// "Indexing Complete!".to_string()
// }
// semantic_index::SemanticIndexStatus::Indexing { remaining_files, rate_limit_expiry } => {
// let mut status = format!("Remaining files to index for Context Retrieval: {remaining_files}");
// if let Some(rate_limit_expiry) = rate_limit_expiry {
// let remaining_seconds =
// rate_limit_expiry.duration_since(Instant::now());
// if remaining_seconds > Duration::from_secs(0) {
// write!(status, " (rate limit resets in {}s)", remaining_seconds.as_secs()).unwrap();
// }
// }
// status
// }
// semantic_index::SemanticIndexStatus::NotIndexed => {
// "Not Indexed for Context Retrieval".to_string()
// }
// };
// }
// "".to_string()
// }
fn toggle_include_conversation( fn toggle_include_conversation(
&mut self, &mut self,
_: &ToggleIncludeConversation, _: &ToggleIncludeConversation,

View File

@ -1191,7 +1191,14 @@ pub struct InlineAssistantStyle {
pub pending_edit_background: Color, pub pending_edit_background: Color,
pub include_conversation: ToggleIconButtonStyle, pub include_conversation: ToggleIconButtonStyle,
pub retrieve_context: ToggleIconButtonStyle, pub retrieve_context: ToggleIconButtonStyle,
pub context_status: ContainedText, pub context_status: ContextStatusStyle,
}
#[derive(Clone, Deserialize, Default, JsonSchema)]
pub struct ContextStatusStyle {
pub error_icon: Icon,
pub in_progress_icon: Icon,
pub complete_icon: Icon,
} }
#[derive(Clone, Deserialize, Default, JsonSchema)] #[derive(Clone, Deserialize, Default, JsonSchema)]

View File

@ -80,7 +80,21 @@ export default function assistant(): any {
}, },
pending_edit_background: background(theme.highest, "positive"), pending_edit_background: background(theme.highest, "positive"),
context_status: { context_status: {
...text(theme.highest, "mono", "disabled", { size: "sm" }), error_icon: {
margin: { left: 8, right: 8 },
color: foreground(theme.highest, "negative"),
width: 12,
},
in_progress_icon: {
margin: { left: 8, right: 8 },
color: foreground(theme.highest, "warning"),
width: 12,
},
complete_icon: {
margin: { left: 8, right: 8 },
color: foreground(theme.highest, "positive"),
width: 12,
}
}, },
retrieve_context: toggleable({ retrieve_context: toggleable({
base: interactive({ base: interactive({
@ -94,6 +108,7 @@ export default function assistant(): any {
border: { border: {
width: 1., color: background(theme.highest, "on") width: 1., color: background(theme.highest, "on")
}, },
margin: { left: 2 },
padding: { padding: {
left: 4, left: 4,
right: 4, right: 4,