1
0

add openai

This commit is contained in:
syui 2024-02-11 19:37:32 +09:00
parent 7158f35da7
commit bf1de331c3
Signed by: syui
GPG Key ID: 5417CFEBAD92DF56
11 changed files with 766 additions and 102 deletions

View File

@ -1,3 +1,4 @@
use seahorse::Context;
use config::{Config, ConfigError, File}; use config::{Config, ConfigError, File};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fs; use std::fs;
@ -497,3 +498,53 @@ pub fn w_cid(cid :String, file: String, t: bool) -> bool {
return check return check
} }
} }
pub fn c_follow_all() {
let file = "/.config/ai/scpt/follow_all.zsh";
let mut f = shellexpand::tilde("~").to_string();
f.push_str(&file);
use std::process::Command;
let output = Command::new(&f).output().expect("zsh");
let d = String::from_utf8_lossy(&output.stdout);
let d = "\n".to_owned() + &d.to_string();
println!("{}", d);
}
pub fn c_openai_key(c: &Context) {
let api = c.args[0].to_string();
let o = "api='".to_owned() + &api.to_string() + &"'".to_owned();
let o = o.to_string();
let l = shellexpand::tilde("~") + "/.config/ai/openai.toml";
let l = l.to_string();
let mut l = fs::File::create(l).unwrap();
if o != "" {
l.write_all(&o.as_bytes()).unwrap();
}
println!("{:#?}", l);
}
impl Open {
pub fn new() -> Result<Self, ConfigError> {
let d = shellexpand::tilde("~") + "/.config/ai/openai.toml";
let s = Config::builder()
.add_source(File::with_name(&d))
.add_source(config::Environment::with_prefix("APP"))
.build()?;
s.try_deserialize()
}
}
#[derive(Debug, Deserialize)]
pub struct Open {
pub api: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct OpenData {
choices: Vec<Choices>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Choices {
text: String,
}

82
src/follow.rs Normal file
View File

@ -0,0 +1,82 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
use serde_json::json;
use iso8601_timestamp::Timestamp;
//use crate::data::Follow;
pub async fn post_request(u: String) -> String {
let token = data_toml(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.graph.follow".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
"record": {
"subject": u.to_string(),
"createdAt": d.to_string(),
},
}));
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}
pub async fn delete_request(u: String, rkey: String) -> String {
let token = data_toml(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_delete");
let col = "app.bsky.graph.follow".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
"rkey": rkey.to_string(),
"record": {
"subject": u.to_string(),
"createdAt": d.to_string(),
},
}));
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}

25
src/followers.rs Normal file
View File

@ -0,0 +1,25 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
//use serde_json::json;
pub async fn get_request(actor: String, cursor: Option<String>) -> String {
let token = data_toml(&"access");
let url = url(&"followers");
let cursor = cursor.unwrap();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("actor", actor),("cursor", cursor)])
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}

27
src/follows.rs Normal file
View File

@ -0,0 +1,27 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
//use serde_json::json;
pub async fn get_request(actor: String, cursor: Option<String>) -> String {
let token = data_toml(&"access");
let url = url(&"follows");
let cursor = cursor.unwrap();
//let cursor = "1682386039125::bafyreihwgwozmvqxcxrhbr65agcaa4v357p27ccrhzkjf3mz5xiozjvzfa".to_string();
//let cursor = "1682385956974::bafyreihivhux5m3sxbg33yruhw5ozhahwspnuqdsysbo57smzgptdcluem".to_string();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("actor", actor),("cursor", cursor)])
//cursor.unwrap()
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}

45
src/like.rs Normal file
View File

@ -0,0 +1,45 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
use serde_json::json;
use iso8601_timestamp::Timestamp;
pub async fn post_request(cid: String, uri: String) -> String {
let token = data_toml(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.like".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
"record": {
"subject": {
"uri": uri.to_string(),
"cid": cid.to_string()
},
"createdAt": d.to_string(),
},
}));
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}

View File

@ -5,7 +5,11 @@ use crate::ascii::c_ascii;
use crate::data::data_toml; use crate::data::data_toml;
use crate::data::url; use crate::data::url;
use crate::data::w_cfg; use crate::data::w_cfg;
use crate::data::c_follow_all;
use crate::bot::c_bot; use crate::bot::c_bot;
use crate::data::c_openai_key;
use data::ProfileIdentityResolve as ProfileIdentityResolve;
pub mod ascii; pub mod ascii;
pub mod data; pub mod data;
@ -15,12 +19,21 @@ pub mod session;
pub mod notify; pub mod notify;
pub mod notify_read; pub mod notify_read;
pub mod reply; pub mod reply;
pub mod reply_og;
pub mod reply_link; pub mod reply_link;
pub mod describe; pub mod describe;
pub mod timeline_author; pub mod timeline_author;
pub mod post; pub mod post;
pub mod post_link; pub mod post_link;
pub mod mention;
pub mod profile;
pub mod follow;
pub mod follows;
pub mod followers;
pub mod like;
pub mod repost;
pub mod bot; pub mod bot;
pub mod openai;
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
@ -35,6 +48,15 @@ fn main() {
.alias("t"), .alias("t"),
) )
) )
.command(
Command::new("bot")
.alias("b")
.action(bot),
)
.command(
Command::new("follow_all")
.action(follow_all),
)
.command( .command(
Command::new("login") Command::new("login")
.alias("l") .alias("l")
@ -81,104 +103,122 @@ fn main() {
.alias("l"), .alias("l"),
) )
) )
//.command(
// Command::new("like")
// .description("$ ai like <cid>\n\t\t\t$ ai like <cid> -u <uri>")
// .action(c_like)
// .flag(
// Flag::new("uri", FlagType::String)
// .alias("u"),
// )
// )
//.command(
// Command::new("repost")
// .description("$ ai repost <cid>\n\t\t\t$ ai repost <cid> -u <uri>")
// .action(c_repost)
// .flag(
// Flag::new("uri", FlagType::String)
// .alias("u"),
// )
//)
//.command(
// Command::new("reply-og")
// .description("$ ai reply-og\n\t\t\t$ ai reply-og <text> -c <cid> -u <uri> -i <img> -t <title> -d <description> -l <link>")
// .action(reply_og)
// .flag(
// Flag::new("uri", FlagType::String)
// .alias("u"),
// )
// .flag(
// Flag::new("cid", FlagType::String)
// .alias("c"),
// )
// .flag(
// Flag::new("link", FlagType::String)
// .alias("l"),
// )
// .flag(
// Flag::new("title", FlagType::String)
// .alias("t"),
// )
// .flag(
// Flag::new("description", FlagType::String)
// .alias("d"),
// )
// .flag(
// Flag::new("img", FlagType::String)
// .alias("i"),
// )
// )
// .command(
// Command::new("feed")
// .usage("atr f")
// .description("feed user\n\t\t\t$ atr f\n\t\t\t$ atr f -u user.bsky.social")
// .alias("f")
// .action(c_feed)
// .flag(
// Flag::new("user", FlagType::String)
// .description("user flag(ex: $ atr f -u user)")
// .alias("u"),
// )
// )
// .command(
// Command::new("reply")
// .usage("atr r {}")
// .description("reply\n\t\t\t$ atr r $text -u $uri -c $cid")
// .action(c_reply)
// .flag(
// Flag::new("uri", FlagType::String)
// .description("uri flag(ex: $ atr r -u)")
// .alias("u"),
// )
// .flag(
// Flag::new("cid", FlagType::String)
// .description("cid flag(ex: $ atr r -u -c)")
// .alias("c"),
// )
// .flag(
// Flag::new("link", FlagType::String)
// .description("link flag(ex: $ atr r $text -u $uri -c $cid -l $link)")
// .alias("l"),
// )
// )
// .command(
// Command::new("mention")
// .usage("atr mention {}")
// .description("mention\n\t\t\t$ atr @ syui.bsky.social -p $text")
// .alias("@")
// .action(c_mention)
// .flag(
// Flag::new("post", FlagType::String)
// .description("post flag\n\t\t\t$ atr @ syui.bsky.social -p text")
// .alias("p"),
// )
// )
.command( .command(
Command::new("bot") Command::new("like")
.alias("b") .description("like <cid> -u <uri>")
.action(bot), .action(like)
.flag(
Flag::new("uri", FlagType::String)
.alias("u"),
)
)
.command(
Command::new("repost")
.description("repost <cid> -u <uri>")
.action(repost)
.flag(
Flag::new("uri", FlagType::String)
.alias("u"),
)
)
.command(
Command::new("reply-og")
.description("reply-og <text> -c <cid> -u <uri> -i <img> -t <title> -d <description> -l <link>")
.action(reply_og)
.flag(
Flag::new("uri", FlagType::String)
.alias("u"),
)
.flag(
Flag::new("cid", FlagType::String)
.alias("c"),
)
.flag(
Flag::new("link", FlagType::String)
.alias("l"),
)
.flag(
Flag::new("title", FlagType::String)
.alias("t"),
)
.flag(
Flag::new("description", FlagType::String)
.alias("d"),
)
.flag(
Flag::new("img", FlagType::String)
.alias("i"),
)
)
.command(
Command::new("reply")
.description("r <text> -u <uri> -c <cid>")
.action(reply)
.flag(
Flag::new("uri", FlagType::String)
.alias("u"),
)
.flag(
Flag::new("cid", FlagType::String)
.alias("c"),
)
.flag(
Flag::new("link", FlagType::String)
.description("-l <link>")
.alias("l"),
)
)
.command(
Command::new("mention")
.description("@ <handle> -p <text>")
.alias("@")
.action(mention)
.flag(
Flag::new("post", FlagType::String)
.alias("p"),
)
)
.command(
Command::new("follow")
.description("follow <did>")
.action(follow)
.flag(
Flag::new("follows", FlagType::Bool)
.alias("s"),
)
.flag(
Flag::new("delete", FlagType::String)
.alias("d"),
)
.flag(
Flag::new("followers", FlagType::Bool)
.alias("w"),
)
.flag(
Flag::new("all", FlagType::Bool)
.alias("a"),
)
.flag(
Flag::new("cursor", FlagType::String)
.alias("c"),
)
)
.command(
Command::new("profile")
.description("pro <handle>")
.alias("pro")
.action(profile)
)
.command(
Command::new("openai")
.description("openai <text>")
.alias("chat")
.action(openai)
)
.command(
Command::new("openai-key")
.description("openai-key <API_KEY>")
.action(openai_key),
) )
; ;
app.run(args); app.run(args);
@ -192,6 +232,20 @@ fn ascii_art(c: &Context) {
} }
} }
fn bot(c: &Context) {
loop {
c_bot(c);
}
}
fn follow_all(_c: &Context) {
c_follow_all();
}
fn openai_key(c: &Context) {
c_openai_key(c);
}
fn token(c: &Context) { fn token(c: &Context) {
let m = c.args[0].to_string(); let m = c.args[0].to_string();
let h = async { let h = async {
@ -283,8 +337,136 @@ fn post(c: &Context) {
return res return res
} }
fn bot(c: &Context) { fn like(c: &Context) {
loop { refresh(c);
c_bot(c); let m = c.args[0].to_string();
let h = async {
if let Ok(uri) = c.string_flag("uri") {
let str = like::post_request(m.to_string(), uri);
println!("{}",str.await);
}
};
let res = tokio::runtime::Runtime::new().unwrap().block_on(h);
return res
}
fn repost(c: &Context) {
refresh(c);
let m = c.args[0].to_string();
let h = async {
if let Ok(uri) = c.string_flag("uri") {
let str = repost::post_request(m.to_string(), uri);
println!("{}",str.await);
}
};
let res = tokio::runtime::Runtime::new().unwrap().block_on(h);
return res
}
fn follow(c: &Context) {
refresh(c);
let m = c.args[0].to_string();
let h = async {
let handle = data_toml(&"handle");
if let Ok(cursor) = c.string_flag("cursor") {
let str = follow::post_request(m.to_string());
println!("{}", str.await);
//let str = follow::delete_request(m.to_string(), delete.to_string());
//let str = followers::get_request(handle,Some("".to_string()));
//let str = followers::get_request(handle,Some(cursor.to_string()));
//let str = follows::get_request(handle,Some("".to_string()));
let str = follows::get_request(handle,Some(cursor.to_string()));
println!("{}", str.await);
}
};
let res = tokio::runtime::Runtime::new().unwrap().block_on(h);
return res
}
fn profile(c: &Context) {
refresh(c);
let h = async {
if c.args.len() == 0 {
let j = profile::get_request(data_toml(&"handle")).await;
println!("{}", j);
} else {
let j = profile::get_request(c.args[0].to_string()).await;
println!("{}", j);
}
};
let res = tokio::runtime::Runtime::new().unwrap().block_on(h);
return res
}
fn mention(c: &Context) {
refresh(c);
let m = c.args[0].to_string();
let h = async {
let str = profile::get_request(m.to_string()).await;
let profile: ProfileIdentityResolve = serde_json::from_str(&str).unwrap();
let udid = profile.did;
let handle = m.to_string();
let at = "@".to_owned() + &handle;
let e = at.chars().count();
let s = 0;
if let Ok(post) = c.string_flag("post") {
let str = mention::post_request(post.to_string(), at.to_string(), udid.to_string(), s, e.try_into().unwrap()).await;
println!("{}",str);
}
};
let res = tokio::runtime::Runtime::new().unwrap().block_on(h);
return res
}
fn reply(c: &Context) {
refresh(c);
let m = c.args[0].to_string();
let h = async {
if let Ok(cid) = c.string_flag("cid") {
if let Ok(uri) = c.string_flag("uri") {
if let Ok(link) = c.string_flag("link") {
let s = 0;
let e = link.chars().count();
let str = reply_link::post_request(m.to_string(), link.to_string(), s, e.try_into().unwrap(), cid.to_string(), uri.to_string(), cid.to_string(), uri.to_string()).await;
println!("{}", str);
} else {
let str = reply::post_request(m.to_string(), cid.to_string(), uri.to_string(), cid.to_string(), uri.to_string()).await;
println!("{}", str);
}
}
}
};
let res = tokio::runtime::Runtime::new().unwrap().block_on(h);
return res
}
fn reply_og(c: &Context) {
let m = c.args[0].to_string();
if let Ok(link) = c.string_flag("link") {
if let Ok(cid) = c.string_flag("cid") {
if let Ok(uri) = c.string_flag("uri") {
if let Ok(title) = c.string_flag("title") {
if let Ok(description) = c.string_flag("description") {
if let Ok(img) = c.string_flag("img") {
let h = async {
let str = reply_og::post_request(m.to_string(),link.to_string(),cid.to_string(),uri.to_string(), img.to_string(), title.to_string(), description.to_string());
println!("{}",str.await);
};
tokio::runtime::Runtime::new().unwrap().block_on(h);
}
}
}
}
}
} }
} }
fn openai(c: &Context) {
let m = c.args[0].to_string();
let h = async {
let str = openai::post_request(m.to_string()).await;
println!("{}", str);
};
let res = tokio::runtime::Runtime::new().unwrap().block_on(h);
return res
}

57
src/mention.rs Normal file
View File

@ -0,0 +1,57 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
use serde_json::json;
use iso8601_timestamp::Timestamp;
pub async fn post_request(text: String, at: String, udid: String, s: i32, e: i32) -> String {
let token = data_toml(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
"did": did.to_string(),
"repo": handle.to_string(),
"collection": col.to_string(),
"record": {
"text": at.to_string() + &" ".to_string() + &text.to_string(),
"$type": "app.bsky.feed.post",
"createdAt": d.to_string(),
"facets": [
{
"$type": "app.bsky.richtext.facet",
"index": {
"byteEnd": e,
"byteStart": s
},"features": [
{
"did": udid.to_string(),
"$type": "app.bsky.richtext.facet#mention"
}
]
}
]
},
}));
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}

60
src/openai.rs Normal file
View File

@ -0,0 +1,60 @@
extern crate reqwest;
use crate::data::Open;
use serde_json::{json};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type")]
struct OpenChar {
choices: Vec<ChoicesChar>,
}
#[derive(Serialize, Deserialize, Debug)]
struct ChoicesChar {
message: OpenContent,
}
#[derive(Serialize, Deserialize, Debug)]
struct OpenContent {
content: String,
}
pub async fn post_request(prompt: String) -> String {
let data = Open::new().unwrap();
let data = Open {
api: data.api,
};
let setting = "あなたはyuiという作品のアイと呼ばれるキャラクターです。第一人称は「アイ」です。
調
調
123
";
let post = Some(json!({
"model": "gpt-3.5-turbo",
"messages": [
{"role": "system", "content": &setting.to_string()},
{"role": "user", "content": &prompt.to_string()},
]
}));
let client = reqwest::Client::new();
let res = client
.post("https://api.openai.com/v1/chat/completions")
.header("Authorization", "Bearer ".to_owned() + &data.api)
.json(&post)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
let p: OpenChar = serde_json::from_str(&res).unwrap();
let o = &p.choices[0].message.content;
return o.to_string()
}

22
src/profile.rs Normal file
View File

@ -0,0 +1,22 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
pub async fn get_request(user: String) -> String {
let token = data_toml(&"access");
let url = url(&"profile_get") + &"?handle=" + &user;
let client = reqwest::Client::new();
let res = client
.get(url)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}

68
src/reply_og.rs Normal file
View File

@ -0,0 +1,68 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
use serde_json::json;
use iso8601_timestamp::Timestamp;
pub async fn post_request(m: String, link: String, cid: String, uri: String, img: String, title: String, description: String) -> String {
let token = data_toml(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
"record": {
"createdAt": d.to_string(),
"text": m.to_string(),
"embed": {
"$type": "app.bsky.embed.external",
"external": {
"uri": link.to_string(),
"thumb": {
"$type": "blob",
"ref": {
"$link": img.to_string()
},
"mimeType": "image/jpeg",
"size": 0
},
"title": title.to_string(),
"description": description.to_string()
}
},
"reply": {
"root": {
"cid": cid.to_string(),
"uri": uri.to_string()
},
"parent": {
"cid": cid.to_string(),
"uri": uri.to_string()
}
}
}
}));
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}

45
src/repost.rs Normal file
View File

@ -0,0 +1,45 @@
extern crate reqwest;
use crate::data_toml;
use crate::url;
use serde_json::json;
use iso8601_timestamp::Timestamp;
pub async fn post_request(cid: String, uri: String) -> String {
let token = data_toml(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.repost".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
"record": {
"subject": {
"uri": uri.to_string(),
"cid": cid.to_string()
},
"createdAt": d.to_string(),
},
}));
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
}