Template code
This commit is contained in:
Generated
+1634
File diff suppressed because it is too large
Load Diff
+13
-1
@@ -1,6 +1,18 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rust-llm-agent"
|
name = "rust-llm-agent"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
# Асинхронный runtime
|
||||||
|
tokio = { version = "1.38", features = ["full"] }
|
||||||
|
|
||||||
|
# HTTP-клиент
|
||||||
|
reqwest = { version = "0.12", features = ["json"] }
|
||||||
|
|
||||||
|
# Сериализация / Десериализация JSON
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
# Парсинг аргументов CLI (флаги --session-id и т.д.)
|
||||||
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
+113
-2
@@ -1,3 +1,114 @@
|
|||||||
fn main() {
|
use clap::Parser;
|
||||||
println!("Hello, world!");
|
use serde_json::json;
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||||
|
|
||||||
|
/// CLI-утилита для взаимодействия с LLM в рамках указанной сессии
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[command(author, version, about, long_about = None)]
|
||||||
|
struct Args {
|
||||||
|
/// Идентификатор сессии/беседы (на будущее для VK peer_id)
|
||||||
|
#[arg(short, long, default_value = "default_session")]
|
||||||
|
session_id: String,
|
||||||
|
|
||||||
|
/// URL OpenAI-совместимого эндпоинта (vLLM / llama.cpp / Ollama)
|
||||||
|
#[arg(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
default_value = "http://localhost:11434/v1/chat/completions"
|
||||||
|
)]
|
||||||
|
api_url: String,
|
||||||
|
|
||||||
|
/// Название модели (для Ollama/vLLM)
|
||||||
|
#[arg(m_flag, short, long, default_value = "qwen2.5-coder")]
|
||||||
|
model: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Функция отправки Stateless-запроса к LLM
|
||||||
|
async fn send_llm_request(
|
||||||
|
client: &reqwest::Client,
|
||||||
|
api_url: &str,
|
||||||
|
model: &str,
|
||||||
|
user_message: &str,
|
||||||
|
) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
|
let payload = json!({
|
||||||
|
"model": model,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": user_message
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"temperature": 0.7
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = client.post(api_url).json(&payload).send().await?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
let status = response.status();
|
||||||
|
let error_text = response.text().await?;
|
||||||
|
return Err(format!("API вернул ошибку [{status}]: {error_text}").into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let res_body: serde_json::Value = response.json().await?;
|
||||||
|
|
||||||
|
if let Some(content) = res_body["choices"][0]["message"]["content"].as_str() {
|
||||||
|
Ok(content.to_string())
|
||||||
|
} else {
|
||||||
|
Err(format!("Не удалось вытащить текст ответа из JSON: {res_body}").into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
println!("==================================================");
|
||||||
|
println!(" LLM CLI Agent (Stage 1)");
|
||||||
|
println!(" Session ID: {}", args.session_id);
|
||||||
|
println!(" API URL: {}", args.api_url);
|
||||||
|
println!(" Model: {}", args.model);
|
||||||
|
println!("==================================================");
|
||||||
|
println!("Введите сообщение и нажмите Enter. Для выхода наберите 'exit' или 'quit'.\n");
|
||||||
|
|
||||||
|
let stdin = tokio::io::stdin();
|
||||||
|
let mut reader = BufReader::new(stdin);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("[Session: {}] > ", args.session_id);
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut input = String::new();
|
||||||
|
let bytes_read = reader.read_line(&mut input).await.unwrap_or(0);
|
||||||
|
|
||||||
|
if bytes_read == 0 {
|
||||||
|
break; // EOF (Ctrl+D)
|
||||||
|
}
|
||||||
|
|
||||||
|
let trimmed_input = input.trim();
|
||||||
|
|
||||||
|
if trimmed_input.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if trimmed_input.eq_ignore_ascii_case("exit")
|
||||||
|
|| trimmed_input.eq_ignore_ascii_case("quit")
|
||||||
|
{
|
||||||
|
println!("Завершение работы.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
print!("[Ожидание ответа от LLM...]\r");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
match send_llm_request(&client, &args.api_url, &args.model, trimmed_input).await {
|
||||||
|
Ok(reply) => {
|
||||||
|
println!("\r[LLM]: {}\n", reply);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("\r[Ошибка]: {}\n", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user