Sentence Similarity
sentence-transformers
English
zephyr
zephyr-rtos
rag
retrieval
faiss
documentation
embedded
qwen
offline
Instructions to use eoinedge/zephyrproject with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- sentence-transformers
How to use eoinedge/zephyrproject with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("eoinedge/zephyrproject") sentences = [ "That is a happy person", "That is a happy dog", "That is a very happy person", "Today is a sunny day" ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [4, 4] - Notebooks
- Google Colab
- Kaggle
| """Gradio app for the Zephyr docs RAG. | |
| Deployed at https://huggingface.co/spaces/eoinedge/zephyrproject-rag and | |
| runnable locally with `python app.py`. | |
| Retrieval and generation are separate tabs on purpose. Retrieval alone is fast, | |
| runs on CPU, and answers "where is this documented?" — which is often the whole | |
| question. Generation is opt-in because on a free CPU Space it is slow, and a | |
| slow wrong answer is worse than a fast citation. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import os | |
| import sys | |
| from functools import lru_cache | |
| from pathlib import Path | |
| import gradio as gr | |
| sys.path.insert(0, str(Path(__file__).resolve().parent / "scripts")) | |
| import retrieval # noqa: E402 | |
| if hasattr(sys.stdout, "reconfigure"): | |
| sys.stdout.reconfigure(encoding="utf-8", errors="replace") | |
| ROOT = Path(__file__).resolve().parent | |
| INDEX_DIR = Path(os.environ.get("ZEPHYR_INDEX", ROOT / "data" / "index")) | |
| GEN_MODEL = os.environ.get("ZEPHYR_GEN_MODEL", "Qwen/Qwen2.5-Coder-1.5B-Instruct") | |
| ENABLE_GENERATION = os.environ.get("ZEPHYR_ENABLE_GENERATION", "0") == "1" | |
| SYSTEM_PROMPT = ( | |
| "You are a Zephyr RTOS assistant. Answer only from the documentation excerpts " | |
| "provided. Zephyr is large and moves fast, and a confident wrong answer costs an " | |
| "engineer hours on hardware — if the excerpts do not cover the question, say so " | |
| "and name what is missing rather than filling the gap from general RTOS knowledge. " | |
| "Cite the source path for anything you assert. Show configuration as it would " | |
| "actually appear: a Kconfig symbol, a devicetree node, a west command." | |
| ) | |
| EXAMPLES = [ | |
| "How do I define a devicetree binding for a new sensor?", | |
| "What is the difference between a work queue and a thread?", | |
| "How do I enable logging and set the log level for one module?", | |
| "How do I add a custom board definition?", | |
| "What does CONFIG_MAIN_STACK_SIZE control?", | |
| "How do I use west to build for a specific board?", | |
| ] | |
| def resources(): | |
| return retrieval.load(str(INDEX_DIR)) | |
| def search(question: str, k: int) -> list[dict]: | |
| """Shared with the CLI via scripts/retrieval.py — same index, same | |
| re-ranking, so a result here matches a result from `scripts/ask.py`.""" | |
| try: | |
| return retrieval.search(question, int(k), INDEX_DIR) | |
| except FileNotFoundError as error: | |
| raise gr.Error(str(error)) from error | |
| def render(hits: list[dict]) -> str: | |
| if not hits: | |
| return "Nothing retrieved." | |
| blocks = ["### Retrieved passages\n"] | |
| for position, hit in enumerate(hits, start=1): | |
| blocks.append( | |
| f"**{position}. [{hit['source']}]({hit['url']})** — {hit['section']} \n" | |
| f"`similarity {hit['score']:.3f}`\n\n" | |
| f"```\n{hit['text'][:900]}\n```\n" | |
| ) | |
| return "\n".join(blocks) | |
| def do_retrieve(question: str, k: int) -> str: | |
| if not question.strip(): | |
| return "Ask something about Zephyr." | |
| return render(search(question, k)) | |
| def generator(): | |
| import torch | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| tokenizer = AutoTokenizer.from_pretrained(GEN_MODEL) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| GEN_MODEL, | |
| torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32, | |
| device_map="auto" if torch.cuda.is_available() else None, | |
| ) | |
| return tokenizer, model | |
| def do_answer(question: str, k: int) -> tuple[str, str]: | |
| if not question.strip(): | |
| return "Ask something about Zephyr.", "" | |
| hits = search(question, k) | |
| if not hits: | |
| return "Nothing retrieved — the index may not cover this.", "" | |
| if not ENABLE_GENERATION: | |
| return ( | |
| "Generation is off on this Space (CPU hardware makes it slow enough to be " | |
| "misleading). The retrieved passages below are the grounded answer; set " | |
| "`ZEPHYR_ENABLE_GENERATION=1` to turn the model on locally or on GPU " | |
| "hardware.", | |
| render(hits), | |
| ) | |
| tokenizer, model = generator() | |
| context = "\n\n".join( | |
| f"[{index + 1}] {hit['source']} - {hit['section']}\n{hit['text']}" | |
| for index, hit in enumerate(hits) | |
| ) | |
| messages = [ | |
| {"role": "system", "content": SYSTEM_PROMPT}, | |
| {"role": "user", "content": f"Documentation excerpts:\n\n{context}\n\nQuestion: {question}"}, | |
| ] | |
| prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | |
| inputs = tokenizer(prompt, return_tensors="pt").to(model.device) | |
| output = model.generate( | |
| **inputs, max_new_tokens=512, do_sample=False, pad_token_id=tokenizer.eos_token_id | |
| ) | |
| answer = tokenizer.decode( | |
| output[0][inputs["input_ids"].shape[1] :], skip_special_tokens=True | |
| ).strip() | |
| return answer, render(hits) | |
| def corpus_note() -> str: | |
| try: | |
| _, _, _, meta = resources() | |
| except Exception: | |
| return "Index not built yet." | |
| source = str(meta.get("source", "")).replace("\n", " · ").strip(" ·") | |
| return ( | |
| f"**{meta['chunks']:,} chunks** from **{meta['documents']} documents** · " | |
| f"embeddings `{meta['embedding_model']}` · {meta['index']} \n" | |
| f"<sub>{source}</sub>" | |
| ) | |
| with gr.Blocks(title="Zephyr Docs RAG", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# Zephyr RTOS documentation assistant") | |
| gr.Markdown( | |
| "Retrieval over the Zephyr documentation source, built from the RST in " | |
| "`zephyrproject-rtos/zephyr`. Every passage links back to the page it came " | |
| "from, so an answer can always be checked against the docs." | |
| ) | |
| gr.Markdown(corpus_note()) | |
| with gr.Tab("Ask"): | |
| question = gr.Textbox(label="Question", placeholder=EXAMPLES[0], lines=2) | |
| with gr.Row(): | |
| top_k = gr.Slider(1, 12, value=6, step=1, label="Passages to retrieve") | |
| ask_button = gr.Button("Ask", variant="primary") | |
| answer_box = gr.Markdown(label="Answer") | |
| sources_box = gr.Markdown(label="Sources") | |
| gr.Examples(examples=EXAMPLES, inputs=question) | |
| ask_button.click(do_answer, [question, top_k], [answer_box, sources_box]) | |
| question.submit(do_answer, [question, top_k], [answer_box, sources_box]) | |
| with gr.Tab("Search only"): | |
| gr.Markdown( | |
| "Retrieval with no model in the loop. Fast, and often the whole answer — " | |
| "the passage you need with a link to the page." | |
| ) | |
| search_question = gr.Textbox(label="Question", lines=2) | |
| search_k = gr.Slider(1, 20, value=8, step=1, label="Passages") | |
| search_button = gr.Button("Search", variant="primary") | |
| search_output = gr.Markdown() | |
| search_button.click(do_retrieve, [search_question, search_k], search_output) | |
| search_question.submit(do_retrieve, [search_question, search_k], search_output) | |
| if __name__ == "__main__": | |
| demo.launch( | |
| server_name=os.environ.get("GRADIO_SERVER_NAME", "0.0.0.0"), | |
| server_port=int(os.environ.get("GRADIO_SERVER_PORT", "7860")), | |
| ) | |