Compare commits

..

5 Commits

Author SHA1 Message Date
7a595a65ca rm lexicon
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 19s
2024-12-27 16:39:05 +09:00
73d860bf01 fix
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 15s
2024-11-14 16:19:33 +09:00
ce126faf4d add game
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2024-11-11 14:37:34 +09:00
454de01881 add lexicons
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2024-11-09 09:51:05 +09:00
57365a41a5 add card 2024-11-09 09:51:05 +09:00
12 changed files with 90 additions and 189 deletions

1
.config/ai/scpt Submodule

Submodule .config/ai/scpt added at e55225eb57

0
.config/keep Normal file
View File

View File

@@ -1,5 +0,0 @@
# Admin handle (bot will respond to admin commands from this user)
ADMIN=syui.ai
# Bluesky host (optional, default: bsky.social)
HOST=syu.is

2
.gitignore vendored
View File

@@ -17,5 +17,3 @@ pnpm-lock.yaml
**Cargo.lock **Cargo.lock
*/target/ */target/
*/**/*.rs.bk */**/*.rs.bk
.claude
.config

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "aibot" name = "ai"
authors = ["syui"] authors = ["syui"]
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"

View File

@@ -1,5 +1,9 @@
FROM syui/aios FROM syui/aios
ADD .ssh /root/.ssh
COPY ./target/release/aibot /usr/sbin/aibot
WORKDIR /root WORKDIR /root
ADD ./test/entrypoint.sh .
RUN chmod +x /root/entrypoint.sh
RUN pacman -Syu bc --noconfirm
ENTRYPOINT ["/root/entrypoint.sh"]

View File

@@ -4,61 +4,61 @@
- name : ai bot - name : ai bot
- base : [ai os](https://git.syui.ai/ai/os) - base : [ai os](https://git.syui.ai/ai/os)
- host : [yui.syui.ai](https://bsky.app/profile/yui.syui.ai), [ai.syu.is](https://syu.is/profile/did:plc:6qyecktefllvenje24fcxnie) - host : [yui.syui.ai](https://bsky.app/profile/yui.syui.ai), [ai.syu.is](https://web.syu.is/profile/ai.syu.is)
```sh ```sh
$ aibot $ ai
``` ```
```sh ```sh
$ docker run -it syui/aios aibot $ docker run -it syui/aios ai
``` ```
### build ### build
```sh ```sh
$ cargo build $ cargo build
$ ./target/debug/aibot ai $ ./target/debug/ai ai
``` ```
```sh ```sh
$ aibot ai -t avatar $ ai ai -t avatar
``` ```
### login ### login
```sh ```sh
# aibot login $handle -p $password # ai login $handle -p $password
$ aibot l yui.syui.ai -p password $ ai l yui.syui.ai -p password
$ cat ~/.config/ai/token.toml $ cat ~/.config/ai/token.toml
``` ```
```sh ```sh
# aibot l $handle -p $password -s $server # ai l $handle -p $password -s $server
$ aibot l ai.syu.is -p password -s syu.is $ ai l ai.syu.is -p password -s syu.is
``` ```
### refresh ### refresh
``` ```
$ aibot r $ ai r
``` ```
### notify ### notify
``` ```
$ aibot n $ ai n
``` ```
``` ```
$ aibot n | jq . $ ai n | jq .
``` ```
### bot ### bot
``` ```
$ aibot bot $ ai bot
``` ```
|command|sub|type|link|auth| |command|sub|type|link|auth|

View File

@@ -1,16 +1,11 @@
services: services:
bot: aios:
#image: syui/aios
#command: ai bot -a syui.syu.is
build: build:
context: . context: .
dockerfile: Dockerfile restart: always
image: syui/aios:custom env_file:
container_name: aibot - .env
restart: unless-stopped
command: ["aibot", "bot", "-a", "${ADMIN:-syui.ai}"]
volumes: volumes:
- ./.config/syui/ai/bot:/root/.config/syui/ai/bot - ./.config:/root/.config
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"

View File

@@ -167,9 +167,7 @@ pub fn c_bot(c: &Context) {
|| com.contains("うらない") == true || com.contains("うらない") == true
|| com.contains("うらなって") == true || com.contains("うらなって") == true
{ {
let script_path = data_scpt(&"ai"); let _output = Command::new(data_scpt(&"ai"))
println!("[fortune] script: {}", script_path);
let output = Command::new(&script_path)
.arg(&"atproto").arg(&"fortune") .arg(&"atproto").arg(&"fortune")
.arg(&handle) .arg(&handle)
.arg(&did) .arg(&did)
@@ -180,25 +178,11 @@ pub fn c_bot(c: &Context) {
.arg(&host) .arg(&host)
.arg(&prompt) .arg(&prompt)
.arg(&prompt_sub) .arg(&prompt_sub)
.output(); .output()
match output { .expect("zsh");
Ok(out) => {
let stdout = String::from_utf8_lossy(&out.stdout);
let stderr = String::from_utf8_lossy(&out.stderr);
println!("[fortune] stdout: {}", stdout);
if !stderr.is_empty() {
println!("[fortune] stderr: {}", stderr);
}
}
Err(e) => {
println!("[fortune] error: {}", e);
}
}
w_cid(cid.to_string(), log_file(&"n1"), true); w_cid(cid.to_string(), log_file(&"n1"), true);
} else if com == "card" || com == "/card" { } else if com == "card" || com == "/card" {
let script_path = data_scpt(&"ai"); let output = Command::new(data_scpt(&"ai"))
println!("[card] script: {}", script_path);
let output = Command::new(&script_path)
.arg(&"atproto").arg(&"card") .arg(&"atproto").arg(&"card")
.arg(&handle) .arg(&handle)
.arg(&did) .arg(&did)
@@ -209,26 +193,14 @@ pub fn c_bot(c: &Context) {
.arg(&host) .arg(&host)
.arg(&prompt) .arg(&prompt)
.arg(&prompt_sub) .arg(&prompt_sub)
.output(); .output()
.expect("zsh");
match output { let d = String::from_utf8_lossy(&output.stdout);
Ok(out) => {
let d = String::from_utf8_lossy(&out.stdout);
let stderr = String::from_utf8_lossy(&out.stderr);
println!("[card] stdout: {}", d);
if !stderr.is_empty() {
println!("[card] stderr: {}", stderr);
}
let dd = "\n".to_owned() + &d.to_string(); let dd = "\n".to_owned() + &d.to_string();
let text_limit = c_char(dd); let text_limit = c_char(dd);
if text_limit.len() > 3 { if text_limit.len() > 3 {
let lines: Vec<&str> = d.lines().collect(); //handlev = handle.replace(".", "-").to_string();
handlev = lines.get(0).unwrap_or(&"").trim().to_string(); handlev = d.lines().collect::<Vec<_>>()[0].to_string();
// 空白を含む場合や空の場合はhandleから生成
if handlev.is_empty() || handlev.contains(' ') {
handlev = handle.split('.').next().unwrap_or("").to_string();
}
if !handlev.is_empty() {
link = "https://card.syui.ai/".to_owned() + &handlev; link = "https://card.syui.ai/".to_owned() + &handlev;
e = link.chars().count(); e = link.chars().count();
let str_rep = reply_link::post_request( let str_rep = reply_link::post_request(
@@ -245,13 +217,6 @@ pub fn c_bot(c: &Context) {
println!("{}", str_rep); println!("{}", str_rep);
w_cid(cid.to_string(), log_file(&"n1"), true); w_cid(cid.to_string(), log_file(&"n1"), true);
} }
}
}
Err(e) => {
println!("[card] script error: {}", e);
w_cid(cid.to_string(), log_file(&"n1"), true);
}
}
} else if com == "fav" || com == "/fav" { } else if com == "fav" || com == "/fav" {
let output = Command::new(data_scpt(&"ai")) let output = Command::new(data_scpt(&"ai"))
.arg(&"atproto").arg(&"fav") .arg(&"atproto").arg(&"fav")
@@ -466,42 +431,6 @@ pub fn c_bot(c: &Context) {
println!("{}", str_rep); println!("{}", str_rep);
w_cid(cid.to_string(), log_file(&"n1"), true); w_cid(cid.to_string(), log_file(&"n1"), true);
} }
} else if com == "game" || com == "/game" {
let output = Command::new(data_scpt(&"ai"))
.arg(&"atproto").arg(&"game")
.arg(&handle)
.arg(&did)
.arg(&cid)
.arg(&uri)
.arg(&cid_root)
.arg(&uri_root)
.arg(&host)
.arg(&prompt)
.arg(&prompt_sub)
.output()
.expect("zsh");
let d = String::from_utf8_lossy(&output.stdout);
let dd = "\n".to_owned() + &d.to_string();
let text_limit = c_char(dd);
handlev = d.lines().collect::<Vec<_>>()[0].to_string();
link = "https://card.syui.ai/".to_owned() + &handlev;
println!("{}", e);
e = link.chars().count();
if text_limit.len() > 3 {
let str_rep = reply_link::post_request(
text_limit.to_string(),
link.to_string(),
s,
e.try_into().unwrap(),
cid.to_string(),
uri.to_string(),
cid_root.to_string(),
uri_root.to_string(),
)
.await;
println!("{}", str_rep);
w_cid(cid.to_string(), log_file(&"n1"), true);
}
} else if com == "quiz" || com == "/quiz" { } else if com == "quiz" || com == "/quiz" {
println!("admin:{}", admin); println!("admin:{}", admin);
let output = Command::new(data_scpt(&"ai")) let output = Command::new(data_scpt(&"ai"))
@@ -849,9 +778,7 @@ pub fn c_bot_feed(c: &Context) {
} }
w_cid(cid.to_string(), log_file(&"n1"), true); w_cid(cid.to_string(), log_file(&"n1"), true);
} else if com == "card" || com == "/card" { } else if com == "card" || com == "/card" {
let script_path = data_scpt(&"ai"); let output = Command::new(data_scpt(&"ai"))
println!("[card] script: {}", script_path);
let output = Command::new(&script_path)
.arg(&"atproto").arg(&"card") .arg(&"atproto").arg(&"card")
.arg(&handle) .arg(&handle)
.arg(&did) .arg(&did)
@@ -862,26 +789,14 @@ pub fn c_bot_feed(c: &Context) {
.arg(&host) .arg(&host)
.arg(&prompt) .arg(&prompt)
.arg(&prompt_sub) .arg(&prompt_sub)
.output(); .output()
.expect("zsh");
match output { let d = String::from_utf8_lossy(&output.stdout);
Ok(out) => {
let d = String::from_utf8_lossy(&out.stdout);
let stderr = String::from_utf8_lossy(&out.stderr);
println!("[card] stdout: {}", d);
if !stderr.is_empty() {
println!("[card] stderr: {}", stderr);
}
let dd = "\n".to_owned() + &d.to_string(); let dd = "\n".to_owned() + &d.to_string();
let text_limit = c_char(dd); let text_limit = c_char(dd);
if text_limit.len() > 3 { if text_limit.len() > 3 {
let lines: Vec<&str> = d.lines().collect(); //handlev = handle.replace(".", "-").to_string();
handlev = lines.get(0).unwrap_or(&"").trim().to_string(); handlev = d.lines().collect::<Vec<_>>()[0].to_string();
// 空白を含む場合や空の場合はhandleから生成
if handlev.is_empty() || handlev.contains(' ') {
handlev = handle.split('.').next().unwrap_or("").to_string();
}
if !handlev.is_empty() {
link = "https://card.syui.ai/".to_owned() + &handlev; link = "https://card.syui.ai/".to_owned() + &handlev;
e = link.chars().count(); e = link.chars().count();
let str_rep = reply_link::post_request( let str_rep = reply_link::post_request(
@@ -898,13 +813,6 @@ pub fn c_bot_feed(c: &Context) {
println!("{}", str_rep); println!("{}", str_rep);
w_cid(cid.to_string(), log_file(&"n1"), true); w_cid(cid.to_string(), log_file(&"n1"), true);
} }
}
}
Err(e) => {
println!("[card] script error: {}", e);
w_cid(cid.to_string(), log_file(&"n1"), true);
}
}
} else if com == "fav" || com == "/fav" { } else if com == "fav" || com == "/fav" {
let output = Command::new(data_scpt(&"ai")) let output = Command::new(data_scpt(&"ai"))
.arg(&"atproto").arg(&"fav") .arg(&"atproto").arg(&"fav")

View File

@@ -8,7 +8,7 @@ use std::io::Write;
use std::path::Path; use std::path::Path;
pub fn data_file(s: &str) -> String { pub fn data_file(s: &str) -> String {
let file = "/.config/syui/ai/bot/"; let file = "/.config/ai/";
let mut f = shellexpand::tilde("~").to_string(); let mut f = shellexpand::tilde("~").to_string();
f.push_str(&file); f.push_str(&file);
let path = Path::new(&f); let path = Path::new(&f);
@@ -24,7 +24,7 @@ pub fn data_file(s: &str) -> String {
} }
pub fn log_file(s: &str) -> String { pub fn log_file(s: &str) -> String {
let file = "/.config/syui/ai/bot/txt/"; let file = "/.config/ai/txt/";
let mut f = shellexpand::tilde("~").to_string(); let mut f = shellexpand::tilde("~").to_string();
f.push_str(&file); f.push_str(&file);
let path = Path::new(&f); let path = Path::new(&f);
@@ -263,7 +263,7 @@ pub fn data_refresh(s: &str) -> String {
pub fn data_scpt(s: &str) -> String { pub fn data_scpt(s: &str) -> String {
let s = String::from(s); let s = String::from(s);
let file = "/.config/syui/ai/bot/scpt/".to_owned() + &s + &".zsh"; let file = "/.config/ai/scpt/".to_owned() + &s + &".zsh";
let mut f = shellexpand::tilde("~").to_string(); let mut f = shellexpand::tilde("~").to_string();
f.push_str(&file); f.push_str(&file);
return f; return f;
@@ -603,7 +603,7 @@ pub fn w_cid(cid: String, file: String, t: bool) -> bool {
} }
pub fn c_follow_all() { pub fn c_follow_all() {
let file = "/.config/syui/ai/bot/scpt/follow_all.zsh"; let file = "/.config/ai/scpt/follow_all.zsh";
let mut f = shellexpand::tilde("~").to_string(); let mut f = shellexpand::tilde("~").to_string();
f.push_str(&file); f.push_str(&file);
use std::process::Command; use std::process::Command;
@@ -617,7 +617,7 @@ pub fn c_openai_key(c: &Context) {
let api = c.args[0].to_string(); let api = c.args[0].to_string();
let o = "api='".to_owned() + &api.to_string() + &"'".to_owned(); let o = "api='".to_owned() + &api.to_string() + &"'".to_owned();
let o = o.to_string(); let o = o.to_string();
let l = shellexpand::tilde("~") + "/.config/syui/ai/bot/openai.toml"; let l = shellexpand::tilde("~") + "/.config/ai/openai.toml";
let l = l.to_string(); let l = l.to_string();
let mut l = fs::File::create(l).unwrap(); let mut l = fs::File::create(l).unwrap();
if o != "" { if o != "" {
@@ -628,7 +628,7 @@ pub fn c_openai_key(c: &Context) {
impl Open { impl Open {
pub fn new() -> Result<Self, ConfigError> { pub fn new() -> Result<Self, ConfigError> {
let d = shellexpand::tilde("~") + "/.config/syui/ai/bot/openai.toml"; let d = shellexpand::tilde("~") + "/.config/ai/openai.toml";
let s = Config::builder() let s = Config::builder()
.add_source(File::with_name(&d)) .add_source(File::with_name(&d))
.add_source(config::Environment::with_prefix("APP")) .add_source(config::Environment::with_prefix("APP"))

View File

@@ -480,8 +480,6 @@ fn bot(c: &Context) {
loop { loop {
c_bot(c); c_bot(c);
c_bot_feed(c); c_bot_feed(c);
// 10秒待機してCPU使用率を抑制
std::thread::sleep(std::time::Duration::from_secs(10));
} }
} }
@@ -489,7 +487,6 @@ fn feed_watch(c: &Context) {
refresh(c); refresh(c);
loop { loop {
c_feed_watch(c); c_feed_watch(c);
std::thread::sleep(std::time::Duration::from_secs(10));
} }
} }

3
test/entrypoint.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/zsh
ai l $HANDLE -p $PASSWORD -s $HOST && ai bot -a $ADMIN