|
| 1 | +//! Seedframe is a clean, macro-driven Rust library for building LLM applications. |
| 2 | +//! |
| 3 | +//! # Features |
| 4 | +//! |
| 5 | +//! - **Declarative API** through straight forward proc-macros |
| 6 | +//! - **Modular Architecture** with clearly defined components: |
| 7 | +//! - **Loaders**: Data ingestion from various sources (files, APIs, etc.) |
| 8 | +//! - **Vector Stores**: Embedding storage and retrieval (In-memory, Redis, etc.) |
| 9 | +//! - **Embedders**: Text embedding providers |
| 10 | +//! - **LLM Clients**: Unified interface for different LLM providers |
| 11 | +//! - **Tools**: Function calling abstractions with state management and automatic documentation |
| 12 | +//! - **Extractors**: Structured output generation from LLM responses |
| 13 | +//! |
| 14 | +//! # Examples |
| 15 | +//! |
| 16 | +//! The seedframe repo contains a [number of examples](https://github.com/Shifta-Robel/SeedFrame/tree/main/core/examples) that show how to put all the pieces together. |
| 17 | +//! |
| 18 | +//! ## Building a simple RAG |
| 19 | +//! |
| 20 | +//! ```rust,no_run |
| 21 | +//! use seedframe::prelude::*; |
| 22 | +//! |
| 23 | +//! // Declare file loader that doesnt check for updates, loading files that match the glob pattern |
| 24 | +//! #[loader(kind = "FileOnceLoader", path = "/tmp/data/**/*.txt")] |
| 25 | +//! pub struct MyLoader; |
| 26 | +//! |
| 27 | +//! #[vector_store(kind = "InMemoryVectorStore")] |
| 28 | +//! pub struct MyVectorStore; |
| 29 | +//! |
| 30 | +//! #[embedder(provider = "openai", model = "text-embedding-3-small")] |
| 31 | +//! struct MyEmbedder { |
| 32 | +//! #[vector_store] |
| 33 | +//! my_vector_store: MyVectorStore, |
| 34 | +//! #[loader] |
| 35 | +//! my_loader: MyLoader, |
| 36 | +//! } |
| 37 | +//! |
| 38 | +//! #[client(provider = "openai", model = "gpt-4o-mini")] |
| 39 | +//! struct MyClient { |
| 40 | +//! #[embedder] |
| 41 | +//! my_embedder: MyEmbedder, |
| 42 | +//! } |
| 43 | +//! |
| 44 | +//! #[tokio::main] |
| 45 | +//! async fn main() { |
| 46 | +//! let mut client = MyClient::build( |
| 47 | +//! "You are a helpful assistant".to_string() |
| 48 | +//! ).await; |
| 49 | +//! |
| 50 | +//! tokio::time::sleep(Duration::from_secs(5)).await; |
| 51 | +//! let response = client.prompt("Explain quantum computing").send().await.unwrap(); |
| 52 | +//! } |
| 53 | +//! ``` |
| 54 | +//! |
| 55 | +//! ## Tool calls and Extractors |
| 56 | +//! |
| 57 | +//! ```rust,no_run |
| 58 | +//! #[client(provider = "openai", model = "gpt-4o-mini", tools("analyze"))] |
| 59 | +//! struct ToolClient; |
| 60 | +//! |
| 61 | +//! /// Perform sentiment analysis on text |
| 62 | +//! /// # Arguments |
| 63 | +//! /// * `text`: Input text to analyze |
| 64 | +//! /// * `language`: Language of the text (ISO 639-1) |
| 65 | +//! #[tool] |
| 66 | +//! fn analyze(text: String, language: String) -> String { |
| 67 | +//! todo!("implementation"); |
| 68 | +//! } |
| 69 | +//! |
| 70 | +//! #[derive(Extractor)] |
| 71 | +//! struct PersonData { |
| 72 | +//! /// Age in years |
| 73 | +//! age: u8, |
| 74 | +//! /// Email address |
| 75 | +//! email: String |
| 76 | +//! } |
| 77 | +//! |
| 78 | +//! #[tokio::main] |
| 79 | +//! async fn main() -> Result<()> { |
| 80 | +//! let mut client = ToolClient::build("You're a data analyst".to_string()) |
| 81 | +//! .await |
| 82 | +//! .with_state(AppState::new())?; |
| 83 | +//! |
| 84 | +//! // Tool call |
| 85 | +//! client.prompt("Analyze this: 'I love Rust!' (en)") |
| 86 | +//! .send() |
| 87 | +//! .await?; |
| 88 | +//! |
| 89 | +//! // Structured extraction |
| 90 | +//! let person = client.prompt("John is 30, email [email protected]") |
| 91 | +//! .extract::<PersonData>() |
| 92 | +//! .await?; |
| 93 | +//! } |
| 94 | +//! ``` |
| 95 | +//! |
| 96 | +//! ## Sharing state with tools |
| 97 | +//! |
| 98 | +//! You can pass state to tools by adding arguments of type `State<_>` to them, the only catch is that there can only be one type of State\<T\> attached to the client. |
| 99 | +//! |
| 100 | +//! ```rust,no_run |
| 101 | +//! use seedframe::prelude::*; |
| 102 | +//! |
| 103 | +//! #[client(provider = "openai", model = "gpt-4o-mini", tools("greet"))] |
| 104 | +//! struct ToolClient; |
| 105 | +//! |
| 106 | +//! /// Greets a user |
| 107 | +//! /// # Arguments |
| 108 | +//! /// * `name`: name of the user |
| 109 | +//! #[tool] |
| 110 | +//! fn greet(name: String, State(count): State<u32>) -> String { |
| 111 | +//! for _ in range 0..count { println("Hello {name}!!")}; |
| 112 | +//! } |
| 113 | +//! |
| 114 | +//! #[tokio::main] |
| 115 | +//! async fn main() -> Result<()> { |
| 116 | +//! let mut client = ToolClient::build("You're a helpful assistant".to_string()) |
| 117 | +//! .await |
| 118 | +//! .with_state(3u32)? |
| 119 | +//! .with_state(7u32)? // this is an error since there's already a State of type u32 attached |
| 120 | +//! .with_state("some other state".to_string())?; |
| 121 | +//! |
| 122 | +//! // Tool call |
| 123 | +//! client.prompt("Say hi to jack for me".to_string()) |
| 124 | +//! .send() |
| 125 | +//! .await?; |
| 126 | +//! ``` |
| 127 | +//! |
| 128 | +//! ### Sharing mutable state with tools |
| 129 | +//! |
| 130 | +//! To share mutable state you can use types with interior mutablity, eg `Mutex`s |
| 131 | +//! |
| 132 | +//! ```rust,no_run |
| 133 | +//! /// Greets a user |
| 134 | +//! /// # Arguments |
| 135 | +//! /// * `name`: name of the user |
| 136 | +//! #[tool] |
| 137 | +//! fn greet(name: String, State(count): State<u32>) -> String { |
| 138 | +//! let mut count = count.lock().unwrap(); |
| 139 | +//! println!("{name}! This is my {count}th time saying hello"); |
| 140 | +//! *count += 1; |
| 141 | +//! } |
| 142 | +//! |
| 143 | +//! struct AppState { |
| 144 | +//! count: std::sync::Mutex<u32> |
| 145 | +//! } |
| 146 | +//! |
| 147 | +//! #[tokio::main] |
| 148 | +//! async fn main() -> Result<()> { |
| 149 | +//! let mut client = ToolClient::build("You're a helpful assistant".to_string()) |
| 150 | +//! .await |
| 151 | +//! .with_state(AppState { count: std::sync::Mutex::new(0u32) })?; |
| 152 | +//! |
| 153 | +//! // Tool call |
| 154 | +//! client.prompt("Say hi to jack for me".to_string()) |
| 155 | +//! .send() |
| 156 | +//! .await?; |
| 157 | +//! |
| 158 | +//! // Tool call |
| 159 | +//! client.prompt("Say hi to jack for me".to_string()) |
| 160 | +//! .send() |
| 161 | +//! .await?; |
| 162 | +//! ``` |
| 163 | +//! |
| 164 | +//! # Feature flags |
| 165 | +//! |
| 166 | +//! seedframe uses a set of [feature flags] to reduce the amount of compiled and |
| 167 | +//! optional dependencies. |
| 168 | +//! |
| 169 | +//! The following optional features are available: |
| 170 | +//! |
| 171 | +//! Name | Description | Default? |
| 172 | +//! ---|---|--- |
| 173 | +//! `pinecone` | enables the pinecone vectorstore integration | No |
| 174 | +//! `pdf` | enables file loaders to parse PDFs | No |
| 175 | +
|
1 | 176 | pub mod completion; |
2 | 177 | pub mod document; |
3 | 178 | pub mod embeddings; |
|
0 commit comments