#bedrock #ollama #aws #text-generation #client #api-client #error-message

bin+lib hiramu

Hiramu 是一个用于访问 Ollama 和 AWS Bedrock 的 Rust AI 工程工具箱。

12 个版本

0.1.15 2024 年 4 月 21 日
0.1.14 2024 年 4 月 18 日

#1420网络编程

Download history 17/week @ 2024-04-26 3/week @ 2024-05-03 9/week @ 2024-05-17 4/week @ 2024-05-24 4/week @ 2024-05-31 5/week @ 2024-06-07 2/week @ 2024-06-14 5/week @ 2024-06-21 8/week @ 2024-06-28 50/week @ 2024-07-05

每月 696 次下载
hiramu-cli 中使用

MIT 许可证

1.5MB
2.5K SLoC

Hiramu

Hiramu 是一个强大而灵活的 Rust 库,提供了与各种 AI 模型和 API(包括 Ollama 和 AWS Bedrock)交互的高级接口。

它简化了生成文本、参与聊天对话以及与不同 AI 模型协同工作的过程。

特性

  • 用于生成文本和与 AI 模型进行聊天对话的简单易用的接口
  • 支持 Ollama 和 Bedrock AI 服务
  • 方便的 Claude 和 Mistral 接口,用于 AWS Bedrock
  • 异步和流式响应,以高效处理大量输出
  • 可定制的选项,以微调 AI 模型的行为
  • 全面的错误处理和详尽的信息性错误消息
  • 带有示例和解释的良好文档化的代码

入门指南

要开始在您的 Rust 项目中使用 Hiramu,请将以下内容添加到您的 Cargo.toml 文件中

[dependencies]
hiramu = "0.1.15"

示例

Mistral 生成文本

use hiramu::bedrock::model_info::{ModelInfo, ModelName};
use hiramu::bedrock::models::mistral::mistral_client::{MistralClient, MistralOptions};
use hiramu::bedrock::models::mistral::mistral_request_message::MistralRequestBuilder;

async fn generating_text_with_mistral() {
    let mistral_options = MistralOptions::new()
        .profile_name("bedrock")
        .region("us-west-2");

    let client = MistralClient::new(mistral_options).await;

    let request =
        MistralRequestBuilder::new("<s>[INST] What is the capital of France?[/INST]".to_string())
            .max_tokens(200)
            .temperature(0.8)
            .build();

    let model_id = ModelInfo::from_model_name(ModelName::MistralMixtral8X7BInstruct0x);
    let response = client.generate(model_id, &request).await.unwrap();

    println!("Response: {:?}", response.outputs[0].text);
}

Mistral 流式文本生成

use futures::stream::StreamExt;
use hiramu::bedrock::models::mistral::mistral_client::{MistralClient, MistralOptions};
use hiramu::bedrock::models::mistral::mistral_request_message::MistralRequestBuilder;
use hiramu::bedrock::model_info::{ModelInfo, ModelName};

pub async fn generating_text_with_mistral() {
    let mistral_options = MistralOptions::new()
        .profile_name("bedrock")
        .region("us-west-2");

    let client = MistralClient::new(mistral_options).await;

    let request = MistralRequestBuilder::new("<s>[INST] What is the capital of France?[/INST]".to_string())
        .max_tokens(200)
        .temperature(0.8)
        .build();

    let model_id = ModelInfo::from_model_name(ModelName::MistralMixtral8X7BInstruct0x);
    let mut stream = client.generate_with_stream(model_id, &request).await.unwrap();

    while let Some(result) = stream.next().await {
        match result {
            Ok(response) => {
                println!("Response: {:?}", response.outputs[0].text);
            }
            Err(err) => {
                eprintln!("Error: {:?}", err);
            }
        }
    }
}

Ollama 生成文本

use std::io::Write;

use futures::TryStreamExt;

use hiramu::ollama::ollama_client::OllamaClient;
use hiramu::ollama::model::{GenerateRequestBuilder};

async fn generating_text_with_ollama() {
    let client = OllamaClient::new("https://127.0.0.1:11434".to_string());
    
    let request = GenerateRequestBuilder::new("mistral".to_string())
        .prompt("Once upon a time".to_string())
        .build();

    let response_stream = client.generate(request).await.unwrap();

    response_stream
        .try_for_each(|chunk| async move {
            print!("{}", chunk.response);
            std::io::stdout().flush()?;
            Ok(())
        })
        .await
        .unwrap();
}

与 Ollama 聊天


use futures::TryStreamExt;
use std::io::{self, Write};

use hiramu::ollama::{ChatRequestBuilder, Message, OllamaClient, OllamaError, OptionsBuilder};

async fn demo_chat_with_ollama_with_stream() -> Result<(), OllamaError> {
    let client = OllamaClient::new("https://127.0.0.1:11434".to_string());

    let messages = vec![Message::new(
        "user".to_string(),
        "What is the capital of France?  "
            .to_string(),
    )];

    let options = OptionsBuilder::new()
        .num_predict(100) // Limit the number of predicted tokens
        .temperature(0.4);

    let request = ChatRequestBuilder::new("mistral".to_string())
        .messages(messages.to_owned())
        .options_from_builder(options)
        .build();

    let response_stream = client.chat(request).await?;

    let result = response_stream
        .try_for_each(|chunk| async {
            let message = chunk.message;
            print!("{}", message.content);
            // Flush the output to ensure the prompt is displayed.
            io::stdout().flush().unwrap();
            Ok(())
        })
        .await;

    result
}

使用 Bedrock 与 Claude 聊天

use std::io::Write;

use futures::TryStreamExt;

use hiramu::bedrock::model_info::{ModelInfo, ModelName};
use hiramu::bedrock::models::claude::claude_client::{ClaudeClient, ClaudeOptions};
use hiramu::bedrock::models::claude::claude_request_message::{
    ChatOptions, ContentBlockDelta, ConversationRequest, Message, StreamResultData,
};

pub async fn chat_with_claude() {
    let claude_options = ClaudeOptions::new()
        .profile_name("bedrock")
        .region("us-west-2");

    let client = ClaudeClient::new(claude_options).await;

    let mut conversation_request = ConversationRequest::default();
    conversation_request
        .messages
        .push(Message::new_user_message("Hello, Claude!".to_owned()));

    let chat_options = ChatOptions::default()
        .with_temperature(0.7)
        .with_max_tokens(100)
        .with_model_id(ModelInfo::from_model_name(
            ModelName::AnthropicClaudeHaiku1x,
        ));

    let response_stream = client
        .chat_with_stream(&conversation_request, &chat_options)
        .await
        .unwrap();

    response_stream
        .try_for_each(|chunk| async move {
            match chunk {
                StreamResultData::ContentBlockStart(..) => {
                    println!("\n------------------------------");
                }
                StreamResultData::ContentBlockStop(..) => {
                    println!("\n------------------------------");
                }
                StreamResultData::ContentBlockDelta(ContentBlockDelta { delta, .. }) => {
                    print!("{}", delta.text);
                    std::io::stdout().flush().unwrap();
                }
                _ => {}
            }
            Ok(())
        })
        .await
        .unwrap();
}

Claude 与图像协同工作

use std::io::Write;

use futures::TryStreamExt;

use hiramu::bedrock::models::claude::claude_client::{ClaudeClient, ClaudeOptions};
use hiramu::bedrock::models::claude::claude_request_message::{ChatOptions, ContentBlockDelta, ConversationRequest, Message, StreamResultData};
use hiramu::fetch_and_base64_encode_image;

async fn image_with_claude() {
    let claude_options = ClaudeOptions::new()
        .profile_name("bedrock")
        .region("us-west-2");

    let client = ClaudeClient::new(claude_options).await;

    let image_url = "./data/mario.png";
    let input_text = "What's in this image?".to_string();
    let image = fetch_and_base64_encode_image(image_url).await.unwrap().to_string();
    let mime_type = "image/png".to_string();

    let message = Message::new_user_message_with_image(&input_text, &image, &mime_type);

    let mut conversation_request = ConversationRequest::default();
    conversation_request.messages.push(message);

    let chat_options = ChatOptions::default()
        .with_temperature(0.7)
        .with_max_tokens(100);

    let response_stream = client
        .chat_with_stream(&conversation_request, &chat_options)
        .await
        .unwrap();

        response_stream
        .try_for_each(|chunk| async move {
            match chunk {
                StreamResultData::ContentBlockStart(..) => {
                    println!("\n------------------------------");
                }
                StreamResultData::ContentBlockStop(..) => {
                    println!("\n------------------------------");
                }

                StreamResultData::ContentBlockDelta(ContentBlockDelta { delta, .. }) => {
                    print!("{}", delta.text);
                    std::io::stdout().flush().unwrap();
                }
                _ => {}
            }
            Ok(())
        })
        .await
        .unwrap();
}

使用原始 Bedrock API

生成原始响应

use hiramu::bedrock::bedrock_client::{BedrockClient, BedrockClientOptions};
use hiramu::bedrock::model_info::{ModelInfo, ModelName};

#[tokio::main]
async fn main() {
    let model_id = ModelInfo::from_model_name(ModelName::AnthropicClaudeHaiku1x);
    let profile_name = "bedrock";
    let region = "us-west-2";

    let prompt = "Hi. In a short paragraph, explain what you can do.";

    let payload = serde_json::json!({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1000,
        "messages": [{
            "role": "user",
            "content": [{
                "type": "text",
                "text": prompt
            }]
        }]
    });

    let options = BedrockClientOptions::new()
        .profile_name(profile_name)
        .region(region);

    let client = BedrockClient::new(options).await;

    let result = client
        .generate_raw(model_id.to_string(), payload)
        .await
        .unwrap();

    println!("{:?}", result);
}

生成原始流响应

use futures::TryStreamExt;
use hiramu::bedrock::bedrock_client::{BedrockClient, BedrockClientOptions};
use hiramu::bedrock::model_info::{ModelInfo, ModelName};

#[tokio::main]
async fn main() {
    let model_id = ModelInfo::from_model_name(ModelName::AnthropicClaudeHaiku1x);
    let profile_name = "bedrock";
    let region = "us-west-2";

    let prompt = "Hi. In a short paragraph, explain what you can do.";

    let payload = serde_json::json!({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1000,
        "messages": [{
            "role": "user",
            "content": [{
                "type": "text",
                "text": prompt
            }]
        }]
    });

    let options = BedrockClientOptions::new()
        .profile_name(profile_name)
        .region(region);

    let client = BedrockClient::new(options).await;

    let stream = client
        .generate_raw_stream(model_id.to_string(), payload)
        .await
        .unwrap();

    stream
        .try_for_each(|chunk| async move {
            println!("{:?}", chunk);
            Ok(())
        })
        .await
        .unwrap();
}

使用 Ollama 的嵌入

use hiramu::ollama::{EmbeddingsRequestBuilder, OllamaClient};

pub async fn demo_ollama_embedding() -> Result<(), Box<dyn std::error::Error>> {
    let client = OllamaClient::new("https://127.0.0.1:11434".to_string());

    let prompt = "The quick brown fox jumps over the lazy dog.";

    let request = EmbeddingsRequestBuilder::new("nomic-embed-text".to_string(), prompt.to_string())
        .keep_alive("10m".to_string())
        .build();

    match client.embeddings(request).await {
        Ok(response) => {
            // Print embeddings dimensions
            println!("Embeddings dimensions: {:?}", response.embedding.len());
            println!("Embeddings: {:?}", response);
        }
        Err(error) => {
            eprintln!("Error: {:?}", error);
        }
    }

    Ok(())
}

示例

以下是每个示例的描述表

示例 路径 描述
demo_ollama src/examples/demo_ollama.rs 一个简单的示例,演示了如何使用 Ollama API 生成响应。
demo_chat_with_ollama src/examples/demo_chat_with_ollama.rs 一个简单的示例,演示了如何使用 Ollama 聊天 API。
demo_bedrock_raw_generate src/examples/demo_bedrock_raw_generate.rs 演示了如何使用 generate_raw 方法从 Bedrock 服务生成原始响应。
demo_bedrock_raw_stream src/examples/demo_bedrock_raw_stream.rs 演示了如何使用 generate_raw_stream 方法从 Bedrock 服务生成原始响应流。
demo_bedrock_raw_mistral src/examples/demo_bedrock_raw_mistral.rs 演示了如何在Bedrock服务中从Mistral模型生成原始响应流。
demo_claude_chat src/examples/demo_claude_chat.rs 演示了如何在Bedrock服务中使用Claude模型生成聊天响应。
demo_claude_chat_stream src/examples/demo_claude_chat_stream.rs 演示了如何在Bedrock服务中使用Claude模型生成聊天响应流。
demo_claude_multimedia src/examples/demo_claude_multimedia.rs 演示了如何在Bedrock服务中使用Claude模型根据文本和图像生成响应。
demo_ollama_embedding src/examples/demo_ollama_embedding.rs 演示了如何使用Ollama API生成文本嵌入。
demo_mistral_stream src/examples/demo_mistral_stream.rs 演示了如何在Bedrock服务中使用Mistral模型生成响应流。

贡献

欢迎为Hiramu做出贡献!如果您遇到任何问题,有改进建议或想添加新功能,请在GitHub仓库上创建问题或提交pull请求。

要为项目做出贡献,请按照以下步骤操作

  1. 将仓库Fork并为您所做的更改创建一个新的分支。
  2. 进行修改并确保代码成功编译。
  3. 编写测试以覆盖您的更改并确保所有现有测试都通过。
  4. 如有必要,更新文档,包括README和API文档。
  5. 提交一个包含更改描述和解决问题的pull请求。

许可证

Hiramu使用MIT许可证

致谢

Hiramu构建在以下库和API之上

我们想对以下项目的开发者和维护者表示衷心的感谢,他们为Rust生态系统做出了卓越的工作和贡献。

依赖项

~19–34MB
~498K SLoC