#include"liboai.h"usingnamespaceliboai;intmain(){OpenAIoai;// create a conversationConversationconvo;// add a message to the conversationconvo.AddUserData("What is the point of taxes?");if(oai.auth.SetKeyEnv("OPENAI_API_KEY")){try{Responseresponse=oai.ChatCompletion->create("gpt-3.5-turbo",convo);// update our conversation with the responseconvo.Update(response);// print the responsestd::cout<<convo.GetLastResponse()<<std::endl;}catch(std::exception&e){std::cout<<e.what()<<std::endl;}}}
liboai::Responseliboai::netimpl::Session::Get(){#if defined(LIBOAI_DEBUG)_liboai_dbg("[dbg] [@%s] Called PrepareGet().\n",__func__);#endifthis->PrepareGet();this->Perform();returnComplete();}voidliboai::netimpl::Session::PrepareGet(){// holds error codes - all init to OK to prevent errors// when checking unset valuesCURLcodee[5];memset(e,CURLcode::CURLE_OK,sizeof(e));if(this->hasBody){e[0]=curl_easy_setopt(this->curl_,CURLOPT_NOBODY,0L);e[1]=curl_easy_setopt(this->curl_,CURLOPT_CUSTOMREQUEST,"GET");}else{e[2]=curl_easy_setopt(this->curl_,CURLOPT_NOBODY,0L);e[3]=curl_easy_setopt(this->curl_,CURLOPT_CUSTOMREQUEST,nullptr);e[4]=curl_easy_setopt(this->curl_,CURLOPT_HTTPGET,1L);}ErrorCheck(e,5,"liboai::netimpl::Session::PrepareGet()");this->Prepare();}
采用tokio的实现的一个异步库哈,api也很清晰。这里觉得有趣的,第一个可以学习一下这个库,第二个我发现作者自己写了一个应用Song search in Rust using OpenAI。
和RAG知识库原理基本一样,把歌词和作者信息等通过embedding模型转换成vector信息,将歌词信息和vector信息存储到向量数据库中,然后通过距离算法,这里使用了余弦距离,计算相似度。然后搜索出排名靠前的音乐。
usestd::error::Error;useasync_openai::{types::{ChatCompletionRequestAssistantMessageArgs,ChatCompletionRequestSystemMessageArgs,ChatCompletionRequestUserMessageArgs,CreateChatCompletionRequestArgs,},Client,};#[tokio::main]asyncfnmain()->Result<(),Box<dynError>>{letclient=Client::new();letrequest=CreateChatCompletionRequestArgs::default().max_tokens(512u32).model("gpt-3.5-turbo").messages([ChatCompletionRequestSystemMessageArgs::default().content("You are a helpful assistant.").build()?.into(),ChatCompletionRequestUserMessageArgs::default().content("Who won the world series in 2020?").build()?.into(),ChatCompletionRequestAssistantMessageArgs::default().content("The Los Angeles Dodgers won the World Series in 2020.").build()?.into(),ChatCompletionRequestUserMessageArgs::default().content("Where was it played?").build()?.into(),]).build()?;println!("{}",serde_json::to_string(&request).unwrap());letresponse=client.chat().create(request).await?;println!("\nResponse:\n");forchoiceinresponse.choices{println!("{}: Role: {} Content: {:?}",choice.index,choice.message.role,choice.message.content);}Ok(())}
During my non-exhaustive search I found various vector databases and libraries like pinecone, milvus, Weaviate, and Faiss. And there are many more. But none of them seem to have an out-of-the-box ready to go library in Rust. Except pgvector - a Postgres extension to store and query vectors! The pgvector project provides Docker image with extension already installed as well as Rust library 😎
implSong{/// Save embedding for this Song in DBpubasyncfnsave_embedding(&self,pg_pool:&PgPool,pgvector:pgvector::Vector)->Result<()>{sqlx::query(r#"INSERT INTO songs (artist, title, album, lyric, embedding) VALUES ($1, $2, $3, $4, $5)"#).bind(self.artist.clone()).bind(self.title.clone()).bind(self.album.clone()).bind(self.lyric.clone()).bind(pgvector).execute(pg_pool).await?;Ok(())}}
// Search for nearest neighbors in databaseOk(sqlx::query(r#"SELECT artist, title, album, lyric FROM songs ORDER BY embedding <-> $1 LIMIT $2::int"#,).bind(pgvector).bind(n).fetch_all(pg_pool).await?.into_iter().map(|r|Song{artist:r.get("artist"),title:r.get("title"),album:r.get("album"),lyric:r.get("lyric"),}).collect())