Research Tools
Open NotebookLM
Build an open-source alternative to Google's NotebookLM: upload documents, ask questions grounded in your sources, and generate podcast-style audio summaries — all with OneInfer.
OneInfer Chat APIOneInfer EmbeddingsOneInfer TTSFAISSStreamlit
Step-by-step guide
1
Build the document knowledge base
python
import openai
import faiss
import numpy as np
from pypdf import PdfReader
from dataclasses import dataclass
client = openai.OpenAI(
api_key="your-oneinfer-api-key",
base_url="https://api.oneinfer.ai/v1"
)
@dataclass
class Chunk:
text: str
source: str
page: int
def load_and_chunk(pdf_path: str, chunk_size: int = 600) -> list[Chunk]:
reader = PdfReader(pdf_path)
chunks = []
for i, page in enumerate(reader.pages):
text = (page.extract_text() or "").strip()
for j in range(0, len(text), chunk_size):
chunks.append(Chunk(text[j:j+chunk_size], pdf_path, i+1))
return chunks
def build_index(chunks: list[Chunk]):
texts = [c.text for c in chunks]
resp = client.embeddings.create(model="text-embedding-3-small", input=texts)
vectors = np.array([d.embedding for d in resp.data], dtype="float32")
index = faiss.IndexFlatL2(vectors.shape[1])
index.add(vectors)
return index, vectors
chunks = load_and_chunk("research_paper.pdf")
index, vectors = build_index(chunks)
print(f"Indexed {len(chunks)} chunks")2
Answer questions grounded in sources
python
def ask(question: str, top_k: int = 5) -> dict:
q_resp = client.embeddings.create(model="text-embedding-3-small", input=[question])
q_vec = np.array([q_resp.data[0].embedding], dtype="float32")
_, indices = index.search(q_vec, top_k)
relevant = [chunks[i] for i in indices[0]]
context = "\n\n".join(
f"[Source: {c.source}, Page {c.page}]\n{c.text}"
for c in relevant
)
response = client.chat.completions.create(
model="meta-llama/Llama-3.3-70B-Instruct-Turbo",
messages=[
{"role": "system", "content": (
"You are a research assistant. Answer questions strictly based on "
"the provided source material. Always cite the page number."
)},
{"role": "user", "content": f"Sources:\n{context}\n\nQuestion: {question}"}
]
)
return {
"answer": response.choices[0].message.content,
"sources": [{"source": c.source, "page": c.page} for c in relevant]
}
result = ask("What methodology did the authors use?")
print(result["answer"])3
Generate a podcast-style audio summary
python
def generate_podcast(chunks: list[Chunk], num_chunks: int = 8) -> bytes:
sample_text = " ".join(c.text for c in chunks[:num_chunks])
script_resp = client.chat.completions.create(
model="meta-llama/Llama-3.3-70B-Instruct-Turbo",
messages=[
{"role": "system", "content": "Write a 2-3 minute podcast script summarizing this research. Be engaging and clear."},
{"role": "user", "content": sample_text}
]
)
script = script_resp.choices[0].message.content
audio_resp = client.audio.speech.create(
model="tts-1-hd",
voice="nova",
input=script
)
return audio_resp.content
audio = generate_podcast(chunks)
with open("notebook_podcast.mp3", "wb") as f:
f.write(audio)
print("Podcast saved!")