Skip to content

Commit

Permalink
Merge pull request #61 from neatwork-ai/chat-app-4
Browse files Browse the repository at this point in the history
Chat App 4
  • Loading branch information
kaizu-xyz authored Nov 2, 2023
2 parents 66379d9 + c3e1521 commit fdfebc4
Show file tree
Hide file tree
Showing 33 changed files with 1,232 additions and 721 deletions.
1 change: 1 addition & 0 deletions crates/neatcoder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ js-sys = "0.3"
wasm-bindgen-futures = "0.4.37"
serde-wasm-bindgen = "0.5.0"
web-sys = { version = "0.3", features = ['console'] }
chrono = {version = "0.4", features = ["serde"]}

[dev-dependencies]
wasm-bindgen-test = "0.3"
1 change: 1 addition & 0 deletions crates/neatcoder/src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
///< Constants used throughout the application.
pub const CONFIG_EXTENSIONS: [&str; 15] = [
"txt", "json", "toml", "lock", "yaml", "gemspec", "xml", "gradle",
"csproj", "config", "sln", "mod", "sbt", "cabal", "md",
Expand Down
64 changes: 64 additions & 0 deletions crates/neatcoder/src/endpoints/get_chat_title.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use anyhow::{anyhow, Result};
use js_sys::Function;

use crate::openai::{
msg::{GptRole, OpenAIMsg},
params::{OpenAIModels, OpenAIParams},
request::chat_raw,
};

pub async fn get_chat_title(
msg: &str,
request_callback: &Function,
) -> Result<String> {
let mut prompts = Vec::new();

prompts.push(OpenAIMsg {
role: GptRole::System,
content: String::from(
"
- Context: Briefly describe the key topics or themes of the chat.
- Title Specifications: The title should be concise, and not exceed 6 words. It should reflect the tone of the chat (e.g., professional, casual, informative, provocative, etc.).
- Output: Provide a title that encapsulates the main focus of the chat.
",
),
});

let main_prompt = format!(
"
Your task is to create a title for the following prompt:
\"\"\"{}\"\"\"
The title of the prompt is:",
msg
);

prompts.push(OpenAIMsg {
role: GptRole::User,
content: main_prompt,
});

let prompts = prompts.iter().map(|x| x).collect::<Vec<&OpenAIMsg>>();

let ai_params =
OpenAIParams::empty(OpenAIModels::Gpt35Turbo).max_tokens(15);

let chat =
chat_raw(request_callback, &ai_params, &prompts, &[], &[]).await?;

let mut answer = chat
.choices
.first()
.ok_or_else(|| anyhow!("LLM Respose seems to be empty :("))?
.message
.content
.clone();

answer = clean_title(answer);

Ok(answer)
}

fn clean_title(answer: String) -> String {
answer.replace("\"", "")
}
2 changes: 2 additions & 0 deletions crates/neatcoder/src/endpoints/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
///< internal API endpoint definitions.
pub mod scaffold_project;
pub mod stream_code;
pub mod get_chat_title;
48 changes: 40 additions & 8 deletions crates/neatcoder/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use js_sys::Reflect;
use chrono::{DateTime, Utc};
use js_sys::{Date as IDate, Reflect};
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_wasm_bindgen::to_value;
Expand All @@ -7,19 +8,13 @@ use std::hash::Hash;
use utils::log_err;
use wasm_bindgen::{JsCast, JsValue};

// Public modules declaration
pub mod consts;
///< Constants used throughout the application.
pub mod endpoints;
///< internal API endpoint definitions.
pub mod models;
///< Data models used in the application.
pub mod openai;
///< Client for interacting with the OpenAI API.
pub mod prelude;
///< Re-exports commonly used items.
pub mod typescript;
pub mod utils;
///< Contains utility functions and helpers.

/// Type alias for JavaScript errors represented as JsValue
pub type JsError = JsValue;
Expand Down Expand Up @@ -336,3 +331,40 @@ where
})
}
}

impl WasmType<IDate> for DateTime<Utc> {
type RustType = DateTime<Utc>;

fn to_extern(rust_type: Self::RustType) -> Result<IDate, JsError> {
// Convert the Rust DateTime<Utc> to a string
let iso_string = rust_type.to_rfc3339();
// Create a new JavaScript Date object from the string
let js_date = js_sys::Date::new(&JsValue::from_str(&iso_string));

// Check if the conversion was successful
if js_date.is_instance_of::<js_sys::Date>() {
Ok(js_date)
} else {
Err(JsError::from(
"Failed to create JavaScript Date object.".to_owned(),
))
}
}

fn from_extern(extern_type: IDate) -> Result<Self::RustType, JsError> {
// Ensure we have a Date object
if let Some(date) = extern_type.dyn_into::<js_sys::Date>().ok() {
// Convert the JavaScript Date object to an ISO string
let iso_string =
date.to_iso_string().as_string().unwrap_or_default();
// Parse the ISO string into a Rust DateTime<Utc>
DateTime::parse_from_rfc3339(&iso_string)
.map(|dt| dt.with_timezone(&Utc))
.map_err(|e| JsError::from(e.to_string()))
} else {
Err(JsError::from(
"Input JsValue is not a Date object.".to_owned(),
))
}
}
}
3 changes: 2 additions & 1 deletion crates/neatcoder/src/models/app_data/interfaces/apis.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::{AsContext, ISchemas, SchemaFile};
use super::{AsContext, SchemaFile};
use crate::{
openai::msg::{GptRole, OpenAIMsg},
typescript::ISchemas,
JsError, WasmType,
};
use anyhow::Result;
Expand Down
3 changes: 2 additions & 1 deletion crates/neatcoder/src/models/app_data/interfaces/dbs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::{AsContext, ISchemas, SchemaFile};
use super::{AsContext, SchemaFile};
use crate::{
openai::msg::{GptRole, OpenAIMsg},
typescript::ISchemas,
JsError, WasmType,
};
use anyhow::Result;
Expand Down
8 changes: 1 addition & 7 deletions crates/neatcoder/src/models/app_data/interfaces/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@ pub mod dbs;
pub mod storage;

use self::{apis::Api, dbs::Database, storage::Storage};
use crate::{openai::msg::OpenAIMsg, JsError};
use crate::{openai::msg::OpenAIMsg, typescript::ISchemas, JsError};
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "Record<string, string>")]
pub type ISchemas;
}

#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
#[wasm_bindgen]
Expand Down
3 changes: 2 additions & 1 deletion crates/neatcoder/src/models/app_data/interfaces/storage.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
openai::msg::{GptRole, OpenAIMsg},
typescript::ISchemas,
JsError, WasmType,
};
use anyhow::Result;
Expand All @@ -11,7 +12,7 @@ use std::{
};
use wasm_bindgen::prelude::wasm_bindgen;

use super::{AsContext, ISchemas, SchemaFile};
use super::{AsContext, SchemaFile};

/// Struct documenting a Data storage interface. This refers to more raw storage
/// solutions that usually provide a direct interface to a file or object-store
Expand Down
13 changes: 1 addition & 12 deletions crates/neatcoder/src/models/app_data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
stream_code::{stream_code, CodeGenParams},
},
openai::params::OpenAIParams,
typescript::{ICodebase, IInterfaces, ITasksVec},
JsError, WasmType,
};
use anyhow::{anyhow, Result};
Expand Down Expand Up @@ -83,18 +84,6 @@ pub struct AppData {
pub(crate) task_pool: TaskPool,
}

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "Record<string, Interface>")]
pub type IInterfaces;

#[wasm_bindgen(typescript_type = "Record<string, string>")]
pub type ICodebase;

#[wasm_bindgen(typescript_type = "Array<Task>")]
pub type ITasksVec;
}

#[wasm_bindgen]
impl AppData {
#[wasm_bindgen(constructor)]
Expand Down
14 changes: 4 additions & 10 deletions crates/neatcoder/src/models/app_data/task_pool/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
pub mod task;
pub mod task_params;
use self::{task::Task, task_params::TaskParams};
use crate::{JsError, WasmType};
use crate::{
typescript::{IOrder, ITasks},
JsError, WasmType,
};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, VecDeque};
Expand Down Expand Up @@ -141,15 +144,6 @@ impl TaskPool {
pub type Todo = Pipeline;
pub type Done = Pipeline;

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "Record<number, Task>")]
pub type ITasks;

#[wasm_bindgen(typescript_type = "Array<number>")]
pub type IOrder;
}

#[wasm_bindgen]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
Expand Down
Loading

0 comments on commit fdfebc4

Please sign in to comment.