#nlp #whisper #text-generation #llm #llama #language-model #ocr

kalosm

预训练模型的简单接口

7 个版本

新版本 0.3.2 2024 年 8 月 14 日
0.3.1 2024 年 8 月 13 日
0.2.2 2024 年 6 月 30 日
0.2.1 2024 年 2 月 28 日
0.1.0 2023 年 12 月 16 日

#88 in 机器学习

Download history 1/week @ 2024-04-28 1/week @ 2024-05-19 4/week @ 2024-06-02 4/week @ 2024-06-09 5/week @ 2024-06-16 7/week @ 2024-06-23 240/week @ 2024-06-30 9/week @ 2024-07-07 3/week @ 2024-07-14 7/week @ 2024-07-28 351/week @ 2024-08-11

每月 358 次下载
用于 rbert

MIT/Apache 许可

310KB
3K SLoC

Kalosm

Kalosm 是 Rust 中预训练模型的简单接口。它使得与预训练的语言、音频和图像模型交互变得容易。

Kalosm 中有三个不同的包

  • kalosm::language - 用于文本生成和嵌入模型的简单接口以及相关工具。它包括对搜索引擎、网站、RSS 源和搜索引擎的文本收集的支持。
  • kalosm::audio - 用于音频转录和相关工具的简单接口。它包括对麦克风输入、使用 whisper 模型进行转录和语音活动检测的支持。
  • kalosm::vision - 用于图像生成和分割模型的简单接口和相关工具。它包括对 wuerstchensegment-anything 模型的支持以及与 image crate 的集成。

有关 Kalosm 的完整指南可在 Kalosm 网站 上找到,示例代码位于 示例文件夹 中。

快速入门!

  1. 安装 rust
  2. 创建一个新的项目
cargo new next-gen-ai
cd ./next-gen-ai
  1. 将 Kalosm 添加为依赖项
cargo add kalosm --git https://github.com/floneum/floneum --features full
cargo add tokio --features full
  1. 将以下代码添加到您的 main.rs 文件中
use std::io::Write;

use kalosm::{*, language::*};

#[tokio::main]
async fn main() {
    let mut llm = Llama::new().await.unwrap();
    let prompt = "The following is a 300 word essay about Paris:";
    print!("{}", prompt);

    let mut stream = llm.stream_text(prompt).with_max_length(1000).await.unwrap();

    stream.to_std_out().await.unwrap();
}
  1. 使用以下命令运行您的应用程序
cargo run --release

您可以使用 Kalosm 做什么?

您可以将 Kalosm 视为不同预训练模型之间或与周围世界的“管道”。Kalosm 使得构建使用预训练模型生成文本、音频和图像的应用程序变得简单。以下是您可以使用 Kalosm 构建的一些示例

本地文本生成

要开始使用 Kalosm 语言,最简单的方法是引入一个本地的大型语言模型,并使用它来生成文本。Kalosm 支持流式 API,允许您在不阻塞主线程的情况下实时生成文本

use kalosm::language::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut llm = Llama::phi_3().await.unwrap();
    let prompt = "The following is a 300 word essay about why the capital of France is Paris:";
    print!("{}", prompt);

    let mut stream = llm.stream_text(prompt).with_max_length(1000).await.unwrap();

    stream.to_std_out().await.unwrap();

    Ok(())
}
结构化生成

自然语言生成很有趣,但文本作为通用数据格式的有趣方面更大。您可以使用类似 json 的格式将任何类型的数据编码成文本。Kalosm 允许您使用结构化生成与 LLMs 创建从自然语言输入派生的任意类型

use kalosm::language::*;

// First, derive an efficient parser for your structured data
#[derive(Parse, Clone, Debug)]
enum Class {
    Thing,
    Person,
    Animal,
}

#[derive(Parse, Clone, Debug)]
struct Response {
    classification: Class,
}

#[tokio::main]
async fn main() {
    // Then set up a task with a prompt and constraints
    let llm = Llama::new_chat().await.unwrap();
    let task = Task::builder("You classify the user's message as about a person, animal or thing in a JSON format")
        .with_constraints(Response::new_parser())
        .build();

    // Finally, run the task
    let response = task.run("The Kalosm library lets you create structured data from natural language inputs", &llm).await.unwrap();
    println!("{:?}", response);
}
云模型

Kalosm 还支持与云模型(如 GPT4)相同的流式 API

// You must set the environment variable OPENAI_API_KEY (https://platform.openai.com/account/api-keys) to run this example.
use kalosm::language::*; 

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut llm = Gpt4::default();
    let prompt = "The following is a 300 word essay about why the capital of France is Paris:";
    print!("{}", prompt);

    let mut stream = llm.stream_text(prompt).with_max_length(300).await.unwrap();

    stream.to_std_out().await.unwrap();

    Ok(())
}
从 RSS、网站、本地文件、搜索结果等收集上下文

Kalosm 使您轻松地从各种来源收集文本数据。例如,您可以使用 Kalosm 从本地文档文件夹、RSS 流、网站或搜索引擎中收集文本

use kalosm::language::*;
use std::convert::TryFrom;
use std::path::PathBuf;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Read an RSS stream
    let nyt = RssFeed::new(Url::parse("https://rss.nytimes.com/services/xml/rss/nyt/US.xml").unwrap());
    // Read a local folder of documents
    let mut documents = DocumentFolder::try_from(PathBuf::from("./documents")).unwrap();
    // Read a website (either from the raw HTML or inside of a headless browser)
    let page = Page::new(Url::parse("https://www.nytimes.com/live/2023/09/21/world/zelensky-russia-ukraine-news").unwrap(), BrowserMode::Static).unwrap();
    let document = page.article().await.unwrap();
    println!("Title: {}", document.title());
    println!("Body: {}", document.body());
    // Read pages from a search engine (You must have the SERPER_API_KEY environment variable set to run this example)
    let query = "What is the capital of France?";
    let api_key = std::env::var("SERPER_API_KEY").unwrap();
    let search_query = SearchQuery::new(query, &api_key, 5);
    let documents = search_query.into_documents().await.unwrap();
    let mut text = String::new();
    for document in documents {
        for word in document.body().split(' ').take(300) {
            text.push_str(word);
            text.push(' ');
        }
        text.push('\n');
    }
    println!("{}", text);

    Ok(())
}
基于嵌入的搜索

一旦您有了数据,Kalosm 就包括创建基于嵌入的搜索索引的工具。基于嵌入的搜索允许您找到与特定单词或短语语义上相似的文档,即使没有任何单词是完全匹配的

use kalosm::language::*;
use surrealdb::{engine::local::RocksDb, Surreal};

#[tokio::main]
async fn main() {
    // Create database connection
    let db = Surreal::new::<RocksDb>(std::env::temp_dir().join("temp.db")).await.unwrap();

    // Select a specific namespace / database
    db.use_ns("search").use_db("documents").await.unwrap();

    // Create a table in the surreal database to store the embeddings
    let document_table = db
        .document_table_builder("documents")
        .build::<Document>()
        .await
        .unwrap();

    // Add documents to the database
    document_table.add_context(DocumentFolder::new("./documents").unwrap()).await.unwrap();

    loop {
        // Get the user's question
        let user_question = prompt_input("Query: ").unwrap();

        let nearest_5 = document_table
            .select_nearest(user_question, 5)
            .await
            .unwrap();

        println!("{:?}", nearest_5);
    }
}
资源增强生成

现代 LLMs 性能的关键部分是管理模型可访问的上下文。资源增强生成(或 RAG)通过根据搜索查询在提示中插入上下文来帮助您完成此操作。例如,您可以使用 Kalosm 创建一个聊天机器人,该机器人使用本地文档中的上下文来回答问题

use kalosm::language::*;
use surrealdb::{engine::local::RocksDb, Surreal};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let exists = std::path::Path::new("./db").exists();

    // Create database connection
    let db = Surreal::new::<RocksDb>("./db/temp.db").await?;

    // Select a specific namespace / database
    db.use_ns("test").use_db("test").await?;

    // Create a table in the surreal database to store the embeddings
    let document_table = db
        .document_table_builder("documents")
        .at("./db/embeddings.db")
        .build::<Document>()
        .await?;

    // If the database is new, add documents to it
    if !exists {
        std::fs::create_dir_all("documents")?;
        let context = [
            "https://floneum.com/kalosm/docs",
            "https://floneum.com/kalosm/docs/guides/retrieval_augmented_generation",
        ]
        .iter()
        .map(|url| Url::parse(url).unwrap());

        document_table.add_context(context).await?;
    }

    // Create a llama chat model
    let model = Llama::new_chat().await?;
    let mut chat = Chat::builder(model).with_system_prompt("The assistant help answer questions based on the context given by the user. The model knows that the information the user gives it is always true.").build();

    loop {
        // Ask the user for a question
        let user_question = prompt_input("\n> ")?;

        // Search for relevant context in the document engine
        let context = document_table
            .select_nearest(&user_question, 1)
            .await?
            .into_iter()
            .map(|document| {
                format!(
                    "Title: {}\nBody: {}\n",
                    document.record.title(),
                    document.record.body()
                )
            })
            .collect::<Vec<_>>()
            .join("\n");

        // Format a prompt with the question and context
        let prompt = format!(
            "{context}\n{user_question}"
        );

        // Display the prompt to the user for debugging purposes
        println!("{}", prompt);

        // And finally, respond to the user
        let mut output_stream = chat.add_message(prompt);
        print!("Bot: ");
        output_stream.to_std_out().await?;
    }
}
实时音频转录

Kalosm 使您轻松地构建有关您应用程序周围世界的上下文。

use kalosm::sound::*;

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    // Create a new whisper model
    let model = Whisper::new().await?;

    // Stream audio from the microphone
    let mic = MicInput::default();
    let stream = mic.stream().unwrap();

    // The audio into chunks based on voice activity and then transcribe those chunks
    // The model will transcribe chunks of speech that are separated by silence
    let mut text_stream = stream.transcribe(model);

    // Finally, print the text to the console
    text_stream.to_std_out().await.unwrap();

    Ok(())
}
图像生成

除了语言、音频和嵌入模型之外,Kalosm 还支持图像生成。例如,您可以使用 Kalosm 从文本生成图像

use kalosm::vision::*;

#[tokio::main]
async fn main() {
    let model = Wuerstchen::new().await.unwrap();
    let settings = WuerstchenInferenceSettings::new(
        "a cute cat with a hat in a room covered with fur with incredible detail",
    );
    if let Ok(mut images) = model.run(settings) {
        while let Some(image) = images.next().await {
            if let Some(buf) = image.generated_image() {
                buf.save(&format!("{}.png",image.sample_num())).unwrap();
            }
        }
    }
}
图像分割

Kalosm 还支持使用 segment-anything 模型进行图像分割

use kalosm::vision::*;

#[tokio::main]
async fn main() {
    let model = SegmentAnything::builder().build().unwrap();
    let image = image::open("examples/landscape.jpg").unwrap();
    let images = model.segment_everything(image).unwrap();
    for (i, img) in images.iter().enumerate() {
        img.save(&format!("{}.png", i)).unwrap();
    }
}

依赖项

~21–72MB
~1.5M SLoC