tiny-rag-ai 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: tiny-rag-ai
3
+ Version: 0.1.0
4
+ Summary: Complete In-Device RAG chatbot library, no API keys needed.With 2 lines of implementation in applications.
5
+ Project-URL: Homepage, https://github.com/Madhan-1000/tiny-ai
6
+ Requires-Python: >=3.9
7
+ Requires-Dist: faiss-cpu
8
+ Requires-Dist: sentence-transformers
9
+ Requires-Dist: llama-cpp-python
10
+ Requires-Dist: huggingface-hub
11
+ Requires-Dist: pymupdf
12
+ Requires-Dist: numpy
@@ -0,0 +1,15 @@
1
+ # Tiny AI
2
+
3
+ A lightweight Python library for embedding a chatbot into your web app with a simple function call.
4
+
5
+ ## What it is
6
+ - Wraps the Qwen2.5-0.5B-Instruct-GGUF model.
7
+ - Runs inference in about 330 MB of memory on-device.
8
+ - Avoids heavy RAG pipelines by accepting documents directly through its parameters.
9
+
10
+ ## Why use it
11
+ - Minimal setup and small footprint.
12
+ - Focus on your app logic instead of infrastructure.
13
+
14
+ ## Status
15
+ - Code coming soon.
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64"]
3
+ build-backend = "setuptools.build_meta" # ← change this line
4
+
5
+
6
+
7
+ [project]
8
+ name = "tiny-rag-ai"
9
+ version = "0.1.0"
10
+ description = "Complete In-Device RAG chatbot library, no API keys needed.With 2 lines of implementation in applications."
11
+ requires-python = ">=3.9"
12
+
13
+ dependencies = [
14
+ "faiss-cpu",
15
+ "sentence-transformers",
16
+ "llama-cpp-python",
17
+ "huggingface-hub",
18
+ "pymupdf",
19
+ "numpy",
20
+ ]
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/Madhan-1000/tiny-ai"
24
+
25
+
26
+
27
+ [tool.setuptools.packages.find]
28
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,34 @@
1
+ from . import engine,indexer
2
+ import faiss
3
+ import numpy as np
4
+
5
+
6
+ def index(folder_path, save_path="./tiny_ai_data"):
7
+ """
8
+ This fucntion does many things to initialize the setup.
9
+ -> First loads all the documents
10
+ -> Second the seperates them into chunks
11
+ -> Third Loads all the AI models
12
+ -> Then Embeddes the chunks into vectors
13
+ -> Then it will store them in a faiss index
14
+ -> After that the path for saving the indexes is done
15
+ """
16
+
17
+ documents=indexer.load_documenmts(folder_path=folder_path)
18
+ chunks=[]
19
+ for doc in documents:
20
+ chunks.extend(indexer.chunk_text(text=doc,chunk_size=500,overlap=50 ))
21
+ engine._load_models()
22
+ embeddings=indexer.embed_chunks(chunks=chunks, embed_model=engine._embed_model)
23
+ dimensions=embeddings.shape[1]
24
+ faiss_index=faiss.IndexFlatL2(dimensions)
25
+ engine.set_save_path(save_path)
26
+ faiss_index.add(embeddings)
27
+ indexer.save_index(faiss_index,chunks=chunks,save_path=save_path)
28
+
29
+
30
+ def chat(query, use_case):
31
+ """
32
+ This fucntion does exactly what is in its name it just calls the ai fucntion.
33
+ """
34
+ return engine.chat(user_query=query,usecase=use_case)
@@ -0,0 +1,90 @@
1
+ import os
2
+ import faiss
3
+ import pickle
4
+ from pathlib import Path
5
+
6
+
7
+ _cache_dir = os.environ.get("TINY_AI_CACHE_DIR", os.path.expanduser("~/.cache/tiny_ai"))
8
+ _embed_model = None
9
+ _llm = None
10
+ _index = None
11
+ _chunks = None
12
+ _save_path = None
13
+
14
+ def set_save_path(path: str):
15
+ global _save_path
16
+ _save_path = path
17
+
18
+
19
+ def _load_models(cache_dir=_cache_dir):
20
+ global _embed_model, _llm, _index, _chunks
21
+ if _embed_model is None:
22
+ from sentence_transformers import SentenceTransformer
23
+ _embed_model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2" ,cache_folder=_cache_dir)
24
+ if _llm is None:
25
+
26
+ from huggingface_hub import hf_hub_download
27
+ from llama_cpp import Llama
28
+
29
+ model_path = hf_hub_download(
30
+ repo_id="Qwen/Qwen2.5-0.5B-Instruct-GGUF",
31
+ filename="qwen2.5-0.5b-instruct-q4_k_m.gguf",
32
+ cache_dir=_cache_dir
33
+ )
34
+ _llm = Llama(model_path=model_path, n_ctx=4096, n_threads=16)
35
+
36
+
37
+ def _load_index():
38
+ global _index, _chunks ,_save_path
39
+ if _save_path is None:
40
+ default = Path("./tiny_ai_data/config.txt")
41
+ if default.exists():
42
+ _save_path = default.read_text().strip()
43
+ else:
44
+ print("Error: run index() first")
45
+ return
46
+ if _index is None:
47
+ _index = faiss.read_index(str(Path(_save_path) / "faiss.index"))
48
+
49
+ if _chunks is None:
50
+ try:
51
+ with open(Path(_save_path) / "chunks.pkl", "rb") as f:
52
+ _chunks = pickle.load(f)
53
+ except FileNotFoundError:
54
+ print("Error: index files not found, run index() first")
55
+ except Exception as e:
56
+ print(f"An error occurred: {e}")
57
+
58
+ def search(query: str, k=6):
59
+ _load_models()
60
+ _load_index()
61
+ query_vector = _embed_model.encode([query]).astype("float32").reshape(1, -1)
62
+ distances, indices = _index.search(query_vector, k)
63
+ results = [_chunks[i] for i in indices[0]]
64
+ return "\n".join(results)
65
+
66
+
67
+ def build_prompt(query: str, context, use_case: str):
68
+ prompt = f"""<|im_start|>system
69
+ You are a helpful chatbot assistant for {use_case} and you must say I don't know or I can't answer it with a reason why if anything outside of this context.
70
+ Use ONLY the context below to answer.
71
+ CONTEXT:
72
+ {context}<|im_end|>
73
+ <|im_start|>user
74
+ {query}<|im_end|>
75
+ <|im_start|>assistant
76
+ """
77
+ return prompt
78
+
79
+ def generate(prompt:str,max_tokens:int=650):
80
+ _load_models()
81
+ answer_output=_llm(prompt,max_tokens=max_tokens,echo=False,stop=["<|im_end|>"])
82
+ return answer_output["choices"][0]["text"].strip()
83
+
84
+ def chat(user_query:str,usecase:str):
85
+ context=search(query=user_query)
86
+
87
+ prompt=build_prompt(user_query,context=context,use_case=usecase)
88
+
89
+ answer=generate(prompt=prompt)
90
+ return answer
@@ -0,0 +1,141 @@
1
+ import faiss
2
+ import pickle
3
+ import fitz
4
+ from pathlib import Path
5
+
6
+ def load_documenmts(folder_path: str) -> list:
7
+ """
8
+ Returns all the loaded documents in the path.
9
+
10
+ Parameters
11
+ ----------
12
+ path : str
13
+ path for the folder of the web application or any application detailed documents either in .txt files or .pdf files.
14
+
15
+ Returns
16
+ -------
17
+ returns all the text in the documents in form of array of each document in a string.
18
+ """
19
+ docs=[]
20
+ folder=Path(folder_path)
21
+ for pdf_file in folder.glob("**/*.pdf"):
22
+
23
+ pdf_content=load_pdf(pdf_file_path=pdf_file)
24
+ docs.append(pdf_content)
25
+
26
+ for txt_file in folder.glob("**/*.txt"):
27
+
28
+ txt_file_content=load_txt(txt_file_path=txt_file)
29
+ docs.append(txt_file_content)
30
+
31
+ return docs
32
+
33
+
34
+ def load_txt(txt_file_path: str) -> str:
35
+ """
36
+ Returns all the content in the txt file.
37
+
38
+ Parameters
39
+ ----------
40
+ txt_file_path : str
41
+ path for the txt file.
42
+
43
+ Returns
44
+ -------
45
+ returns the text file content
46
+ """
47
+ text=""
48
+ with open(txt_file_path,"r") as file:
49
+ text=file.read()
50
+
51
+ return text
52
+
53
+
54
+ def load_pdf(pdf_file_path: str) -> str:
55
+ """
56
+ Returns all the content in the pdf file.
57
+
58
+ Parameters
59
+ ----------
60
+ pdf_file_path : str
61
+ path for the pdf file.
62
+
63
+ Returns
64
+ -------
65
+ returns the pdf file content
66
+ """
67
+ try:
68
+
69
+ doc=fitz.open(pdf_file_path)
70
+ text=""
71
+
72
+ for page in doc:
73
+ text+=page.get_text()
74
+ doc.close()
75
+
76
+ except Exception as e:
77
+ print(f"Error processing file {pdf_file_path.name}: {e}")
78
+ return text
79
+
80
+
81
+
82
+ def chunk_text(text :str , chunk_size:int , overlap:int)-> list :
83
+
84
+ """
85
+ Returns the chunked text with size of 'chunk_size' and with overlap of 'overlap'.
86
+
87
+ Parameters
88
+ ----------
89
+ text : str
90
+ the text of all the documents
91
+ chunk_size : int
92
+ the variable for chunking the data
93
+ overlap : int
94
+ the variable for overlapping the chunked data
95
+
96
+ Returns
97
+ -------
98
+ returns all the text in the documents in form of array of each document in a string.
99
+ """
100
+ chunks = []
101
+ start = 0
102
+ while start < len(text):
103
+ end = start + chunk_size
104
+ chunks.append(text[start:end])
105
+ start += chunk_size - overlap
106
+ return chunks
107
+
108
+ def embed_chunks(chunks:list,embed_model):
109
+ """
110
+ Returns the embedded chunks of data.
111
+
112
+ Parameters
113
+ ----------
114
+ chunks : list
115
+ the text of all the documents
116
+
117
+ embed_model
118
+ the model with transformer
119
+ Returns
120
+ -------
121
+ array of float32 values which are embedded using the model.
122
+ """
123
+ embeddings_array=embed_model.encode(chunks).astype("float32")
124
+ if len(embeddings_array.shape) == 1:
125
+ embeddings_array = embeddings_array.reshape(1, -1)
126
+ return embeddings_array
127
+
128
+
129
+
130
+ def save_index(index, chunks: list, save_path: str):
131
+ """
132
+ Saves the FAISS index and chunks to disk.
133
+ """
134
+ path = Path(save_path)
135
+
136
+ path.mkdir(parents=True, exist_ok=True)
137
+ faiss.write_index(index, str(path / "faiss.index"))
138
+
139
+
140
+ with open(path / "chunks.pkl", "wb") as f:
141
+ pickle.dump(chunks,f)
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: tiny-rag-ai
3
+ Version: 0.1.0
4
+ Summary: Complete In-Device RAG chatbot library, no API keys needed.With 2 lines of implementation in applications.
5
+ Project-URL: Homepage, https://github.com/Madhan-1000/tiny-ai
6
+ Requires-Python: >=3.9
7
+ Requires-Dist: faiss-cpu
8
+ Requires-Dist: sentence-transformers
9
+ Requires-Dist: llama-cpp-python
10
+ Requires-Dist: huggingface-hub
11
+ Requires-Dist: pymupdf
12
+ Requires-Dist: numpy
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/tiny_rag_ai/__init__.py
4
+ src/tiny_rag_ai/engine.py
5
+ src/tiny_rag_ai/indexer.py
6
+ src/tiny_rag_ai.egg-info/PKG-INFO
7
+ src/tiny_rag_ai.egg-info/SOURCES.txt
8
+ src/tiny_rag_ai.egg-info/dependency_links.txt
9
+ src/tiny_rag_ai.egg-info/requires.txt
10
+ src/tiny_rag_ai.egg-info/top_level.txt
11
+ tests/test_engine.py
12
+ tests/test_indexer.py
@@ -0,0 +1,6 @@
1
+ faiss-cpu
2
+ sentence-transformers
3
+ llama-cpp-python
4
+ huggingface-hub
5
+ pymupdf
6
+ numpy
@@ -0,0 +1 @@
1
+ tiny_rag_ai
@@ -0,0 +1 @@
1
+ #python script to test engine.py seperatly.
@@ -0,0 +1 @@
1
+ #python script to test indexer.py seperatly.