Skip to content

Commit

Permalink
Merge pull request #70 from solaoi/main
Browse files Browse the repository at this point in the history
update to v0.9.1
  • Loading branch information
solaoi authored Jun 5, 2023
2 parents ba69c98 + 8d6e5ed commit 876a1c0
Show file tree
Hide file tree
Showing 11 changed files with 315 additions and 25 deletions.
4 changes: 4 additions & 0 deletions src-tauri/migrations/001.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ INSERT INTO settings(setting_name, setting_status) VALUES("transcriptionAccuracy
INSERT INTO settings(setting_name, setting_status) VALUES("settingKeyOpenai", "");
INSERT INTO settings(setting_name, setting_status) VALUES("settingLanguage", "日本語");
INSERT INTO settings(setting_name, setting_status) VALUES("settingTemplate", "");
INSERT INTO settings(setting_name, setting_status) VALUES("settingHook", "");
INSERT INTO settings(setting_name, setting_status) VALUES("settingResource", "");
INSERT INTO settings(setting_name, setting_status) VALUES("settingModel", "gpt-3.5-turbo");
INSERT INTO settings(setting_name, setting_status) VALUES("settingAILanguage", "None");
CREATE TABLE models (
id INTEGER PRIMARY KEY AUTOINCREMENT,
model_name TEXT,
Expand Down
109 changes: 95 additions & 14 deletions src-tauri/src/module/chat_online.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,12 @@ impl ChatOnline {

#[tokio::main]
async fn request_gpt(
model: &str,
question: &str,
token: String,
template: String,
) -> Result<String, Box<dyn std::error::Error>> {
let url = "https://api.openai.com/v1/chat/completions";

let model = "gpt-3.5-turbo";
let temperature = 0;

let client = Client::new();
Expand Down Expand Up @@ -197,14 +196,20 @@ impl ChatOnline {
.send()
.await?;

println!("Status: {}", response.status());
// println!("Status: {}", response.status());
let status = response.status();
let json_response: Value = response.json().await?;
println!("Response: {:?}", json_response);
let response_text = json_response["choices"][0]["message"]["content"]
.as_str()
.unwrap_or("choices[0].message.content field not found");
// println!("Response: {:?}", json_response);
let response_text = if status == 200 {
json_response["choices"][0]["message"]["content"]
.as_str()
.unwrap_or("choices[0].message.content field not found")
.to_string()
} else {
json_response.to_string()
};

Ok(response_text.to_string())
Ok(response_text)
}

fn convert(&mut self) -> Result<(), rusqlite::Error> {
Expand All @@ -217,24 +222,100 @@ impl ChatOnline {
);
if result.is_ok() {
let question = result.unwrap();

let result = self.sqlite.select_ai_resource();
let resource = if result.is_ok() {
let command = result.unwrap().replace("{{question}}", &question);
println!("command: {}", command);
if command == "" {
"".to_string()
} else {
let result = std::process::Command::new("sh")
.arg("-c")
.arg(command)
.output()
.expect("failed");
if !result.stderr.is_empty() {
String::from_utf8(result.stderr).expect("Found invalid UTF-8")
} else {
String::from_utf8(result.stdout).expect("Found invalid UTF-8")
}
}
} else {
"".to_string()
};
let result = self.sqlite.select_ai_template();
let template = if result.is_ok() {
result.unwrap()
if resource == "" {
result.unwrap()
} else {
result
.unwrap()
.replace("{{resource}}", &resource)
.replace("{{question}}", &question)
}
} else {
"".to_string()
};
let result = Self::request_gpt(&question, self.token.clone(), template);

let result = self.sqlite.select_ai_model();
let model = if result.is_ok() {
result.unwrap()
} else {
"gpt-3.5-turbo".to_string()
};
let result = Self::request_gpt(&model, &question, self.token.clone(), template);
if result.is_ok() {
let answer = result.unwrap();
let updated = self.sqlite.update_model_vosk_to_whisper(
speech.id,
format!("Q. {}\nA. {}", question, answer),
);

let result = self.sqlite.select_ai_hook();
let hook = if result.is_ok() {
result.unwrap()
} else {
"".to_string()
};
let output = if hook != "" {
let command = hook
.replace("{{resource}}", &resource)
.replace("{{answer}}", &answer)
.replace("{{question}}", &question);
let result = std::process::Command::new("sh")
.arg("-c")
.arg(command)
.output()
.expect("failed");
if !result.stderr.is_empty() {
String::from_utf8(result.stderr).expect("Found invalid UTF-8")
} else {
String::from_utf8(result.stdout).expect("Found invalid UTF-8")
}
} else {
"".to_string()
};
let message = if output != "" {
format!("Q. {}\nA. {}\nCLI. {}", question, answer, output)
} else {
format!("Q. {}\nA. {}", question, answer)
};

let updated = self.sqlite.update_model_vosk_to_whisper(speech.id, message);

self.app_handle
.clone()
.emit_all("finalTextConverted", updated.unwrap())
.unwrap();

let result = self.sqlite.select_ai_language();
if result.is_ok() {
let lang = result.unwrap();
if lang != "None" {
std::process::Command::new("sh")
.arg("-c")
.arg(format!("say -v {} \"{}\"", lang, answer))
.output()
.expect("failed");
}
}
} else {
println!("gpt api is temporally failed, so skipping...")
}
Expand Down
32 changes: 32 additions & 0 deletions src-tauri/src/module/sqlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,30 @@ impl Sqlite {
);
}

pub fn select_ai_language(&self) -> Result<String, rusqlite::Error> {
return self.conn.query_row(
"SELECT setting_status FROM settings WHERE setting_name = \"settingAILanguage\"",
params![],
|row| Ok(row.get_unwrap(0)),
);
}

pub fn select_ai_model(&self) -> Result<String, rusqlite::Error> {
return self.conn.query_row(
"SELECT setting_status FROM settings WHERE setting_name = \"settingModel\"",
params![],
|row| Ok(row.get_unwrap(0)),
);
}

pub fn select_ai_resource(&self) -> Result<String, rusqlite::Error> {
return self.conn.query_row(
"SELECT setting_status FROM settings WHERE setting_name = \"settingResource\"",
params![],
|row| Ok(row.get_unwrap(0)),
);
}

pub fn select_ai_template(&self) -> Result<String, rusqlite::Error> {
return self.conn.query_row(
"SELECT setting_status FROM settings WHERE setting_name = \"settingTemplate\"",
Expand All @@ -89,6 +113,14 @@ impl Sqlite {
);
}

pub fn select_ai_hook(&self) -> Result<String, rusqlite::Error> {
return self.conn.query_row(
"SELECT setting_status FROM settings WHERE setting_name = \"settingHook\"",
params![],
|row| Ok(row.get_unwrap(0)),
);
}

pub fn update_model_vosk_to_whisper(
&self,
id: u16,
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"package": {
"productName": "Lycoris",
"version": "0.9.0"
"version": "0.9.1"
},
"tauri": {
"allowlist": {
Expand Down
73 changes: 73 additions & 0 deletions src/components/molecules/SettingAILanguage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ChangeEvent } from "react";
import { useRecoilState } from 'recoil';
import { settingKeyState } from "../../store/atoms/settingKeyState";

const SettingAILanguage = (): JSX.Element => {
const settingAILanguages = ["None", "Kyoko", "Samantha", "Tingting", "Yuna", "Thomas", "Anna", "Milena", "Mónica", "Luciana", "Yelda", "Linh", "Alice", "Xander", "Montse", "Lesya", "Alva", "Lekha", "Zuzana", "Zosia"]
const [settingKey, setSettingKey] = useRecoilState(settingKeyState("settingAILanguage"))

const change = (e: ChangeEvent<HTMLSelectElement>) => {
const settingKey = e.target.value
setSettingKey(settingKey)
}

const mapper = (aiLanguage: string) => {
switch (aiLanguage) {
case "None":
return "しない";
case "Kyoko":
return "日本語";
case "Samantha":
return "英語";
case "Tingting":
return "中国語";
case "Yuna":
return "韓国語";
case "Thomas":
return "フランス語";
case "Anna":
return "ドイツ語";
case "Milena":
return "ロシア語";
case "Mónica":
return "スペイン語";
case "Luciana":
return "ポルトガル語";
case "Yelda":
return "トルコ語";
case "Linh":
return "ベトナム語";
case "Alice":
return "イタリア語";
case "Xander":
return "オランダ語";
case "Montse":
return "カタルーニャ語";
case "Lesya":
return "ウクライナ語";
case "Alva":
return "スウェーデン語";
case "Lekha":
return "ヒンディー語";
case "Zuzana":
return "チェコ語";
case "Zosia":
return "ポーランド語";
default:
throw new Error("unknown languageType");
}
}

return (
<div className="flex items-center mb-2">
<p className="w-[8rem]">発話</p>
<select className="select select-bordered focus:outline-none text-xs" name="setting-aiLanguage" onChange={change} >
{settingAILanguages?.map((aiLanguage, i) => (
<option key={"setting-aiLanguage" + i} value={aiLanguage} selected={aiLanguage === settingKey}>{mapper(aiLanguage)}</option>
))}
</select>
</div>
)
}

export { SettingAILanguage }
25 changes: 25 additions & 0 deletions src/components/molecules/SettingHook.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ChangeEvent } from "react";
import { useRecoilState } from 'recoil';
import { settingKeyState } from "../../store/atoms/settingKeyState";

type SettingHookProps = {
hookName: string;
}

const SettingHook = (props: SettingHookProps): JSX.Element => {
const { hookName } = props;
const [settingKey, setSettingKey] = useRecoilState(settingKeyState(hookName))
const change = (e: ChangeEvent<HTMLTextAreaElement>) => {
const settingKey = e.target.value
setSettingKey(settingKey)
}

return (
<div className="flex items-center">
<p className="w-[8rem]">CLI Hook</p>
<textarea rows={3} placeholder='echo "{{question}} > {{answer}}" > ~/Desktop/sample.txt' className="p-2.5 h-full rounded-2xl input input-bordered focus:outline-none flex-1" value={settingKey} onChange={change} onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); } }} />
</div>
)
}

export { SettingHook }
2 changes: 1 addition & 1 deletion src/components/molecules/SettingKey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const SettingKey = (props: SettingKeyProps): JSX.Element => {

return (
<div className="flex items-center mb-2">
<p className="w-[9rem]">API キー</p>
<p className="w-[8rem]">API キー</p>
<input type="password" placeholder={placeholder} className="rounded-2xl input input-bordered focus:outline-none flex-1" value={settingKey} onChange={change} />
</div>
)
Expand Down
26 changes: 26 additions & 0 deletions src/components/molecules/SettingModel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ChangeEvent } from "react";
import { useRecoilState } from 'recoil';
import { settingKeyState } from "../../store/atoms/settingKeyState";

const SettingModel = (): JSX.Element => {
const settingModels = ["gpt-3.5-turbo", "gpt-4"]
const [settingKey, setSettingKey] = useRecoilState(settingKeyState("settingModel"))

const change = (e: ChangeEvent<HTMLSelectElement>) => {
const settingKey = e.target.value
setSettingKey(settingKey)
}

return (
<div className="flex items-center mb-2">
<p className="w-[8rem]">利用モデル</p>
<select className="select select-bordered focus:outline-none text-xs" name="setting-model" onChange={change} >
{settingModels?.map((model, i) => (
<option key={"setting-model" + i} value={model} selected={model === settingKey}>{model}</option>
))}
</select>
</div>
)
}

export { SettingModel }
25 changes: 25 additions & 0 deletions src/components/molecules/SettingResource.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ChangeEvent } from "react";
import { useRecoilState } from 'recoil';
import { settingKeyState } from "../../store/atoms/settingKeyState";

type SettingResourceProps = {
resourceName: string;
}

const SettingResource = (props: SettingResourceProps): JSX.Element => {
const { resourceName } = props;
const [settingKey, setSettingKey] = useRecoilState(settingKeyState(resourceName))
const change = (e: ChangeEvent<HTMLTextAreaElement>) => {
const settingKey = e.target.value
setSettingKey(settingKey)
}

return (
<div className="flex items-center mb-2">
<p className="w-[8rem]">CLI Resource</p>
<textarea rows={3} placeholder='curl -s "https://example.com/latest?query={{question}}"' className="p-2.5 h-full rounded-2xl input input-bordered focus:outline-none flex-1" value={settingKey} onChange={change} onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); } }} />
</div>
)
}

export { SettingResource }
6 changes: 3 additions & 3 deletions src/components/molecules/SettingTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ const SettingTemplate = (props: SettingTemplateProps): JSX.Element => {
}

return (
<div className="flex items-center">
<p className="w-[9rem]">AI - System Role -</p>
<textarea rows={5} placeholder="あなたは○○の専門家です。" className="p-2.5 h-full rounded-2xl input input-bordered focus:outline-none flex-1" value={settingKey} onChange={change} />
<div className="flex items-center mb-2">
<p className="w-[8rem]">システム ロール</p>
<textarea rows={5} placeholder='あなたは〇〇の専門家です。&#13;&#13;最新の情報"""&#13;{{resource}}&#13;"""' className="p-2.5 h-full rounded-2xl input input-bordered focus:outline-none flex-1" value={settingKey} onChange={change} />
</div>
)
}
Expand Down
Loading

0 comments on commit 876a1c0

Please sign in to comment.