From 1fb07264997a54955b53b10e94037c40d4b767b0 Mon Sep 17 00:00:00 2001 From: NJEI03 Date: Fri, 26 Sep 2025 13:05:12 +0100 Subject: [PATCH 01/33] Imported important modules --- hello-llm/main.py | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 hello-llm/main.py diff --git a/hello-llm/main.py b/hello-llm/main.py new file mode 100644 index 0000000..c12a455 --- /dev/null +++ b/hello-llm/main.py @@ -0,0 +1,4 @@ +from fastapi import FastAPI +from pydantic import BaseModel +from transformers import pipeline #Easiest way to use + From 85070369690f81486e9162ba497e3a981df893c1 Mon Sep 17 00:00:00 2001 From: NJEI03 Date: Fri, 26 Sep 2025 13:07:27 +0100 Subject: [PATCH 02/33] Created the fast api server and loaing the model from HF --- hello-llm/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hello-llm/main.py b/hello-llm/main.py index c12a455..175433d 100644 --- a/hello-llm/main.py +++ b/hello-llm/main.py @@ -2,3 +2,8 @@ from pydantic import BaseModel from transformers import pipeline #Easiest way to use +#Creating the app +app = FastAPI() + +#Loading the model once the app starts +generator = pipeline('text-generation', model='distilgpt2') \ No newline at end of file From a0096ab19af5859eb76ac15ca13a7a28ce3a2e2f Mon Sep 17 00:00:00 2001 From: NJEI03 Date: Fri, 26 Sep 2025 13:09:08 +0100 Subject: [PATCH 03/33] Defined our basemodel --- hello-llm/main.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hello-llm/main.py b/hello-llm/main.py index 175433d..aa96249 100644 --- a/hello-llm/main.py +++ b/hello-llm/main.py @@ -6,4 +6,9 @@ app = FastAPI() #Loading the model once the app starts -generator = pipeline('text-generation', model='distilgpt2') \ No newline at end of file +generator = pipeline('text-generation', model='distilgpt2') + +#Defining wjat my API expects, which is a prompt string + +class Request:(BaseModel): +prompt: str \ No newline at end of file From d6ff9db5414e27bd804820ec0d8792333585a575 Mon Sep 17 00:00:00 2001 From: NJEI03 Date: Fri, 26 Sep 2025 13:42:38 +0100 Subject: [PATCH 04/33] Tested the endpoint and it works --- hello-llm/__pycache__/main.cpython-313.pyc | Bin 0 -> 1116 bytes hello-llm/main.py | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 hello-llm/__pycache__/main.cpython-313.pyc diff --git a/hello-llm/__pycache__/main.cpython-313.pyc b/hello-llm/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6d695848020c29b266efe4914800d57527cc44c GIT binary patch literal 1116 zcmZ8fO>Y!O5Urli-Sw^w3J%6dXs{edBe8)XHW49;1VKP-VIg;%3nPsNyS*MVJ2O=G zV&H&`g1|>|upoy>Il_&ff`t^J5k7J9ZLReWNcHTlh0;=2SG}t4s;+wdMxzF_u0H#B z{ci){lQu@n9xDA8q-+BR&K6*vA@j6uEEw}9nx$?oSo1d89t3O#TElDT1ojMYi`(3} zXrMa@7d|_9wZ#S|uLYG01|OS-yVl{$wRYWa?CAiX74Ef2 zs>`>2A+>rXlHz8zDiSg(d7O(RPQ{}MB_60|TciRb6=!KtTaBfPlXkAoQ=r|^H&#AN z55w}H?-9BU0U+am24`q~1%VaV-1wS2+(f5s`F7zhiF;ik)n0?p!pSk~4NB!hL4Bv~^_IzcCj({J*JSfwnb(EpS!iRbX4KJjb;kBvN! zYG)7c6)q0?vND_|1p#PY=?3?IC9w^+4}Ht9L>&D8;*1*?jg;LU@e!8Uh#kZ}bD42V zySS<4IW`Nvy|{Otbee6g6FmqMk+#)(F+TjZSPeBHQ0MZ^qB?{##4$n&J4b4UZ{U~O za!|-_qNEP?Je<^6WAxDAol}Gzr7gcBu?Ytbj30lo@$&JXkKfMhG+LY2K3dhSxu-XK z4pdLPn)~PIU;ew<3p>-To@tCZJuqyiY~P|kR=8_K<|vO*H;5?wa5YM4;Am;Ht}sgF zT814OG3wtIW|Zf6lC*Lvg_UQ-99>Y!iosOMnkzpJxc3vzl2^A}{zjr_GRAh{ Date: Fri, 26 Sep 2025 13:46:18 +0100 Subject: [PATCH 05/33] Added model params for controlling output --- hello-llm/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hello-llm/main.py b/hello-llm/main.py index 12b9460..4ab7bbf 100644 --- a/hello-llm/main.py +++ b/hello-llm/main.py @@ -17,7 +17,9 @@ class Request(BaseModel): @app.post('/hello-llm') def generate_text(request: Request): #Calling the model - result = generator(request.prompt, max_length=50) + result = generator(request.prompt, max_length=100, + num_return_sequences=1, + temperature=0.7, repetition_penalty=1.5, do_sample=True) print(result) # Return the generated text return{ From d7f9f4deb9e9d4043c31588aa6a54f32b646604f Mon Sep 17 00:00:00 2001 From: NJEI03 Date: Fri, 26 Sep 2025 13:59:51 +0100 Subject: [PATCH 06/33] Created the fastapi app --- Text Summarizer API/main.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Text Summarizer API/main.py diff --git a/Text Summarizer API/main.py b/Text Summarizer API/main.py new file mode 100644 index 0000000..6967ec8 --- /dev/null +++ b/Text Summarizer API/main.py @@ -0,0 +1,5 @@ +from fastapi import FastAPI +from pydantic import BaseModel +from transformers import pipeline + +app = FastAPI() \ No newline at end of file From b766c73cdfcac634317cba147515dc2f3a53bd38 Mon Sep 17 00:00:00 2001 From: NJEI03 Date: Fri, 26 Sep 2025 14:01:48 +0100 Subject: [PATCH 07/33] Loaded the summarization pipeline --- Text Summarizer API/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Text Summarizer API/main.py b/Text Summarizer API/main.py index 6967ec8..661a4aa 100644 --- a/Text Summarizer API/main.py +++ b/Text Summarizer API/main.py @@ -2,4 +2,7 @@ from pydantic import BaseModel from transformers import pipeline -app = FastAPI() \ No newline at end of file +app = FastAPI() + +#Loading the summarization pipeline +summarizer = pipeline("summarization", model="facebook/bart-large-cnn") \ No newline at end of file From cb520f50f83a4ef9db8c9bce70c6fed443873362 Mon Sep 17 00:00:00 2001 From: NJEI03 Date: Fri, 26 Sep 2025 14:11:07 +0100 Subject: [PATCH 08/33] Created the endpoint to summarize --- .../__pycache__/main.cpython-313.pyc | Bin 0 -> 1155 bytes Text Summarizer API/main.py | 19 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Text Summarizer API/__pycache__/main.cpython-313.pyc diff --git a/Text Summarizer API/__pycache__/main.cpython-313.pyc b/Text Summarizer API/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bd305bcc2897db349bcca8b056fd8f29938f51f GIT binary patch literal 1155 zcmZ8f-D@0G6hC*qc6YM7g~lXHg*qvU40Nr65hGG)mDDB}N^bKY4h}b)o6XqWnd!NA z+a|t51*=c44}ts({x=pumccxTPkGz0`2#$6b`y#h?zzA7bn^$hMC=x<%-qn6+*`mM?s9L{!b%H> ztK0xyjqDYBYJ}Cu+nS#_y!Ps%}* zuy$W4`DL~%d&E@pB$vG;l|@4h`h9`Pq0mW|9xm;Pj@-$zCwF!P>UK|HSGGH8N^zie(9_B|1pzJ?S@X)a^u}cpHtDL5i5$U&2hG-~ zdhOTxFZI#<;%I(hbbaZ(<~F^fwQ&<_*M}dSEdRE8^3ALH+hg0B^TuGgUfIpfaIUEA z(bkJRLDMhV^@ClJ(k7r|*t$lMs=W;RGG503l`kFn`}TeTi>^SzWpa#8e2Z|PVP>Co{0@s>)Z&+sQ&>9(IuY% literal 0 HcmV?d00001 diff --git a/Text Summarizer API/main.py b/Text Summarizer API/main.py index 661a4aa..d083a00 100644 --- a/Text Summarizer API/main.py +++ b/Text Summarizer API/main.py @@ -5,4 +5,21 @@ app = FastAPI() #Loading the summarization pipeline -summarizer = pipeline("summarization", model="facebook/bart-large-cnn") \ No newline at end of file +summarizer = pipeline("summarization", model="facebook/bart-large-cnn") + +#Define input: Now we need a longer text field +class SummaryRequest(BaseModel): + text: str + +@app.post('/summarize') +def summarize_text(request:SummaryRequest): + #Calling the model. We must handle long text by truncating within the model's limits + result = summarizer( + request.text, + max_length=130, #summary length + min_length=30, + do_sample=False #for summary to be deterministic + ) + return{ + "summary": result[0]['summary_text'] + } \ No newline at end of file From fe246a76de56789c7f220abb27aff33ffaf6662c Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Fri, 26 Sep 2025 14:31:44 +0100 Subject: [PATCH 09/33] Loaded our Classifer model from HF --- Sentiment Analysis API/main.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Sentiment Analysis API/main.py diff --git a/Sentiment Analysis API/main.py b/Sentiment Analysis API/main.py new file mode 100644 index 0000000..ff55f72 --- /dev/null +++ b/Sentiment Analysis API/main.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI +from pydantic import BaseModel +from transformers import pipeline + +app = FastAPI() +#Load the sentimnt analysis model + +classifier = pipeline("sentiment-analysis", model ="distilbert-base-uncased-finetuned-sst-2-english") + +class sentimentRequest(BaseModel): + text: str \ No newline at end of file From e2a013dadaa5d0990024bd38793c2318082786fe Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Fri, 26 Sep 2025 14:38:02 +0100 Subject: [PATCH 10/33] Loaded the model --- Sentiment Analysis API/main.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Sentiment Analysis API/main.py b/Sentiment Analysis API/main.py index ff55f72..5d9901d 100644 --- a/Sentiment Analysis API/main.py +++ b/Sentiment Analysis API/main.py @@ -7,5 +7,15 @@ classifier = pipeline("sentiment-analysis", model ="distilbert-base-uncased-finetuned-sst-2-english") -class sentimentRequest(BaseModel): - text: str \ No newline at end of file +class SentimentRequest(BaseModel): + text: str + +@app.post("/sentiment") +def analyze_sentiment(request:SentimentRequest ): + # Modal reruns a list of results for our unique input + result = classifier(request.text)[0] + + return{ + "sentiment": result['label'], + "confidence": round(result['score'], 4) # round to 4 decimal places + } \ No newline at end of file From 0ab76340d86678234f7f15924df55344cdb3a11b Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 06:03:43 +0100 Subject: [PATCH 11/33] Added images --- Multimodal image captioning API/main.py | 14 ++++++++++++++ .../__pycache__/main.cpython-313.pyc | Bin 0 -> 1200 bytes hello-llm/__pycache__/main.cpython-313.pyc | Bin 1116 -> 1228 bytes 3 files changed, 14 insertions(+) create mode 100644 Multimodal image captioning API/main.py create mode 100644 Sentiment Analysis API/__pycache__/main.cpython-313.pyc diff --git a/Multimodal image captioning API/main.py b/Multimodal image captioning API/main.py new file mode 100644 index 0000000..71db788 --- /dev/null +++ b/Multimodal image captioning API/main.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from PIL import Image +from transformers import pipeline + +app = FastAPI() +#Loading the model +captioner = pipeline("image-to-text" , model="nlpconnect/vit-gpt2-image-captioning") + +app.post("/caption-image") +async def caption_image(file: UploadFile = File(...)): + #reading the uploaded images + image= Image.open(file.file) + + \ No newline at end of file diff --git a/Sentiment Analysis API/__pycache__/main.cpython-313.pyc b/Sentiment Analysis API/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22d8148e12a9092e2318932083e3c156d891b6d4 GIT binary patch literal 1200 zcmZ8gOK%)S5UzRddb|^!Syo9DhA0*cVr=oScnBdGkV9-?f=A|(kw(3`QF&!oFI z!9E!w5su+t5E|hF%E>od>mNY%?0OT?QdifbtE#K&>yht!fa~$^e{Gc} zz*8-pFK5Dx9w4&^F~r6ytQf)wG;gk&E0(Zo-deR+9N`3z7}sEN;wIe0xdyQvJF)w* zDHsc{M7W@0T`<4dBMxa+S>9G*MknMGqP#$M9=z>H@v!T0twvbWg^{bPM0G^)lj zk!tDIO=M?2Cz5_$^k|Mkvt%XB8K*lhOUe}+Ac+Vk`L<+oXQ9WWVtJPe6?M@o8uAQ} zUereqHRQ-isiOBH$~SW+w=keH(2=v}o(YpOU=*Ns4-ybY48n{JVa-8eCr)g>iI&(B z?xr0&)r;}@OV;U~A(iS_x4*I#{Zai1Yhj~mrYR=_nx>VPrkHS;Yrd7HcZMXNSYAle zJ`+;u;&_2(ODa*JmT+DuqFBKtYA>d#)KZobr3C8^6-Bj}#f&4|P~~5Il59vSWb)Om zGyM zq{{)0B^eOL=gV!;#FRDBCCdhq`|!8t|8i4k0MwQpZ(%yBsv*WL$|gv_O8^>^y6K|? z$sXLE+BRSv@%#TZMUkN$xv^oyrsi&+V;fLoX(6^3C;qWBZ(fJcT@zYSIXUUlymDk# z2zqRzDm1H^XV3Jqg7;aE@{ER7u+x=BHzTekSJ7sz)KeLvmsnhH(U!kKpPNyz#H= z|IBu+Q>>wV(0=>i{oWIw?s{joVO)5yeFk`7DW-G3^Hb;7cMgr$PRxek9$cLt0iGiZ L%+9IS)Or5{l=m(+ literal 0 HcmV?d00001 diff --git a/hello-llm/__pycache__/main.cpython-313.pyc b/hello-llm/__pycache__/main.cpython-313.pyc index e6d695848020c29b266efe4914800d57527cc44c..f778471d8f9c7ae56ba264a504836866f1bff1af 100644 GIT binary patch delta 318 zcmcb^afXxkGcPX}0}y=bx|Z>4BX0&17blR%48)&fCf74*)(0~OvjnpSvstp`F-Eh3 zl!8DgqbVbVrN9u(9?BTZ0g?)42ayJhDh!&OelJsi?3W-_>1kl_%sw5+0fHa)A)2hW zxN;LK;&W2-(n~UKiR6{$#uufQlosX17pE4MrsgH57T@A7NzGL+NG(bPil^QZDoQO# zEy*m&%+HH2NX<*kDXF~0nUWu0oS0jXlREhgQ>2kH&~QN@E_MMD4Gdq{82H2|luxgl zShqp>hNRRD0pS(Q8%jR1GV$3qxB+EZxh7{a#|kO{RTqK0eT$_azqq7GdGd8;Sw_vt eUzz_wB2FN2i=`mHxTHvKvO9|`qsrt| d7C%XLMz$H|pBaGEXJ!T_iH}S`R*?u$EdY%*D)j&W From d8587c60b04e81637b1dcf292a15c13ac0caf0b8 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 06:11:27 +0100 Subject: [PATCH 12/33] Added the captioner and solveed the file error by importing it --- Multimodal image captioning API/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Multimodal image captioning API/main.py b/Multimodal image captioning API/main.py index 71db788..af9b0a6 100644 --- a/Multimodal image captioning API/main.py +++ b/Multimodal image captioning API/main.py @@ -1,4 +1,4 @@ -from fastapi import FastAPI +from fastapi import FastAPI, File from PIL import Image from transformers import pipeline @@ -11,4 +11,6 @@ async def caption_image(file: UploadFile = File(...)): #reading the uploaded images image= Image.open(file.file) - \ No newline at end of file + #Generating caption + result=captioner(image) + From 05340c1ab0def3022201bc8a42509f7936aca492 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 06:21:02 +0100 Subject: [PATCH 13/33] Added comments for model size --- Multimodal image captioning API/main.py | 4 ++++ Sentiment Analysis API/main.py | 3 ++- Text Summarizer API/main.py | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Multimodal image captioning API/main.py b/Multimodal image captioning API/main.py index af9b0a6..2100e8b 100644 --- a/Multimodal image captioning API/main.py +++ b/Multimodal image captioning API/main.py @@ -14,3 +14,7 @@ async def caption_image(file: UploadFile = File(...)): #Generating caption result=captioner(image) + return{ + "caption": result[0]['generated_text'] + } +#Model is about 500MBs diff --git a/Sentiment Analysis API/main.py b/Sentiment Analysis API/main.py index 5d9901d..288e63b 100644 --- a/Sentiment Analysis API/main.py +++ b/Sentiment Analysis API/main.py @@ -18,4 +18,5 @@ def analyze_sentiment(request:SentimentRequest ): return{ "sentiment": result['label'], "confidence": round(result['score'], 4) # round to 4 decimal places - } \ No newline at end of file + } +#Model is 269MB \ No newline at end of file diff --git a/Text Summarizer API/main.py b/Text Summarizer API/main.py index d083a00..854440d 100644 --- a/Text Summarizer API/main.py +++ b/Text Summarizer API/main.py @@ -22,4 +22,5 @@ def summarize_text(request:SummaryRequest): ) return{ "summary": result[0]['summary_text'] - } \ No newline at end of file + } +#Model is about 1.6GB \ No newline at end of file From 65355d33f0918f9401f41ad4b54b7441b38d3a16 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 06:59:23 +0100 Subject: [PATCH 14/33] Crated the RAG logic --- Naive RAG system/main.py | 38 ++++++++++++++++++++++++++++++++++++++ Naive RAG system/rag.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 Naive RAG system/main.py create mode 100644 Naive RAG system/rag.py diff --git a/Naive RAG system/main.py b/Naive RAG system/main.py new file mode 100644 index 0000000..2d3b150 --- /dev/null +++ b/Naive RAG system/main.py @@ -0,0 +1,38 @@ +from langchain.vectorstores import Chroma +from langchain.embeddings import HuggingFaceEmbeddings +from langchain.text_splitter import CharacterTextSplitter +from langchain.schema import Document + +# 1. Initialize embedding model +embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") + +# 2. Create your knowledge base (simple example) +documents = [ + "Paul Biya has been the president of Cameroon since 1982.", + "FastAPI is a modern Python web framework for building APIs.", + "The capital of France is Paris." +] + +# 3. Split documents into chunks +text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0) +docs = [Document(page_content=text) for text in documents] +texts = text_splitter.split_documents(docs) + +# 4. Create vector store +vector_store = Chroma.from_documents(texts, embeddings) + +# 5. Create retriever +retriever = vector_store.as_retriever() + +def rag_query(question: str): + # 6. Retrieve relevant documents + relevant_docs = retriever.get_relevant_documents(question) + + # 7. Simple RAG: use the first relevant doc as context + context = relevant_docs[0].page_content if relevant_docs else "No relevant information found." + + return { + "question": question, + "context": context, + "answer": f"Based on the context: {context}" # In next step, we'll use an LLM here + } \ No newline at end of file diff --git a/Naive RAG system/rag.py b/Naive RAG system/rag.py new file mode 100644 index 0000000..2d3b150 --- /dev/null +++ b/Naive RAG system/rag.py @@ -0,0 +1,38 @@ +from langchain.vectorstores import Chroma +from langchain.embeddings import HuggingFaceEmbeddings +from langchain.text_splitter import CharacterTextSplitter +from langchain.schema import Document + +# 1. Initialize embedding model +embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") + +# 2. Create your knowledge base (simple example) +documents = [ + "Paul Biya has been the president of Cameroon since 1982.", + "FastAPI is a modern Python web framework for building APIs.", + "The capital of France is Paris." +] + +# 3. Split documents into chunks +text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0) +docs = [Document(page_content=text) for text in documents] +texts = text_splitter.split_documents(docs) + +# 4. Create vector store +vector_store = Chroma.from_documents(texts, embeddings) + +# 5. Create retriever +retriever = vector_store.as_retriever() + +def rag_query(question: str): + # 6. Retrieve relevant documents + relevant_docs = retriever.get_relevant_documents(question) + + # 7. Simple RAG: use the first relevant doc as context + context = relevant_docs[0].page_content if relevant_docs else "No relevant information found." + + return { + "question": question, + "context": context, + "answer": f"Based on the context: {context}" # In next step, we'll use an LLM here + } \ No newline at end of file From 3e740a667288cadda67287abbce39d6585feab27 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 07:29:57 +0100 Subject: [PATCH 15/33] Manual text knowledge base works fine --- .../__pycache__/main.cpython-313.pyc | Bin 0 -> 907 bytes .../__pycache__/rag.cpython-313.pyc | Bin 0 -> 1567 bytes Naive RAG system/main.py | 44 ++++-------------- 3 files changed, 9 insertions(+), 35 deletions(-) create mode 100644 Naive RAG system/__pycache__/main.cpython-313.pyc create mode 100644 Naive RAG system/__pycache__/rag.cpython-313.pyc diff --git a/Naive RAG system/__pycache__/main.cpython-313.pyc b/Naive RAG system/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..841a9910fcf37df47162646a6411f183d45b4a5e GIT binary patch literal 907 zcmZ8f-Afcv6hC)9c6Qgb(6ly-7$lVew+QmVh`_!q#l?1zhz5r1dR?b>XQp#UWh250 zvPWP1Bl>R&AB+JXqF#J6)<2+gXLlt!aL?E8+;h%7=XM4Mi$FB{{&2%$0Kb&cC$pz? zK9aHzF1TzF78o*H>Dr>UprfAY`l7L5qG^L?j>Amv8s^F{4z4iMcB2ud0Vz+B3fRH2jPvljq05lQ;Jk< z7k-=@`n-h0edKNNCQV)?!**(6cR=;t+9(J>jar?~G_iend4{b(O(WNT)L;2^+G^F& zP+i3WF^Ay@390Vec!79Y$jbWE0A3_p4M-|r2YwHX>^(mmo%lXFaWF9X&6vzOt~$k3 zSJ5hInvdISJftzBp-gL?{t1r*RDV3xc^qd?PmMUDEvfw32D(qr%IEKP_k0hp5~})= zkBFVMamALen6Ds`+IC6{|B!`u9f=h2nBapc9#&(*}k>>5&_sx9s=6i3B!{Gpe z@zZy`TFrydpW^3a_=e80Dk1b3=}4EB(UQa@EPQ!cUQ(FS_myRJ$-_K-UtRVt`IrwQ zLm5N5NB3qWrd>t4?+c0f4G+XL*zM2CEMWNK=u5=qt1#ne(T|XY4Br?kB0Z3m^72X$ zp&-J5T8IUWK;gnkYNuZ#I1Sl}!NP`AcxT|BwPVN#8``uyh_R>z%7HyFtJkS!`9Srd6FMWqQA{Mk^Kg;R2Ye z5k|@mWe@2iM{m|m2Ydjudv>|ipqA5)k$OG7Vp`^dmGpxf>CNka1{!vS)=L&?(3H}? zl_#w_o;9}#t`UycD7COtqqxZ^H!Hw_?R7i{Yng3Zn44Ca;%nJk*E8+g^MpIO{AbwY zm|#K5ES%qVYOrpLuHkhCyS8k$f!A$@*IH&>B#vPR&$Qot2xpW@({xB(oG{ObU5^9nvEtPG{fjnL9+ZN@HXwZv}f{4B`is+=&mQ<8J9HJzOP*Kt)=w4J1d~b};C0(}UA}Y$dQj{a; zV_8=-$~a1SR+;FD_T^O@Gg_yc1mrX=kfT9Fq99Dms$|-uvxL(MhJaAMf1gLr3{EL5 z1lwKTFyeZN#kZisitA_8VI~D7+|ep^N+;~4%CPdBL1&{AhVWUOvj{+3TpwfX(zzL< z$SLE-V&1q%`G#XRjRoieV&XO1cA!d)Ccb7=sYMy2y-CwKGreUxwX_MsvrUt3rB9^i z#wvjoxR6`Ge49J8VK7q7G`AsRQZ2zUw#^c7^4lVX`(Qfguf(NZVyc^%diK>`;%;Z< zA1|7`^L^tOsonEaM?N*=Jw&R%^*-Ys9oNo3!lMjKidyiOaf)Q;@!XM@$sded`o*;4PK-@G&t_b2oO1@^Xzf z2=j_?;FQJnzZTvN|Bt~{0pV`6&v;rM*CSSOH?j_|{7g7BNW0X}+YJ#8r5#q9#l)cs zcUWIR=zq1(A-a8%#RaH+0?)8jr*~Nreg(jP1aqiJl5~Jl2k6ED${wKPkrzd->}Edg zhI5_3E3X=sJN}~xI`{sw_^-KcY`zozV=}wvn|bcvQGd{$RDRd4{NnHWW;*J=Hqz6Q zT`l>vvZqaSJW!R`XfHbcB0B!GxU;kuz1aytEPSCCN_IoZz0e08|DhU`yib(B5q$oA Q6-U}_E@b^Vmb;_=2aI&C3IG5A literal 0 HcmV?d00001 diff --git a/Naive RAG system/main.py b/Naive RAG system/main.py index 2d3b150..180a33e 100644 --- a/Naive RAG system/main.py +++ b/Naive RAG system/main.py @@ -1,38 +1,12 @@ -from langchain.vectorstores import Chroma -from langchain.embeddings import HuggingFaceEmbeddings -from langchain.text_splitter import CharacterTextSplitter -from langchain.schema import Document +from rag import rag_query +from pydantic import BaseModel +from fastapi import FastAPI -# 1. Initialize embedding model -embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") +app= FastAPI() -# 2. Create your knowledge base (simple example) -documents = [ - "Paul Biya has been the president of Cameroon since 1982.", - "FastAPI is a modern Python web framework for building APIs.", - "The capital of France is Paris." -] +class QueryRequest(BaseModel): + question: str -# 3. Split documents into chunks -text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0) -docs = [Document(page_content=text) for text in documents] -texts = text_splitter.split_documents(docs) - -# 4. Create vector store -vector_store = Chroma.from_documents(texts, embeddings) - -# 5. Create retriever -retriever = vector_store.as_retriever() - -def rag_query(question: str): - # 6. Retrieve relevant documents - relevant_docs = retriever.get_relevant_documents(question) - - # 7. Simple RAG: use the first relevant doc as context - context = relevant_docs[0].page_content if relevant_docs else "No relevant information found." - - return { - "question": question, - "context": context, - "answer": f"Based on the context: {context}" # In next step, we'll use an LLM here - } \ No newline at end of file +@app.post("/rag-query") +def query_rag(request: QueryRequest): + return rag_query(request.question) \ No newline at end of file From acea30ecd170f902e7f0f0c4c64de8a0e80bcff2 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 08:31:24 +0100 Subject: [PATCH 16/33] Gets context --- .../__pycache__/doc_loader.cpython-313.pyc | Bin 0 -> 1549 bytes .../document_loader.cpython-313.pyc | Bin 0 -> 1788 bytes .../__pycache__/rag.cpython-313.pyc | Bin 1567 -> 2179 bytes Naive RAG system/data/cameroon.txt | 74 ++++++++++++++++++ Naive RAG system/document_loader.py | 36 +++++++++ Naive RAG system/rag.py | 64 +++++++++------ 6 files changed, 150 insertions(+), 24 deletions(-) create mode 100644 Naive RAG system/__pycache__/doc_loader.cpython-313.pyc create mode 100644 Naive RAG system/__pycache__/document_loader.cpython-313.pyc create mode 100644 Naive RAG system/data/cameroon.txt create mode 100644 Naive RAG system/document_loader.py diff --git a/Naive RAG system/__pycache__/doc_loader.cpython-313.pyc b/Naive RAG system/__pycache__/doc_loader.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07a072bb6567b03768f3cf0cc7302eda377d7eb6 GIT binary patch literal 1549 zcmb7E-A@}w5a0W-edcm2A#J6ubhk6JGryUg`^}vhMhAlR zuu?A!s0jTjlwc_>;p`>|KcN&#NehUIU0#q9GL;hwRj|;N1vL?(A&|o4@2~y0eK~%qlc!pqu9B9M#)lp$>Ed0iLAXmS@JuVg zxvQqtgRl@atWX$H~lJsk@2V6^lUAsu0K zzb80PDJeA-x*@yabU4`;SlfI0T_=W7JiL2Na12|HgMn|@a`SlQ-U?o|9m4P`^@`Xp z5S+Js3pcs8t4@^itMK->efur&c*Fq%NL*d_Y?o`q&9eu#U!X8?h^r3NM+KKfs1Ju!P?g7+7=mox z%WW2k>$7--3OaHPt|F|EL0rPMiiAgn)EE*T7H}{*(RYE|@Bug5fP}>v=xTS;Z3mJhMhzLM`9kBICF0aZ&uZ?E=`AO&*MY zw@H|9doIh|wZH=>Z_Q!0!+cWAKoQwyK@+7N-Y>-Vjk2Qs*=E-%khL+?>^TT~=p=S| zZ~m2TRHpZ*D>M5u)v>xhQqxC{wT_DZz5c_(uNppz^^{|;y1E}HeoRy!zUUe&Ysa9? zJ(_#G_-OH9;IM1D96ixH>-u0#AFO^;*N1ER@Ue*x`VP&p@|~mJp`Z09`cq^7t0Tj# z8$&f?sJc}*Mry{$vH8hC^w7Nep4T6jx=yr@DzW`oHTpuka@vQ?&)yCp^XgG&_fdE6 zX-F}{drNOLbg8edkJj|jXT68|9J*n-Yq^4DyA#2;YW0dW z=+LA`PuuIg&)6i1!hG6j-7koK44`yCAZuS1z5J#_X6UD&ieDV-hu0fLlBAa?`a7EW T4c$0Z2c$2a&Hja8YsCHy*zi~h literal 0 HcmV?d00001 diff --git a/Naive RAG system/__pycache__/document_loader.cpython-313.pyc b/Naive RAG system/__pycache__/document_loader.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccdb92f034992c6618409cc1cfa935f63480ab09 GIT binary patch literal 1788 zcma)6%}*Ow5P!Sg^#^OmalwEg39kfEAOTb;g`gIdLJGlr$%~~_ShBYE8ZX$p=Ixq* zd*KMZ0F|l`5uKt-tO5*2*b%yJc`w%R`8~9tchP*Uwc|kaK2-aB z!19QEn7sm|4co7vUhV?335gEXK5U=*8I`pJlRzKanoxpi7joT{wOC4}FfbTPY8=nq zpTh|yCF?jrv@|x7GLB1zgiGwrab1~s0=~wok>j&QqH_Qk@08V;7FX1T+?Bh8XauJq zE0{RP4&rI$HZb$m4XBjPO)QyJm!i6olTA-a*H&bbk}~aHlht&Sqw`_f`99BAM zOPx@xOjZ>6LFaN-)@ciRWLkm<92y?O`kHRY>4;TGv{YGFX3cD%>P2f&`hwBY!x0R% z(F@QSc#U=R!s}Zfe<^sj`ZxQxhBk+GZxw~sg3x;8tlAR361Ia+o%qmOx8Z$RQ~Pk@ z>xtbjpVi#ja2|m*wlnr{a%VE%cu>>7;X39#EA4t3bf=uKL~Vh z+Yhfbe;a%hd_1+|I`jpKzUG3jIsakN*HQ3w90hLX?|ttm1U`8q?zgM;FWfa-Gn+HJ z_nx_1Pa2W`_Ul&U?>MZkJ*=%i;cb5V`qZ%#xdTO^tsu1R)gK5wPq>~xUst26fm6h~ z{6}uz_H=$A-?8`U-tu1T$vZty-M!DkXQe zcxclNa`q_Sp;O3?2(8F;ew5bY*_1p)-UE~Vqw5XuIkqtj^9yqQipHO#J11Nd)4MnF K2ZDvP!uCHiq?yP7 literal 0 HcmV?d00001 diff --git a/Naive RAG system/__pycache__/rag.cpython-313.pyc b/Naive RAG system/__pycache__/rag.cpython-313.pyc index e36770006c79b043c8d38c8811935a805a791ee7..8b238aa2e53454ca33d678cd5b8567b72a33ac10 100644 GIT binary patch literal 2179 zcmbVN&2Q6Y7=Qf{C$W<>Gzs(rnAa9YKq(XktQ7*5}eo$NE|urP;MMJ?8yFuh9EVvR0(NlQg1EY4&3&<&PUPI(_YDse}2CF_$SwFho8xENEq{YX%0juY7<9bW_b|^JZ?fgbmxuE1H3xvOy_&N&`8&f>8l*UezjCUYxumTk96|G(*(FXnEZU z0ex&u)wL?lf{OIR+hcH9*Fn_Khw#~rD~<5Q+TFjT=!e*e&2tO&*uBl@;$#1ZNdH#k z%-hJBjsDlkM&w3qwkaLkl1A#%NJBck$)Dbb49M|yYRGjN0&3c8mpvyz3+$n;?po|} zq@zK=fi9yMg<13*SUM=p(2>ET2>PD2*z?F@BWNaskU4Z1s}|U~FhUZN!Ovj3xjBVP zb0MVgX#~=9$z$*b+&i=`z8mXFBew?O|J9K8DBe+S1nOzkwEP*0`{t{xDDKdWsU{{3 zYYh|mfokErY#RDH2-z-bmh7_fkv$=b)0CeSRRf}UuT6mox#}0iR`|pYC0U#!gK%?v z?MTZJR5yFv{`D1L=6%86BYv zGp%eB8KNxObJ<;_k7n@$-?G3CvQFagJWPFFf&kVd}!GKQyAFwYg>}`gG;V z%B!E=EWT0eS7#anci&!}dBtrFo_jZV4ixo)yNyt?c4wF8dYN4TvHqHW7qO!BUWzmAoOTcKh#M6gu+s{*(L9g+}m;+U@tzazVk|m?HeypA-ydgVQ=%{*KkCT3Y7}xs zRWo2rluD~`y4FWq=eu>hTa)7CVQvT0g3zhx^d05|TW=A11e}0PpkK=-DZ!K=bax%8 zxSZ|$VVs`Mgvrt$4JPiia*lPAj#83jt@fXV&@t3oC{o^$^oxVd%w3yCN;t^fc4 literal 1567 zcmZ8g&u<$=6rTNId;Qz3ouC$4hBO9DWH&8ITc@MamALen6Ds`+IC6{|B!`u9f=h2nBapc9#&(*}k>>5&_sx9s=6i3B!{Gpe z@zZy`TFrydpW^3a_=e80Dk1b3=}4EB(UQa@EPQ!cUQ(FS_myRJ$-_K-UtRVt`IrwQ zLm5N5NB3qWrd>t4?+c0f4G+XL*zM2CEMWNK=u5=qt1#ne(T|XY4Br?kB0Z3m^72X$ zp&-J5T8IUWK;gnkYNuZ#I1Sl}!NP`AcxT|BwPVN#8``uyh_R>z%7HyFtJkS!`9Srd6FMWqQA{Mk^Kg;R2Ye z5k|@mWe@2iM{m|m2Ydjudv>|ipqA5)k$OG7Vp`^dmGpxf>CNka1{!vS)=L&?(3H}? zl_#w_o;9}#t`UycD7COtqqxZ^H!Hw_?R7i{Yng3Zn44Ca;%nJk*E8+g^MpIO{AbwY zm|#K5ES%qVYOrpLuHkhCyS8k$f!A$@*IH&>B#vPR&$Qot2xpW@({xB(oG{ObU5^9nvEtPG{fjnL9+ZN@HXwZv}f{4B`is+=&mQ<8J9HJzOP*Kt)=w4J1d~b};C0(}UA}Y$dQj{a; zV_8=-$~a1SR+;FD_T^O@Gg_yc1mrX=kfT9Fq99Dms$|-uvxL(MhJaAMf1gLr3{EL5 z1lwKTFyeZN#kZisitA_8VI~D7+|ep^N+;~4%CPdBL1&{AhVWUOvj{+3TpwfX(zzL< z$SLE-V&1q%`G#XRjRoieV&XO1cA!d)Ccb7=sYMy2y-CwKGreUxwX_MsvrUt3rB9^i z#wvjoxR6`Ge49J8VK7q7G`AsRQZ2zUw#^c7^4lVX`(Qfguf(NZVyc^%diK>`;%;Z< zA1|7`^L^tOsonEaM?N*=Jw&R%^*-Ys9oNo3!lMjKidyiOaf)Q;@!XM@$sded`o*;4PK-@G&t_b2oO1@^Xzf z2=j_?;FQJnzZTvN|Bt~{0pV`6&v;rM*CSSOH?j_|{7g7BNW0X}+YJ#8r5#q9#l)cs zcUWIR=zq1(A-a8%#RaH+0?)8jr*~Nreg(jP1aqiJl5~Jl2k6ED${wKPkrzd->}Edg zhI5_3E3X=sJN}~xI`{sw_^-KcY`zozV=}wvn|bcvQGd{$RDRd4{NnHWW;*J=Hqz6Q zT`l>vvZqaSJW!R`XfHbcB0B!GxU;kuz1aytEPSCCN_IoZz0e08|DhU`yib(B5q$oA Q6-U}_E@b^Vmb;_=2aI&C3IG5A diff --git a/Naive RAG system/data/cameroon.txt b/Naive RAG system/data/cameroon.txt new file mode 100644 index 0000000..cf0d934 --- /dev/null +++ b/Naive RAG system/data/cameroon.txt @@ -0,0 +1,74 @@ + + +# Cameroon – Comprehensive Overview + +## 1. Geography and Location + +Cameroon is a country in Central Africa, often called "Africa in miniature" because of its geological, linguistic, and cultural diversity. It shares borders with Nigeria to the west, Chad to the northeast, the Central African Republic to the east, and Equatorial Guinea, Gabon, and the Republic of the Congo to the south. It has a coastline along the Atlantic Ocean (Gulf of Guinea). + +* **Capital city:** Yaoundé +* **Largest city and economic hub:** Douala +* **Climate:** Ranges from equatorial in the south, tropical in the center, to semi-arid in the north. +* **Notable landmarks:** Mount Cameroon (the highest peak in West and Central Africa), Lake Nyos, and Waza National Park. + +## 2. History + +* **Pre-colonial era:** Inhabited by diverse ethnic groups, kingdoms, and chiefdoms such as the Bamileke, Bamoun, and Fulani emirates. +* **Colonial period:** First colonized by Germany in 1884 (Kamerun). After World War I, the territory was divided between France and Britain under League of Nations mandates. +* **Independence:** French Cameroon gained independence in 1960 as the Republic of Cameroon. In 1961, part of British Southern Cameroons joined to form the Federal Republic of Cameroon. The system later shifted to a unitary state in 1972. +* **Modern era:** Cameroon has faced political challenges, including governance under President Paul Biya since 1982, and ongoing Anglophone crises in the Northwest and Southwest regions. + +## 3. Politics and Governance + +* **System:** Unitary presidential republic. +* **President:** Head of state and government, commander-in-chief, with extensive executive powers. +* **Parliament:** Bicameral, consisting of the National Assembly and Senate. +* **Judiciary:** Formally independent but influenced by the executive branch. +* **Challenges:** Limited political pluralism, concerns about democracy, human rights issues, and regional conflicts. + +## 4. Economy + +Cameroon has a mixed economy with agriculture, oil, and services as major contributors. + +* **Agriculture:** Cocoa, coffee, bananas, cotton, maize, cassava, palm oil. +* **Natural resources:** Oil, gas, timber, bauxite, iron ore. +* **Industry and services:** Douala port is the main economic hub; Yaoundé houses administration and diplomatic services. +* **Currency:** Central African CFA franc (XAF). +* **Economic challenges:** Poverty, corruption, limited infrastructure, and dependence on oil revenue. +* **Opportunities:** Expanding digital economy, agriculture modernization, tourism potential. + +## 5. Demographics + +* **Population:** Over 27 million people. +* **Languages:** Official languages are French and English, reflecting colonial history. Over 250 local languages are spoken (e.g., Ewondo, Fulfulde, Duala). +* **Ethnic groups:** Diverse, including Bantu groups, Semi-Bantu, Sudanese groups, Fulani, and Pygmy communities. +* **Religion:** Christianity (Roman Catholic and Protestant), Islam, and indigenous beliefs. + +## 6. Culture + +Cameroon is culturally rich and diverse. + +* **Music:** Makossa, Bikutsi, Njang, and modern Afropop. +* **Cuisine:** Ndolé (vegetable stew with peanuts and fish or beef), Achu soup, roasted fish with plantains, puff-puff. +* **Festivals:** Ngondo festival (Douala), cultural dances, and traditional ceremonies. +* **Sports:** Football is the most popular sport. The men’s national team, the Indomitable Lions, has won multiple Africa Cup of Nations and performed strongly in FIFA World Cups. + +## 7. Education and Health + +* **Education system:** Primary, secondary, and tertiary education structured under Francophone and Anglophone subsystems. Universities in Yaoundé, Buea, Douala, Bamenda, and others serve as higher learning centers. +* **Health challenges:** Malaria, HIV/AIDS, maternal and child health issues. Recent improvements include vaccination campaigns and private healthcare initiatives. + +## 8. Regional and International Relations + +* **Membership:** United Nations, African Union, Commonwealth of Nations, Organisation Internationale de la Francophonie, and Central African Economic and Monetary Community (CEMAC). +* **Regional influence:** Cameroon plays a key role in Central Africa but faces tensions with Nigeria over the Bakassi Peninsula (settled by ICJ ruling in 2002). + +## 9. Current Issues + +* Political unrest and demands for decentralization or federalism in Anglophone regions. +* Economic diversification efforts to reduce dependence on oil. +* Youth unemployment and brain drain. +* Climate change impacts on agriculture and Lake Chad basin. + +--- + diff --git a/Naive RAG system/document_loader.py b/Naive RAG system/document_loader.py new file mode 100644 index 0000000..8b43c1b --- /dev/null +++ b/Naive RAG system/document_loader.py @@ -0,0 +1,36 @@ +import os +from langchain_community.document_loaders import TextLoader, PyPDFLoader +from langchain.text_splitter import CharacterTextSplitter + +def load_documents_from_folder(folder_path: str = "data"): + """Load all PDF and TXT files from the data folder""" + all_docs = [] + + if not os.path.exists(folder_path): + os.makedirs(folder_path) + return all_docs + + for filename in os.listdir(folder_path): + file_path = os.path.join(folder_path, filename) + + try: + if filename.endswith('.pdf'): + loader = PyPDFLoader(file_path) + documents = loader.load() + elif filename.endswith('.txt'): + loader = TextLoader(file_path, encoding='utf-8') + documents = loader.load() + else: + continue + + all_docs.extend(documents) + except Exception as e: + print(f"Error loading {filename}: {e}") + continue + + # Split into chunks + text_splitter = CharacterTextSplitter( + chunk_size=300, # Smaller to avoid the warning + chunk_overlap=30 + ) + return text_splitter.split_documents(all_docs) \ No newline at end of file diff --git a/Naive RAG system/rag.py b/Naive RAG system/rag.py index 2d3b150..1347a5f 100644 --- a/Naive RAG system/rag.py +++ b/Naive RAG system/rag.py @@ -1,38 +1,54 @@ -from langchain.vectorstores import Chroma -from langchain.embeddings import HuggingFaceEmbeddings +from langchain_community.vectorstores import Chroma +from langchain_community.embeddings import HuggingFaceEmbeddings +from langchain_community.llms import HuggingFacePipeline +from transformers import pipeline as hf_pipeline +from document_loader import load_documents_from_folder from langchain.text_splitter import CharacterTextSplitter from langchain.schema import Document -# 1. Initialize embedding model +# Initialize embedding model embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") -# 2. Create your knowledge base (simple example) -documents = [ - "Paul Biya has been the president of Cameroon since 1982.", - "FastAPI is a modern Python web framework for building APIs.", - "The capital of France is Paris." -] +# Initialize LLM for answer generation +llm_pipeline = hf_pipeline( + "text-generation", + model="distilgpt2", + max_new_tokens=100, + temperature=0.3 +) +llm = HuggingFacePipeline(pipeline=llm_pipeline) -# 3. Split documents into chunks -text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0) -docs = [Document(page_content=text) for text in documents] -texts = text_splitter.split_documents(docs) - -# 4. Create vector store -vector_store = Chroma.from_documents(texts, embeddings) +def initialize_rag(): + """Load documents and create vector store""" + documents = load_documents_from_folder("data") + + if not documents: + # Fallback to simple examples + documents = [Document(page_content="No documents found in /data folder.")] + + vector_store = Chroma.from_documents(documents, embeddings) + return vector_store.as_retriever() -# 5. Create retriever -retriever = vector_store.as_retriever() +# Initialize when app starts +retriever = initialize_rag() def rag_query(question: str): - # 6. Retrieve relevant documents - relevant_docs = retriever.get_relevant_documents(question) + # Use invoke() instead of get_relevant_documents() + relevant_docs = retriever.invoke(question) + context = "\n\n".join([doc.page_content for doc in relevant_docs[:3]]) - # 7. Simple RAG: use the first relevant doc as context - context = relevant_docs[0].page_content if relevant_docs else "No relevant information found." + prompt = f"""Answer based only on this context: + +Context: +{context} + +Question: {question} + +Answer:""" + answer = llm.invoke(prompt) return { "question": question, - "context": context, - "answer": f"Based on the context: {context}" # In next step, we'll use an LLM here + "contexts": [doc.page_content for doc in relevant_docs[:2]], + "answer": answer } \ No newline at end of file From fae1ce20902dbfe9df24a691cdfd2fdde30839c4 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 08:37:36 +0100 Subject: [PATCH 17/33] Added done.txt file --- done.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 done.txt diff --git a/done.txt b/done.txt new file mode 100644 index 0000000..4e20c54 --- /dev/null +++ b/done.txt @@ -0,0 +1,3 @@ +Exercise 1 done +Exercise 2 done +Exercise 3 done \ No newline at end of file From 3c6df3f6ffb1916faa195ce031dc8e3104936b18 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 08:57:41 +0100 Subject: [PATCH 18/33] added the challenge I faced --- .../__pycache__/rag.cpython-313.pyc | Bin 2179 -> 2324 bytes Naive RAG system/rag.py | 3 ++- done.txt | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Naive RAG system/__pycache__/rag.cpython-313.pyc b/Naive RAG system/__pycache__/rag.cpython-313.pyc index 8b238aa2e53454ca33d678cd5b8567b72a33ac10..2f691c97242197be5ee0a195c4d7ccf285b56c82 100644 GIT binary patch delta 283 zcmZn`oFc^cnU|M~0SHQ`Ue6F`-^k~}TAvtNoT}jO=M$+=l98&AmY~N!FDy+hF3HT#(^GKCSIEmRQ78rKPRy%R$Oq~!QpnEBFV9I$ zNl&%n;&O%1b?B~OLq z#5|BaX_z+YoSLGLpO;e!BoslFa-(D}^e~$%<@0d6+~wK5(=1aW}Yq5t^*VZpR_X eAnnEY^OMZx9QK)v{KAZEGnl_J0I4D=pxppeNhhlS diff --git a/Naive RAG system/rag.py b/Naive RAG system/rag.py index 1347a5f..1e56e51 100644 --- a/Naive RAG system/rag.py +++ b/Naive RAG system/rag.py @@ -37,12 +37,13 @@ def rag_query(question: str): relevant_docs = retriever.invoke(question) context = "\n\n".join([doc.page_content for doc in relevant_docs[:3]]) - prompt = f"""Answer based only on this context: + prompt = f"""Use ONLY the following context to answer the question. Do not use any other knowledge: Context: {context} Question: {question} +If the answer is not in the context, say "I cannot find the answer in the provided documents Answer:""" diff --git a/done.txt b/done.txt index 4e20c54..e6f2412 100644 --- a/done.txt +++ b/done.txt @@ -1,3 +1,7 @@ Exercise 1 done Exercise 2 done -Exercise 3 done \ No newline at end of file +Exercise 3 done +Exercise 4 completed + +Challenges +Model size to large to download \ No newline at end of file From 6437823178415376133dcd7d938ce7e109a3893d Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 09:23:16 +0100 Subject: [PATCH 19/33] Initial commit --- FAISS+LangChain/data/cameroon.txt | 74 +++++++++++++++++++++++++++++++ FAISS+LangChain/faisse_rag.py | 51 +++++++++++++++++++++ FAISS+LangChain/main.py | 5 +++ 3 files changed, 130 insertions(+) create mode 100644 FAISS+LangChain/data/cameroon.txt create mode 100644 FAISS+LangChain/faisse_rag.py create mode 100644 FAISS+LangChain/main.py diff --git a/FAISS+LangChain/data/cameroon.txt b/FAISS+LangChain/data/cameroon.txt new file mode 100644 index 0000000..cf0d934 --- /dev/null +++ b/FAISS+LangChain/data/cameroon.txt @@ -0,0 +1,74 @@ + + +# Cameroon – Comprehensive Overview + +## 1. Geography and Location + +Cameroon is a country in Central Africa, often called "Africa in miniature" because of its geological, linguistic, and cultural diversity. It shares borders with Nigeria to the west, Chad to the northeast, the Central African Republic to the east, and Equatorial Guinea, Gabon, and the Republic of the Congo to the south. It has a coastline along the Atlantic Ocean (Gulf of Guinea). + +* **Capital city:** Yaoundé +* **Largest city and economic hub:** Douala +* **Climate:** Ranges from equatorial in the south, tropical in the center, to semi-arid in the north. +* **Notable landmarks:** Mount Cameroon (the highest peak in West and Central Africa), Lake Nyos, and Waza National Park. + +## 2. History + +* **Pre-colonial era:** Inhabited by diverse ethnic groups, kingdoms, and chiefdoms such as the Bamileke, Bamoun, and Fulani emirates. +* **Colonial period:** First colonized by Germany in 1884 (Kamerun). After World War I, the territory was divided between France and Britain under League of Nations mandates. +* **Independence:** French Cameroon gained independence in 1960 as the Republic of Cameroon. In 1961, part of British Southern Cameroons joined to form the Federal Republic of Cameroon. The system later shifted to a unitary state in 1972. +* **Modern era:** Cameroon has faced political challenges, including governance under President Paul Biya since 1982, and ongoing Anglophone crises in the Northwest and Southwest regions. + +## 3. Politics and Governance + +* **System:** Unitary presidential republic. +* **President:** Head of state and government, commander-in-chief, with extensive executive powers. +* **Parliament:** Bicameral, consisting of the National Assembly and Senate. +* **Judiciary:** Formally independent but influenced by the executive branch. +* **Challenges:** Limited political pluralism, concerns about democracy, human rights issues, and regional conflicts. + +## 4. Economy + +Cameroon has a mixed economy with agriculture, oil, and services as major contributors. + +* **Agriculture:** Cocoa, coffee, bananas, cotton, maize, cassava, palm oil. +* **Natural resources:** Oil, gas, timber, bauxite, iron ore. +* **Industry and services:** Douala port is the main economic hub; Yaoundé houses administration and diplomatic services. +* **Currency:** Central African CFA franc (XAF). +* **Economic challenges:** Poverty, corruption, limited infrastructure, and dependence on oil revenue. +* **Opportunities:** Expanding digital economy, agriculture modernization, tourism potential. + +## 5. Demographics + +* **Population:** Over 27 million people. +* **Languages:** Official languages are French and English, reflecting colonial history. Over 250 local languages are spoken (e.g., Ewondo, Fulfulde, Duala). +* **Ethnic groups:** Diverse, including Bantu groups, Semi-Bantu, Sudanese groups, Fulani, and Pygmy communities. +* **Religion:** Christianity (Roman Catholic and Protestant), Islam, and indigenous beliefs. + +## 6. Culture + +Cameroon is culturally rich and diverse. + +* **Music:** Makossa, Bikutsi, Njang, and modern Afropop. +* **Cuisine:** Ndolé (vegetable stew with peanuts and fish or beef), Achu soup, roasted fish with plantains, puff-puff. +* **Festivals:** Ngondo festival (Douala), cultural dances, and traditional ceremonies. +* **Sports:** Football is the most popular sport. The men’s national team, the Indomitable Lions, has won multiple Africa Cup of Nations and performed strongly in FIFA World Cups. + +## 7. Education and Health + +* **Education system:** Primary, secondary, and tertiary education structured under Francophone and Anglophone subsystems. Universities in Yaoundé, Buea, Douala, Bamenda, and others serve as higher learning centers. +* **Health challenges:** Malaria, HIV/AIDS, maternal and child health issues. Recent improvements include vaccination campaigns and private healthcare initiatives. + +## 8. Regional and International Relations + +* **Membership:** United Nations, African Union, Commonwealth of Nations, Organisation Internationale de la Francophonie, and Central African Economic and Monetary Community (CEMAC). +* **Regional influence:** Cameroon plays a key role in Central Africa but faces tensions with Nigeria over the Bakassi Peninsula (settled by ICJ ruling in 2002). + +## 9. Current Issues + +* Political unrest and demands for decentralization or federalism in Anglophone regions. +* Economic diversification efforts to reduce dependence on oil. +* Youth unemployment and brain drain. +* Climate change impacts on agriculture and Lake Chad basin. + +--- + diff --git a/FAISS+LangChain/faisse_rag.py b/FAISS+LangChain/faisse_rag.py new file mode 100644 index 0000000..4ac1715 --- /dev/null +++ b/FAISS+LangChain/faisse_rag.py @@ -0,0 +1,51 @@ +from langchain_community.vectorstores import FAISS +from langchain_community.embeddings import HuggingFaceEmbeddings +from langchain_community.llms import HuggingFacePipeline +from transformers import pipeline as hf_pipeline +from document_loader import load_documents_from_folder +from langchain.schema import Document + +# Same embedding model +embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") + +# Same LLM +llm_pipeline = hf_pipeline( + "text-generation", + model="distilgpt2", + max_new_tokens=50, + temperature=0.1 +) +llm = HuggingFacePipeline(pipeline=llm_pipeline) + +def initialize_faiss_rag(): + """Initialize FAISS vector store""" + documents = load_documents_from_folder("data") + + if not documents: + documents = [Document(page_content="Add documents to /data folder")] + + # Key difference: FAISS instead of Chroma + vector_store = FAISS.from_documents(documents, embeddings) + + # Save FAISS index to disk (optional) + vector_store.save_local("faiss_index") + return vector_store.as_retriever() + +# Initialize FAISS +faiss_retriever = initialize_faiss_rag() + +def rag_faiss_query(question: str): + """FAISS version of RAG query""" + relevant_docs = faiss_retriever.invoke(question) + context = "\n".join([doc.page_content for doc in relevant_docs[:2]]) + + # Simple prompt for the small model + prompt = f"Based on this: {context}\nQuestion: {question}\nAnswer:" + + answer = llm.invoke(prompt) + return { + "question": question, + "database": "FAISS", + "contexts": [doc.page_content[:100] + "..." for doc in relevant_docs[:2]], + "answer": answer + } \ No newline at end of file diff --git a/FAISS+LangChain/main.py b/FAISS+LangChain/main.py new file mode 100644 index 0000000..e72c556 --- /dev/null +++ b/FAISS+LangChain/main.py @@ -0,0 +1,5 @@ +from faiss_rag import rag_faiss_query + +@app.post("/rag-faiss-query") +def query_faiss_rag(request: QueryRequest): + return rag_faiss_query(request.question) \ No newline at end of file From 9c340e316e47f59f9b478f3481585d21bd016dca Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 10:14:45 +0100 Subject: [PATCH 20/33] updated the cameroon.txt --- .../document_loader.cpython-313.pyc | Bin 0 -> 2332 bytes .../__pycache__/faiss_rag.cpython-313.pyc | Bin 0 -> 2223 bytes .../__pycache__/main.cpython-313.pyc | Bin 0 -> 933 bytes FAISS+LangChain/data/cameroon.txt | 1 - FAISS+LangChain/document_loader.py | 45 ++++++++++++++++++ FAISS+LangChain/faiss_index/index.faiss | Bin 0 -> 27693 bytes FAISS+LangChain/faiss_index/index.pkl | Bin 0 -> 6630 bytes .../{faisse_rag.py => faiss_rag.py} | 0 FAISS+LangChain/main.py | 8 ++++ 9 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 FAISS+LangChain/__pycache__/document_loader.cpython-313.pyc create mode 100644 FAISS+LangChain/__pycache__/faiss_rag.cpython-313.pyc create mode 100644 FAISS+LangChain/__pycache__/main.cpython-313.pyc create mode 100644 FAISS+LangChain/document_loader.py create mode 100644 FAISS+LangChain/faiss_index/index.faiss create mode 100644 FAISS+LangChain/faiss_index/index.pkl rename FAISS+LangChain/{faisse_rag.py => faiss_rag.py} (100%) diff --git a/FAISS+LangChain/__pycache__/document_loader.cpython-313.pyc b/FAISS+LangChain/__pycache__/document_loader.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbc86c28bfd5223c6e2c38cdb852f88acd415121 GIT binary patch literal 2332 zcma)7O-vg{6rNqL?KS?x#3YbECWH`7f@vUWAZ?=%{xKwo#Zs!cau<7zH`u$*>^gvZ z$&vJuq*4{C9_m}kt;e2QMd}eND4;EAQ#F?yDiIMyQG4kd+iM%zN*&2N@4b2Rz2AA> zb-U{jtUvOb$qgGqzf;CsmNKzB0>qa{Kmrp&gzjvJnP3S!VIdYwc}s|!uo7#L=0dg! zJFx?87pxKfJS*4^qg&i9hB)S#0RM`DUJI~B-K?~vPpV>EB8GE%d3tE1!~__laWE+o zF{Vp|>Ij*XtOE@P{E!;UrX@u;oC!4rH=`L*PsW(CqjclpM;+gN$5N-ek;2@h^5U8S z+5RK?Y5p6VH?E4Rc*B(!J*g&Y@^JSAC>6@lRzI?T2O)s zG~~MJYrTFQo?aj7jfw&<=z`4lBi2@++8CL;(>S^ zYie35!lUZho?$}ZW(phvInJ?{ z@U>juw3todtMamllcI*_BuOc{lp&HP$Ki=%HGv1kv_w=@!J4eZBz&&FuO|pLTp4j* zipEq$2ff?}Bci4cOpjw(!y-v`A!7=naGIc`Pl7=}ZbTRvtha?hqj}rF`n@o}>ljvoJkg z9fzvYITuT2m4&D#=On{jqSZSRNr{<2y}_!Q!OT~-xB#}uLS&G2e;ibgB$ z2Y6zqavnN_O2IIVMS)Zq4oVd#t6`(?FrXckiv|N>=wK>ZM1;Al@c@L&%g78~ii9~sd7i_A-kL_}S_BXtePT{NIBh*lzZWNESMc2?48 z09s^ZU|bN+Op3}p{3pmt#PlOtax9oxHV#v=8d;QfceK>hq!nDFNzg{2B6raXukY^I zOQ-w(#d{a;U%q#F^~|QTz2I!$=Iib|KX*O|ZSZ)TcdvV{Z14kH-a{+im;Qr~Ccc`S&+{odsX#cJs;n`1kfg^OZe%ztuOraQW|Fzju9g ze8bhg?eaYsT^(D!wBFGE%ys(pG1PeWZ98)L-`J45alJKCaDB4v@~^i>3$9O##9+ZS zv}5P|bu0XvI^^)Idj>c7Ay9AZ{7(3ZE%-xsr?#9;o6e4cvtzC4sk3LD>v{L41=Tn2 zBG%DJEnds_+xO#ta`TyFn!s(wH9cVvT22Kt)us?RR!1qZ*-EhD4 z$x+|%dFzw&R-oaLa&(LY>WBxljkXk2Fh(l~&o-UTDzd&D+*eDj*v6%{K2*^U?&-Bs zGuKy7wOCS0i^WDaESgS=6@QF&!6+gpsA>K~7zx>wbeVJl3vGZjI;VFm48#149KWKm X=cxZVI`x`6&GfDfzD2N+0BHOThm$S} literal 0 HcmV?d00001 diff --git a/FAISS+LangChain/__pycache__/faiss_rag.cpython-313.pyc b/FAISS+LangChain/__pycache__/faiss_rag.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75814c077e3f63f0b0784fbb966bddb5ac4e99af GIT binary patch literal 2223 zcmZuyO>7fa5Ps|ZiR1soHq8%|RY(Xfp5)niGxNr?GvE96 z$nW-?-RBNEZpg;{B) zjks-HoNb@+5Ra`(v)&mW@yRI3_aUWCabM$zKj{X&UGXSh#i#hM2_%pd`%p5V2;dDW zfgVIc$xt5}ZInVflwh*+vP%i|php4;XFFn@`^*>Ps5m)sS5ZKTPOoLNnx36h)A)=0 zL!8OL#so+BBgcYPz&TCFV0IT;dQZ+!GpUS`Udvq^SBhW@P-x7VjUCJ(hQw?GMZ^=xop82*&l&|vp;;# z)^Fo6o{IKC8px{~DIKq;EaNfOP3pC9zQE3}5u9!`zkng&S?? zI$A>K8s-d)c$vl9OK~auHSPkZqh*%IUW+jL|F1sCu zo8#~m)GSV=4c&rSQSXYXnPy7UGk7D`Mi_bttDmq}rvZDC&1}?zo5-LZQ!V0D&Pb~{ z>Ql`W!4}bQ5k~H!?X4redW|W&Mw2x}mg%G0W632G6Eiuzki3J<$Cgn@PGMbEHTj`o zSaMp;7v#^94it(wKB2|eHET7lLEWUN;q~}8YZ$;`=w{Mx#_*h~XK$~nnx3q`6H&8? z!V?++yfwO(YC1>{6cT}-xd5V!-i3y?uT(=L<-31-BY#9s?F`RUqO&`Zx$oNlkx-<2 zH$3sU2>qda#YA+cju=&cC7oAYmlp_=!TU2lKI+h6sb-4V_nK~6;7PJ!tr z)WFP|Ys2t7SOJDC)Lx5CusIe4U~&MWa|*X8wmgou#4%_JD2%>znXU`SbcNA$03oCA zICw6&=0ga1kqmLVtC^cuge5+J6mbcGlrD+7&;s$Xbv1#j!x^RR*eamC$5#Ory9Hpd zIJ^W@bfQ(!lBjqRLO)bjuW;ofE#@utIH)Hk%w0BCs)yy%u*9150bVu@=~b)G+D67 z88~G!E|Kj;x>=SWptk{6`~Apyunw@upFsd%BWHFaLzT$T_SI_Sa(TWM=zOL<)n0u4 zYUI^KWpuLIHT7n6ayz}-9edjy14E^2sv4LsPXTm8r#II(wXJVoOura=`PGhpsyzA5 zAA0uS>4QzF>OWnc{4;X07U`{x&%IuJtyabts*(F|#ur}lyU~G4bYLs9W$r|WxAEKP zC2&?E_iLS9hwY+IIzXZ*eR%Ij-P7EM_nj!Z$eE1xwxhRv?%#)dZ*{ou#UfPB!A(uG zn+i0P&#%G#e3GcsM4ct-<=yG8H~oHUZL5Gikz1uj0H~r$ojV)Cb9%=gAWue1m)rHbw?!8pHw5aoipn*+Vz?(A7P3aSvVDLj#8r3Y^(V+^qN~${yH+ zdTTq#-wQr&@bFU<9;|krD+dpR04Hsx|3&by Gi}(+307Di4 literal 0 HcmV?d00001 diff --git a/FAISS+LangChain/__pycache__/main.cpython-313.pyc b/FAISS+LangChain/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..634e1f060e90fc6487c0e93514ab2b1a1b15c9e6 GIT binary patch literal 933 zcmZ8f-Afcv6hHH|v%6}hWr%AsL?VlB5hPJWV1}ipn1fGU7_RGeo!Xt5&K;HQ$qMqd z7r~bvdhEY3d@u%lh@N~i#y_BQXJ;ikFz258``z;~=bW^!uM8w#znyGNXaK*}r7Ko$ zq#wyR02f?s5f(Jm9A)c^`htN*W*dvRS;TE{&2)Gurri~7aHY=#ws;R)$*C5t6I{Jyy0zfUrO)Yw!k()_8gb-%*s5O zrKenqrEo(u>*{@1^8AoGgd6|^)LcN_)zBCRW-`mwCx~$kEHuojmGr(+p;rZEknx#K zR8q`rKMcOZa@9_Xo)_?z@Vun#d983`yQ%D6kBZ{Woay(xO&?|4^aBxuL>n^3gisy? zVa#I+CJ7z#JgIJVkH<0k>)Wv)7}ac2`XCXrkJy?NDA|h@_DsmPaTu}ZB5=6xtcPLj z)Ojm%?y-gl1X7?KQJe8=yMDY?^MhF6jxTm=-SQ=yo0)gr$(KB6%x-Z%U@cO2qBg4E z%#<>uQv2}p%E0F(9PBdhuimBh*RuAjh}ceS>~yJ~PmrDhsD7(2og#GruP?bZSk(#o zPrB2;O#@!8>Zn|?M5?OcbvmT-ckmkNq(4iWZvYj8Hwaa|l0&5S;GzJ%mBR-omB}BK z$>W}>BXcUNf4N#tN}at?UMfXmZ_?uM$VXG%icx!m2Q&v%%byrLin4YjW)#xkRGw@o zopxl!6d!j+{{%;gRaMG4Qs;)IX{RuL3YAkB`(^fgn%^@nOidg7^6&!aI4^*1?GJw# aJ}QqMYd6n{svWYFs9I`)KK4feS)RWdzuU$D literal 0 HcmV?d00001 diff --git a/FAISS+LangChain/data/cameroon.txt b/FAISS+LangChain/data/cameroon.txt index cf0d934..04fc73f 100644 --- a/FAISS+LangChain/data/cameroon.txt +++ b/FAISS+LangChain/data/cameroon.txt @@ -70,5 +70,4 @@ Cameroon is culturally rich and diverse. * Youth unemployment and brain drain. * Climate change impacts on agriculture and Lake Chad basin. ---- diff --git a/FAISS+LangChain/document_loader.py b/FAISS+LangChain/document_loader.py new file mode 100644 index 0000000..67380e0 --- /dev/null +++ b/FAISS+LangChain/document_loader.py @@ -0,0 +1,45 @@ +import os +from langchain_community.document_loaders import TextLoader, PyPDFLoader +from langchain.text_splitter import CharacterTextSplitter +from langchain.schema import Document + +def load_documents_from_folder(folder_path: str = "data"): + """Load all PDF and TXT files from the data folder""" + all_docs = [] + + if not os.path.exists(folder_path): + os.makedirs(folder_path) + print("Created /data folder. Add some PDF or TXT files.") + return all_docs + + for filename in os.listdir(folder_path): + file_path = os.path.join(folder_path, filename) + + try: + if filename.endswith('.pdf'): + loader = PyPDFLoader(file_path) + documents = loader.load() + elif filename.endswith('.txt'): + loader = TextLoader(file_path, encoding='utf-8') + documents = loader.load() + else: + continue + + all_docs.extend(documents) + print(f"Loaded {filename}") + except Exception as e: + print(f"Error loading {filename}: {e}") + continue + + if not all_docs: + # Fallback examples + all_docs = [ + Document(page_content="Paul Biya has been the president of Cameroon since 1982."), + Document(page_content="FastAPI is a modern Python web framework for building APIs."), + Document(page_content="The capital of France is Paris.") + ] + print("Using example documents (add files to /data folder)") + + # Split into chunks + text_splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=30) + return text_splitter.split_documents(all_docs) \ No newline at end of file diff --git a/FAISS+LangChain/faiss_index/index.faiss b/FAISS+LangChain/faiss_index/index.faiss new file mode 100644 index 0000000000000000000000000000000000000000..8e1de5137f303ce945e607377a5978c7b112b8f7 GIT binary patch literal 27693 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 literal 0 HcmV?d00001 diff --git a/FAISS+LangChain/faisse_rag.py b/FAISS+LangChain/faiss_rag.py similarity index 100% rename from FAISS+LangChain/faisse_rag.py rename to FAISS+LangChain/faiss_rag.py diff --git a/FAISS+LangChain/main.py b/FAISS+LangChain/main.py index e72c556..5269795 100644 --- a/FAISS+LangChain/main.py +++ b/FAISS+LangChain/main.py @@ -1,5 +1,13 @@ from faiss_rag import rag_faiss_query +from fastapi import FastAPI +from pydantic import BaseModel + +app=FastAPI() + +class QueryRequest(BaseModel): + question: str @app.post("/rag-faiss-query") + def query_faiss_rag(request: QueryRequest): return rag_faiss_query(request.question) \ No newline at end of file From 9d869a9ab9159dba49152af4b4a6563941cf4de1 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sat, 27 Sep 2025 10:15:02 +0100 Subject: [PATCH 21/33] updated the dont.txt file --- done.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/done.txt b/done.txt index e6f2412..1271652 100644 --- a/done.txt +++ b/done.txt @@ -2,6 +2,9 @@ Exercise 1 done Exercise 2 done Exercise 3 done Exercise 4 completed +exercise 5 done +exercise 6 done Challenges -Model size to large to download \ No newline at end of file +Models size to large to download +Model capability is limited to generate better responses \ No newline at end of file From 2f28abdf1e6ccfee8d79133dadccdec7ca38a9d8 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Wed, 1 Oct 2025 14:47:34 +0100 Subject: [PATCH 22/33] edited folder name for numerical order --- .../__pycache__/main.cpython-313.pyc | Bin {hello-llm => 1-hello-llm}/main.py | 0 .../__pycache__/main.cpython-313.pyc | Bin .../main.py | 0 .../__pycache__/main.cpython-313.pyc | Bin .../main.py | 0 .../main.py | 0 .../__pycache__/doc_loader.cpython-313.pyc | Bin .../__pycache__/document_loader.cpython-313.pyc | Bin .../__pycache__/main.cpython-313.pyc | Bin .../__pycache__/rag.cpython-313.pyc | Bin .../data/cameroon.txt | 0 .../document_loader.py | 0 {Naive RAG system => 5-Naive RAG system}/main.py | 0 {Naive RAG system => 5-Naive RAG system}/rag.py | 0 .../__pycache__/document_loader.cpython-313.pyc | Bin .../__pycache__/faiss_rag.cpython-313.pyc | Bin .../__pycache__/main.cpython-313.pyc | Bin .../data/cameroon.txt | 0 .../document_loader.py | 0 .../faiss_index/index.faiss | Bin .../faiss_index/index.pkl | Bin {FAISS+LangChain => 6-FAISS+LangChain}/faiss_rag.py | 0 {FAISS+LangChain => 6-FAISS+LangChain}/main.py | 0 24 files changed, 0 insertions(+), 0 deletions(-) rename {hello-llm => 1-hello-llm}/__pycache__/main.cpython-313.pyc (100%) rename {hello-llm => 1-hello-llm}/main.py (100%) rename {Text Summarizer API => 2-Text Summarizer API}/__pycache__/main.cpython-313.pyc (100%) rename {Text Summarizer API => 2-Text Summarizer API}/main.py (100%) rename {Sentiment Analysis API => 3-Sentiment Analysis API}/__pycache__/main.cpython-313.pyc (100%) rename {Sentiment Analysis API => 3-Sentiment Analysis API}/main.py (100%) rename {Multimodal image captioning API => 4-Multimodal image captioning API}/main.py (100%) rename {Naive RAG system => 5-Naive RAG system}/__pycache__/doc_loader.cpython-313.pyc (100%) rename {Naive RAG system => 5-Naive RAG system}/__pycache__/document_loader.cpython-313.pyc (100%) rename {Naive RAG system => 5-Naive RAG system}/__pycache__/main.cpython-313.pyc (100%) rename {Naive RAG system => 5-Naive RAG system}/__pycache__/rag.cpython-313.pyc (100%) rename {Naive RAG system => 5-Naive RAG system}/data/cameroon.txt (100%) rename {Naive RAG system => 5-Naive RAG system}/document_loader.py (100%) rename {Naive RAG system => 5-Naive RAG system}/main.py (100%) rename {Naive RAG system => 5-Naive RAG system}/rag.py (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/__pycache__/document_loader.cpython-313.pyc (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/__pycache__/faiss_rag.cpython-313.pyc (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/__pycache__/main.cpython-313.pyc (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/data/cameroon.txt (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/document_loader.py (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/faiss_index/index.faiss (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/faiss_index/index.pkl (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/faiss_rag.py (100%) rename {FAISS+LangChain => 6-FAISS+LangChain}/main.py (100%) diff --git a/hello-llm/__pycache__/main.cpython-313.pyc b/1-hello-llm/__pycache__/main.cpython-313.pyc similarity index 100% rename from hello-llm/__pycache__/main.cpython-313.pyc rename to 1-hello-llm/__pycache__/main.cpython-313.pyc diff --git a/hello-llm/main.py b/1-hello-llm/main.py similarity index 100% rename from hello-llm/main.py rename to 1-hello-llm/main.py diff --git a/Text Summarizer API/__pycache__/main.cpython-313.pyc b/2-Text Summarizer API/__pycache__/main.cpython-313.pyc similarity index 100% rename from Text Summarizer API/__pycache__/main.cpython-313.pyc rename to 2-Text Summarizer API/__pycache__/main.cpython-313.pyc diff --git a/Text Summarizer API/main.py b/2-Text Summarizer API/main.py similarity index 100% rename from Text Summarizer API/main.py rename to 2-Text Summarizer API/main.py diff --git a/Sentiment Analysis API/__pycache__/main.cpython-313.pyc b/3-Sentiment Analysis API/__pycache__/main.cpython-313.pyc similarity index 100% rename from Sentiment Analysis API/__pycache__/main.cpython-313.pyc rename to 3-Sentiment Analysis API/__pycache__/main.cpython-313.pyc diff --git a/Sentiment Analysis API/main.py b/3-Sentiment Analysis API/main.py similarity index 100% rename from Sentiment Analysis API/main.py rename to 3-Sentiment Analysis API/main.py diff --git a/Multimodal image captioning API/main.py b/4-Multimodal image captioning API/main.py similarity index 100% rename from Multimodal image captioning API/main.py rename to 4-Multimodal image captioning API/main.py diff --git a/Naive RAG system/__pycache__/doc_loader.cpython-313.pyc b/5-Naive RAG system/__pycache__/doc_loader.cpython-313.pyc similarity index 100% rename from Naive RAG system/__pycache__/doc_loader.cpython-313.pyc rename to 5-Naive RAG system/__pycache__/doc_loader.cpython-313.pyc diff --git a/Naive RAG system/__pycache__/document_loader.cpython-313.pyc b/5-Naive RAG system/__pycache__/document_loader.cpython-313.pyc similarity index 100% rename from Naive RAG system/__pycache__/document_loader.cpython-313.pyc rename to 5-Naive RAG system/__pycache__/document_loader.cpython-313.pyc diff --git a/Naive RAG system/__pycache__/main.cpython-313.pyc b/5-Naive RAG system/__pycache__/main.cpython-313.pyc similarity index 100% rename from Naive RAG system/__pycache__/main.cpython-313.pyc rename to 5-Naive RAG system/__pycache__/main.cpython-313.pyc diff --git a/Naive RAG system/__pycache__/rag.cpython-313.pyc b/5-Naive RAG system/__pycache__/rag.cpython-313.pyc similarity index 100% rename from Naive RAG system/__pycache__/rag.cpython-313.pyc rename to 5-Naive RAG system/__pycache__/rag.cpython-313.pyc diff --git a/Naive RAG system/data/cameroon.txt b/5-Naive RAG system/data/cameroon.txt similarity index 100% rename from Naive RAG system/data/cameroon.txt rename to 5-Naive RAG system/data/cameroon.txt diff --git a/Naive RAG system/document_loader.py b/5-Naive RAG system/document_loader.py similarity index 100% rename from Naive RAG system/document_loader.py rename to 5-Naive RAG system/document_loader.py diff --git a/Naive RAG system/main.py b/5-Naive RAG system/main.py similarity index 100% rename from Naive RAG system/main.py rename to 5-Naive RAG system/main.py diff --git a/Naive RAG system/rag.py b/5-Naive RAG system/rag.py similarity index 100% rename from Naive RAG system/rag.py rename to 5-Naive RAG system/rag.py diff --git a/FAISS+LangChain/__pycache__/document_loader.cpython-313.pyc b/6-FAISS+LangChain/__pycache__/document_loader.cpython-313.pyc similarity index 100% rename from FAISS+LangChain/__pycache__/document_loader.cpython-313.pyc rename to 6-FAISS+LangChain/__pycache__/document_loader.cpython-313.pyc diff --git a/FAISS+LangChain/__pycache__/faiss_rag.cpython-313.pyc b/6-FAISS+LangChain/__pycache__/faiss_rag.cpython-313.pyc similarity index 100% rename from FAISS+LangChain/__pycache__/faiss_rag.cpython-313.pyc rename to 6-FAISS+LangChain/__pycache__/faiss_rag.cpython-313.pyc diff --git a/FAISS+LangChain/__pycache__/main.cpython-313.pyc b/6-FAISS+LangChain/__pycache__/main.cpython-313.pyc similarity index 100% rename from FAISS+LangChain/__pycache__/main.cpython-313.pyc rename to 6-FAISS+LangChain/__pycache__/main.cpython-313.pyc diff --git a/FAISS+LangChain/data/cameroon.txt b/6-FAISS+LangChain/data/cameroon.txt similarity index 100% rename from FAISS+LangChain/data/cameroon.txt rename to 6-FAISS+LangChain/data/cameroon.txt diff --git a/FAISS+LangChain/document_loader.py b/6-FAISS+LangChain/document_loader.py similarity index 100% rename from FAISS+LangChain/document_loader.py rename to 6-FAISS+LangChain/document_loader.py diff --git a/FAISS+LangChain/faiss_index/index.faiss b/6-FAISS+LangChain/faiss_index/index.faiss similarity index 100% rename from FAISS+LangChain/faiss_index/index.faiss rename to 6-FAISS+LangChain/faiss_index/index.faiss diff --git a/FAISS+LangChain/faiss_index/index.pkl b/6-FAISS+LangChain/faiss_index/index.pkl similarity index 100% rename from FAISS+LangChain/faiss_index/index.pkl rename to 6-FAISS+LangChain/faiss_index/index.pkl diff --git a/FAISS+LangChain/faiss_rag.py b/6-FAISS+LangChain/faiss_rag.py similarity index 100% rename from FAISS+LangChain/faiss_rag.py rename to 6-FAISS+LangChain/faiss_rag.py diff --git a/FAISS+LangChain/main.py b/6-FAISS+LangChain/main.py similarity index 100% rename from FAISS+LangChain/main.py rename to 6-FAISS+LangChain/main.py From 4ab64a49b0d2dc88130f95face132368d53dd557 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Wed, 1 Oct 2025 15:01:51 +0100 Subject: [PATCH 23/33] Added function to Read the image and generate content --- 7-Geminivision+text/.env | 1 + 7-Geminivision+text/multimodal_qa.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 7-Geminivision+text/.env create mode 100644 7-Geminivision+text/multimodal_qa.py diff --git a/7-Geminivision+text/.env b/7-Geminivision+text/.env new file mode 100644 index 0000000..ace8e91 --- /dev/null +++ b/7-Geminivision+text/.env @@ -0,0 +1 @@ +GOOGLE_API_KEY=AIzaSyD5YYcbIviamb9w9y3xBX2eoQ8A-TtqTLI \ No newline at end of file diff --git a/7-Geminivision+text/multimodal_qa.py b/7-Geminivision+text/multimodal_qa.py new file mode 100644 index 0000000..d885f7b --- /dev/null +++ b/7-Geminivision+text/multimodal_qa.py @@ -0,0 +1,20 @@ +import google.generativeai as genai +import os +from dotenv import load_dotenv +from fastapi import UploadFile, File +from PIL import Image +import io + +load_dotenv() + +# Configure Gemini +genai.configure(api_key=os.getenv('GOOGLE_API_KEY')) +model = genai.GenerativeModel('gemini-2.5-flash') + +def analyze_image_with_question(image: Image.Image, question : str): + """Use Gemini to answer questions about images""" + try: + response = model.generate_content([question, image]) + return response.text + except Exception as e: + return f"Error: {str(e)}" \ No newline at end of file From cd357063c90f145085f40a1732ccd27c40721bb3 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Wed, 1 Oct 2025 15:03:36 +0100 Subject: [PATCH 24/33] Imported function to analyse --- 7-Geminivision+text/main.py | 1 + 7-Geminivision+text/multimodal_qa.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 7-Geminivision+text/main.py diff --git a/7-Geminivision+text/main.py b/7-Geminivision+text/main.py new file mode 100644 index 0000000..05b00a2 --- /dev/null +++ b/7-Geminivision+text/main.py @@ -0,0 +1 @@ +from multimodal_qa import analyze_image_with_question \ No newline at end of file diff --git a/7-Geminivision+text/multimodal_qa.py b/7-Geminivision+text/multimodal_qa.py index d885f7b..ae14591 100644 --- a/7-Geminivision+text/multimodal_qa.py +++ b/7-Geminivision+text/multimodal_qa.py @@ -17,4 +17,6 @@ def analyze_image_with_question(image: Image.Image, question : str): response = model.generate_content([question, image]) return response.text except Exception as e: - return f"Error: {str(e)}" \ No newline at end of file + return f"Error: {str(e)}" + + \ No newline at end of file From c90e189874ed7cb62fe160f6b7ed13233cb2f603 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Wed, 1 Oct 2025 15:48:07 +0100 Subject: [PATCH 25/33] Google Vision works well --- 1-hello-llm/interview_qa.txt | 14 +++++++++++ 2-Text Summarizer API/interview_qa.txt | 13 ++++++++++ 3-Sentiment Analysis API/interview_qa.txt | 13 ++++++++++ .../interview_qa.txt | 13 ++++++++++ 5-Naive RAG system/interview_qa.txt | 13 ++++++++++ 6-FAISS+LangChain/interview_qa.txt | 19 +++++++++++++++ .../__pycache__/main.cpython-313.pyc | Bin 0 -> 1076 bytes .../__pycache__/multimodal_qa.cpython-313.pyc | Bin 0 -> 1157 bytes 7-Geminivision+text/interview_qa.txt | 13 ++++++++++ 7-Geminivision+text/main.py | 23 +++++++++++++++++- 7-Geminivision+text/multimodal_qa.py | 4 +-- 11 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 1-hello-llm/interview_qa.txt create mode 100644 2-Text Summarizer API/interview_qa.txt create mode 100644 3-Sentiment Analysis API/interview_qa.txt create mode 100644 4-Multimodal image captioning API/interview_qa.txt create mode 100644 5-Naive RAG system/interview_qa.txt create mode 100644 6-FAISS+LangChain/interview_qa.txt create mode 100644 7-Geminivision+text/__pycache__/main.cpython-313.pyc create mode 100644 7-Geminivision+text/__pycache__/multimodal_qa.cpython-313.pyc create mode 100644 7-Geminivision+text/interview_qa.txt diff --git a/1-hello-llm/interview_qa.txt b/1-hello-llm/interview_qa.txt new file mode 100644 index 0000000..26071ac --- /dev/null +++ b/1-hello-llm/interview_qa.txt @@ -0,0 +1,14 @@ +1-What is a language model? A program that predicts the next most likely word (token) in a sequence. + +2-GPT-2 vs GPT-3/4? GPT-3/4 are much larger, trained on more data, and smarter. distilgpt2 is a simplified GPT-2. + +3-Why is distilgpt2 lightweight? It's a "distilled" version—a smaller model trained to imitate the bigger one. Fewer parameters = faster, less memory. + +4-What are tokens? Words or pieces of words the model understands. The model thinks in tokens, not full words. + +5-Prompt length limits? Models have a max token limit. We use max_length to control the output. If the prompt is too long, you must shorten it. + +6-API vs CLI? An API lets other programs (like a website or app) use your model easily. A CLI is just for you on your computer. + +7-Risk without moderation? The model might generate bad, biased, or private information from its training data. You need filters. + diff --git a/2-Text Summarizer API/interview_qa.txt b/2-Text Summarizer API/interview_qa.txt new file mode 100644 index 0000000..8a5f42d --- /dev/null +++ b/2-Text Summarizer API/interview_qa.txt @@ -0,0 +1,13 @@ +1-Abstractive vs Extractive? Extractive copies important sentences. Abstractive writes new sentences to capture the meaning (like a human). BART is abstractive. + +2- Why is BART good for this? It's an encoder-decoder model trained to reconstruct corrupted text, which is perfect for tasks like summarization. + +3- Encoder-Decoder? The encoder reads and understands the input text. The decoder uses that understanding to write a new sequence (the summary). + +4- Beam Search? A search strategy that keeps several likely options open instead of just picking the next best word. Can lead to better, more coherent summaries. + +5- Hallucinations? When the model generates information that isn't in the source text. A major risk in summarization. Leads to inaccuracy + +6- ROUGE/BLEU? Metrics to compare a machine-generated summary to a human-written one. They measure overlap of words and phrases. + +7- Fine-tuning on legal docs? You would collect a dataset of legal documents and their human-written summaries, then continue training the model on this specific data. \ No newline at end of file diff --git a/3-Sentiment Analysis API/interview_qa.txt b/3-Sentiment Analysis API/interview_qa.txt new file mode 100644 index 0000000..b0e7ac9 --- /dev/null +++ b/3-Sentiment Analysis API/interview_qa.txt @@ -0,0 +1,13 @@ +1- Transfer Learning? Training a model on a general task (like language understanding) then fine-tuning it for a specific task (like sentiment). Much faster than training from scratch. + +2- DistilBERT vs BERT? DistilBERT is 40% smaller but retains 97% of BERT's performance. Faster and cheaper to run. + +3-SST-2? A standard benchmark dataset of movie reviews labeled as positive or negative. + +4-Embeddings? Numbers that represent the meaning of words. The model converts your text into embeddings to understand it. + +5-Evaluation? Accuracy, precision, recall, F1-score. For sentiment: how often is it correct? + +6-Biases? If trained mostly on movie reviews, it might perform poorly on technical texts or miss cultural context. + +7- Sarcasm? Very hard for models. Requires deep context understanding. Often needs additional context or specialized training. \ No newline at end of file diff --git a/4-Multimodal image captioning API/interview_qa.txt b/4-Multimodal image captioning API/interview_qa.txt new file mode 100644 index 0000000..34d9d27 --- /dev/null +++ b/4-Multimodal image captioning API/interview_qa.txt @@ -0,0 +1,13 @@ +1- How does ViT process images? It splits images into patches (like puzzle pieces) and processes them like a language model processes words. + +2- GPT-2's role? It takes the image understanding from ViT and generates a coherent sentence description. + +3- Why combine vision + language? ViT understands what's in the image, GPT-2 knows how to describe it naturally. + +4- Captioning datasets? COCO - contains images with multiple human-written captions. + +5- Challenges? Handling fine details, counting objects accurately, understanding abstract concepts. + +6- Evaluation metrics? BLEU (word overlap), CIDEr (considers human-like relevance). + +7- Real-world apps? Accessibility (describing images for visually impaired), social media auto-alt-text, surveillance systems. \ No newline at end of file diff --git a/5-Naive RAG system/interview_qa.txt b/5-Naive RAG system/interview_qa.txt new file mode 100644 index 0000000..18be470 --- /dev/null +++ b/5-Naive RAG system/interview_qa.txt @@ -0,0 +1,13 @@ +1- What is RAG? Giving models access to up-to-date, specific information they weren't trained on. + +2- Embeddings? Numbers that capture meaning. Similar texts have similar number patterns. + +3- Why Chroma? Lightweight, simple vector database perfect for learning and prototyping. + +4- Cosine similarity? Measures how similar two vectors are. Used to find the most relevant documents. + +5- Update knowledge? Add new documents to the vector store. The retriever will automatically include them. + +6- Risk of irrelevant docs? The model might use wrong information. Need good retrieval filtering. + +7- RAG vs fine-tuning? RAG adds knowledge without retraining. Fine-tuning teaches new skills/styles. \ No newline at end of file diff --git a/6-FAISS+LangChain/interview_qa.txt b/6-FAISS+LangChain/interview_qa.txt new file mode 100644 index 0000000..a7633a5 --- /dev/null +++ b/6-FAISS+LangChain/interview_qa.txt @@ -0,0 +1,19 @@ +1- What is FAISS? Facebook's AI Similarity Search - a library for fast vector search, especially with large datasets. + +2- Why fast? Uses optimized C++ code and advanced indexing algorithms that pre-organize vectors for quick searching. + +3- Indexing methods: + +IVF (Inverted File Index): Groups similar vectors into buckets + +HNSW (Hierarchical Navigable Small World): Creates a network for efficient navigation + +4- Billions of vectors? Uses compression and distributed search across multiple machines. + +5- FAISS vs Chroma: FAISS is faster for large datasets, Chroma is easier for prototyping with built-in storage. + +6- ANN search: Approximate Nearest Neighbor - finds "good enough" matches much faster than exact search. + +7- Evaluation: Use metrics like recall@k (how often the true match is in top k results). + +8- Production deployment: Run as a separate service, use GPU acceleration, and implement caching. \ No newline at end of file diff --git a/7-Geminivision+text/__pycache__/main.cpython-313.pyc b/7-Geminivision+text/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b10ec8b21a70ba308fe91137d28965e3eea67e3 GIT binary patch literal 1076 zcmZuv&2Jk;6o0cbyZ(r`km7*V25FUWz@QBvHHtt$<$k2tMkdP22q`N?Lo-RH*t?tA zO@htEvG{)OEGEYMP9{` zCJ6BH49t(|M8PjCPmP^dHqV?#C$3Lsz_T*%0`hYHgqQct3&bm&gB#=qI^`;DkZSRT zPOBn$o(8nj>$6qfr5kK@mnWO6TiYy7cozoii|wcr(lw1$u36VP zt^S!0wy2xty9xU~nUnd9L6UV9dR?h>YNkTB)HnJ~EwkV#mD*@|+{I~>0$IIvrQ9Y4 z*g+3*%Pc`)teo;KlUFlN@C>YEQ-J0C|J}EZOs8xQ@XACM`OSy(WB!1&p-nvG8FTm@ z$V2Pm0$xW|-0IucSeFOf`I^V6PD1}jS~Q4vnUH2TTw|T8C5d2kP2}_)2_qIrgNHJA zsh6<0{*_QYLDfuCMM1|DPiC-26DrLV3td&LC3Cb%e)$u>9WxR8Uo81oSo~cQM*cMx zIFvizhGF7dr`^c;$lqWA6ExvF%&l=(57p&C!o&_|yKXj|*k5o@`q)X^cwZ0C?@}Jj zMLlV6(eazm$D*ui&_%{AwY-1<92cQ7z1O?jyZ^(VlQVlg=x%MbxmH1sQ0+~! zR|5sBwzRw3orEhbX=indrgF*Lx_XZ^;zAEzXkmmNw!};IFH@n#YpF}4NRlXw6N%$Q zq}BflBXtGh4IPmGRPk+;2y%%Qz$%z@?VyHix2P- xB0p7rto&X)w~x*bE!F?y%lCUjvxKaJGn2HFyoy8!e{xU*+s^(Ux7%W`AT)3Ebar?ge6>X8<56r*jcN?S356>M@PvFdr;cyi zGAYAn>H#Q|jJkGsj#I19A!UVu<@$VuGAkm(E%#c`2(1oBz81?f7O=C{rHn50TChl~ z0tez#=7!W+2z(r4D728?3Pn7BYk}6~K!nOemeE)Y`(q|5VKU0=fzPQRluL>hieO)y zwXqq-?F+N^dCG5uLESD;-*P?cS`dWRf?KOw$L#GNddoDM^Rg>mxRmwq&urPFE7_gK z?Niwk`l|TI_1)^~8g)7Z9a+qYN-%jb6Zr8ws=LtA zG(G()HT)u#`7@Pydb)Y&(~Z=*ug%TmzHje*bEj#3{NJno-EAOxdUMzCkE!*qe%QNi zHj`t2nPYETDu&1y%Ngn~i5yXXBk283bkvzak*WkirAjAy99>Tg{154f zFsKAv7~PA@(i}ayVII4yw={#Ke`-9r{qyY>p!+NTR~j~g#oqxVm>E|9 literal 0 HcmV?d00001 diff --git a/7-Geminivision+text/interview_qa.txt b/7-Geminivision+text/interview_qa.txt new file mode 100644 index 0000000..ced8cda --- /dev/null +++ b/7-Geminivision+text/interview_qa.txt @@ -0,0 +1,13 @@ +1-What is VQA? Visual Question Answering - asking questions about images and getting text answers. + +2-BLIP-2 vision+text alignment? Uses a visual encoder to understand images, then a language model to generate answers. + +3-Frozen LLM role? The language model is pre-trained and not updated during vision training - it just learns to use visual inputs. + +4-Beneficial tasks? Medical imaging, autonomous vehicles, accessibility, e-commerce, content moderation. + +5-Challenges? Aligning different data types, handling ambiguous images, computational complexity. + +6-Evaluation? Accuracy on benchmark datasets, human evaluation, task-specific metrics. + +7-Industries needing it? Healthcare, retail, automotive, security, social media, education. \ No newline at end of file diff --git a/7-Geminivision+text/main.py b/7-Geminivision+text/main.py index 05b00a2..7ad6a7a 100644 --- a/7-Geminivision+text/main.py +++ b/7-Geminivision+text/main.py @@ -1 +1,22 @@ -from multimodal_qa import analyze_image_with_question \ No newline at end of file +from multimodal_qa import analyze_image_with_question +from fastapi import FastAPI, File, UploadFile +from PIL import Image +import io +import multimodal_qa + +app = FastAPI() + +@app.post("/qa-image-text") +async def qa_image_text( + question: str, + file: UploadFile = File(...) +): + image_data = await file.read() + image = Image.open(io.BytesIO(image_data)) + + answer = analyze_image_with_question(image, question) + return{ + "question": question, + "answer": answer, + "model": "Gemini Vision" + } \ No newline at end of file diff --git a/7-Geminivision+text/multimodal_qa.py b/7-Geminivision+text/multimodal_qa.py index ae14591..ef9f367 100644 --- a/7-Geminivision+text/multimodal_qa.py +++ b/7-Geminivision+text/multimodal_qa.py @@ -1,9 +1,8 @@ import google.generativeai as genai import os from dotenv import load_dotenv -from fastapi import UploadFile, File from PIL import Image -import io + load_dotenv() @@ -19,4 +18,3 @@ def analyze_image_with_question(image: Image.Image, question : str): except Exception as e: return f"Error: {str(e)}" - \ No newline at end of file From 7b27450be8d41bc926468643c3ad68dd42589bb4 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Wed, 1 Oct 2025 15:52:32 +0100 Subject: [PATCH 26/33] Done with exercise 7 --- done.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/done.txt b/done.txt index 1271652..e458d59 100644 --- a/done.txt +++ b/done.txt @@ -4,6 +4,7 @@ Exercise 3 done Exercise 4 completed exercise 5 done exercise 6 done +exercise 7 done with Google Vision Challenges Models size to large to download From 6a5fd043d1fcb193e9f2a396ff365654cf045b5c Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Thu, 2 Oct 2025 08:58:08 +0100 Subject: [PATCH 27/33] Created Chain --- .../interview_qa.txt | 13 ++++++ .../research_chain.py | 44 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 8-ChainMultiple Tools in Langchain/interview_qa.txt create mode 100644 8-ChainMultiple Tools in Langchain/research_chain.py diff --git a/8-ChainMultiple Tools in Langchain/interview_qa.txt b/8-ChainMultiple Tools in Langchain/interview_qa.txt new file mode 100644 index 0000000..4b1c5e6 --- /dev/null +++ b/8-ChainMultiple Tools in Langchain/interview_qa.txt @@ -0,0 +1,13 @@ +1- Tool chaining? Connecting multiple AI tools so output from one becomes input to the next. + +2- Why combine tools? Creates more powerful applications than any single tool alone. + +3- Challenges? Error handling, latency, data format mismatches, cost management. + +4- Orchestration vs composition? Orchestration = smart workflow management; Composition = simple tool connections. + +5- Handle failures? Implement retries, fallbacks, and circuit breakers. + +6- What is LangChain? A framework that makes it easier to chain AI components together. + +7- Monitor latency? Track time for each step, set timeouts, use monitoring tools. \ No newline at end of file diff --git a/8-ChainMultiple Tools in Langchain/research_chain.py b/8-ChainMultiple Tools in Langchain/research_chain.py new file mode 100644 index 0000000..6f89012 --- /dev/null +++ b/8-ChainMultiple Tools in Langchain/research_chain.py @@ -0,0 +1,44 @@ +from langchain_community.utilities import WikipediaAPIWrapper +from langchain.chains import LLMChain, sequential +from langchain.prompts import PromptTemplate +from langchain_community.llms import huggingface_pipeline +from transformers import pipeline +import re + +# Initialize components + +wiki = WikipediaAPIWrapper() + +# LLM for sumarization and sentiment +llm_pipeline = pipeline( + "text-generation", + model = "google/flan-t5-small", # better for instructions than distilgpt2 + max_length=200 +) +llm = huggingface_pipeline(pipeline=llm_pipeline) + +# Step 2: Wikipedia Research + +research_prompt = PromptTemplate( + input_variable = ["topic"], + template = " Research this topic and provide the key facts: {topic}" +) + +# Step 2: Summarization +summary_prompt = PromptTemplate( + input_variables=["research"], + template="Summarize this in 3 bullet points: {research}" +) + +# Step 3: Sentiment Analysis +sentiment_prompt = PromptTemplate( + inpute_variable=['summary'], + template="Analyze the sentiment of this text (positive/negative/neutral):{summary}" +) + +# Create the Chain +research_chain = LLMChain(llm=llm, prompt =research_prompt, output_key ="research") + +summary_chain = LLMChain(llm=llm, prompt= summary_prompt, output_key="summary") + +sentiment_chain = LLMChain(llm=llm, prompt = sentiment_prompt, output_key="sentiment") \ No newline at end of file From 9916eab82db4de000f7b984601e606c5d908b3d9 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Thu, 2 Oct 2025 11:37:08 +0100 Subject: [PATCH 28/33] Yoo --- .../__pycache__/main.cpython-313.pyc | Bin 0 -> 950 bytes .../research_chain.cpython-313.pyc | Bin 0 -> 2304 bytes 8-ChainMultiple Tools in Langchain/main.py | 12 ++++ .../research_chain.py | 63 ++++++++++++------ 4 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 8-ChainMultiple Tools in Langchain/__pycache__/main.cpython-313.pyc create mode 100644 8-ChainMultiple Tools in Langchain/__pycache__/research_chain.cpython-313.pyc create mode 100644 8-ChainMultiple Tools in Langchain/main.py diff --git a/8-ChainMultiple Tools in Langchain/__pycache__/main.cpython-313.pyc b/8-ChainMultiple Tools in Langchain/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..282b28c4def56faf12ae8ecf576819720ac4afd4 GIT binary patch literal 950 zcmZ8g-Afcv6hC)9c6L`Sv=7!bVvs^c-6BY+sKD$~Q_RVy28MC>x;wQyGoCxE89i7* z_SlQyztDeE_)rWOM7{WCtbah~&hChG;GTQt_q+F=&*=;d6oF*q&drLD{L^V0u3@eOqhM=guyseDQoAr3PHt(i zcjUxo=cdTN6x(o&>x!K(!%OY>twOzE6%QnBvE&qT!9A=t+&GNSb^=N4J$RVr&(2b}O zOg}K6dO^J^DW^s1O0Ee09W$lDK zumykmhIhxlm&d=A$M^aszG@R`=nGcy#2}?fr+yM+m1fC{eAMLg`DnA|1=JdpzeA#W zQIwV=(V~!gDP5&~>XsvoD1W;<4R`SZu`*QgfYhPN7~2PHA4c}!;;-Dm2Y*XF(ij{1 neDersJIsNiZ7fK6rS~Z9cSa;*ddS~GK93?f|C>oGz3a5XiI(-SX?S)rD$=+&cb@von42- z6{^Ld>XEiWje5$FsvJ1>7;YRLMU~7*X(d`!<(4Q^LhYq*Hfx7=B+tJ0=Dly`{dzYX zmJzITW4|nJv?BByXBsQu5xcK}c!(6F2$N_+paSN!Z_+m*QgOmh{Vp#~N)rJZaB2T! z%S4a{U0RxKosg-Fkt+0~5f75Ksd7J30!oV#R9Z(x8d8J(NDV2{s6fMN0M6tgL1|M$ zqdppO`7rPimyf!96!@6S$5at)!)incD{;Vzdwf)hx_rCG$CP%LPpE#-kE`u!Vo2oo z3?U_PO;D0xn^a`A6={Gdq5hYNZmPDIW_? zO-)~3)O3?Y74lh`n2xR)t^jNzv(ze|f4C3IDrJF8fL;D_Uv0e3*%6P`q zj1||4V4H`l2phKY-V?!be7t1Yx}z_VA(Ip!04`B>sAi<#ogUJ?l*mNGD6#-J13_l8 zRd)Eh!6(+*L{5n`3Spu#z9o6UL>9>LgxNF65)~B>`HTcT>%bR0R8bC+TT%%D@3(~p}GDW}-&p|uyt*qEUilEcJVZrwGLF<`f zMjY_Ic_EK3ihU?Aq#~7zZt>z~wc|z-@d>;adcEQnCFh&@(|A^G-LCY_SQv_R;SB(< z1OcaPI7}jxTC{>e?>~3InT_*S8LBgHQGARE$7l#Vn9=`)K(p4S@_s7IZ^3y}j$eHF z4c@OxmutK)CAnBE+Hhvxw#qa|_OY0phvJ=gE29#>-sqdWrW<78JWff>e-{P-6KUC` zJ#a5;{ct%)O1wRpXgf6J-@78j)#h`S>A>YI;CU?&+Yd$<7Q27>yqdKMwbiS$>J?(& zfzDGuCMMQ&e9N*NoYRUW{I1&Q|0R;n=;^zVSrq?bzSXyC`rpRr3$|E@pKl^*ws%YDvkk0+y+5O$}*UM|t zw_kh}`Xkz1>-%7RYO`;)o&@sJy7bfCb*??P(8+pNW~VI>lebZzRet>{hC&^?NRZCe zW1Y3`laG}r@gF~VbhUP9q!vBG16?yL-!9o>M*LTt*Lm&KYogKlJO%9BKSf3f)f+1`M$ zDQ`5EZpz=lg*jvoF7AzXn5SgEG0$lWw+X@QGHod9B4nMy1VFUcm4n^BYMhJqE7Tin z5pUkjdwi_fbPdUVE?p;BxM8u!M)wU|fm^*4^GEQk|A2O3M|1!-7Q6ueC1r!WPtO3$ zN143|8w6hvw$R02(b+9@atlpwp(8s16ztw?>8bjGiXE)`yXrEoN85K={4rlOv?HUI zuC)srf#IqM3W+22j-ChO^>AiK5)-~^bSH$`alNDO!Bjnb0c7pIY6N7-{(8sZ2b1;i zryxuEYAD7PyH<0LhSqOy#IIE&&tnHyl}Cry$2Vd#)$nsTvuh{Dp0#bX-vHDAiuBe) kU8~cNF4fw`+&fvvD7-1+tIFG<4&mJD(Z3LU=xOllUty}JSO5S3 literal 0 HcmV?d00001 diff --git a/8-ChainMultiple Tools in Langchain/main.py b/8-ChainMultiple Tools in Langchain/main.py new file mode 100644 index 0000000..f4a04a1 --- /dev/null +++ b/8-ChainMultiple Tools in Langchain/main.py @@ -0,0 +1,12 @@ +from research_chain import research_topic +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + +class QueryRequest(BaseModel): + question: str + +@app.post("/researcher") +def research_endpoint(request: QueryRequest): + return research_topic(request.question) # FIXED: research_topic not research_endpoint \ No newline at end of file diff --git a/8-ChainMultiple Tools in Langchain/research_chain.py b/8-ChainMultiple Tools in Langchain/research_chain.py index 6f89012..433787c 100644 --- a/8-ChainMultiple Tools in Langchain/research_chain.py +++ b/8-ChainMultiple Tools in Langchain/research_chain.py @@ -1,30 +1,27 @@ from langchain_community.utilities import WikipediaAPIWrapper -from langchain.chains import LLMChain, sequential +from langchain.chains import LLMChain, SequentialChain from langchain.prompts import PromptTemplate -from langchain_community.llms import huggingface_pipeline +from langchain_community.llms.huggingface_pipeline import HuggingFacePipeline # FIXED IMPORT from transformers import pipeline -import re # Initialize components - wiki = WikipediaAPIWrapper() -# LLM for sumarization and sentiment +# LLM for summarization and sentiment - FIXED for T5 llm_pipeline = pipeline( - "text-generation", - model = "google/flan-t5-small", # better for instructions than distilgpt2 + "text2text-generation", # T5 models use text2text-generation + model="google/flan-t5-small", max_length=200 ) -llm = huggingface_pipeline(pipeline=llm_pipeline) - -# Step 2: Wikipedia Research +llm = HuggingFacePipeline(pipeline=llm_pipeline) # FIXED: Use the class, not module +# Step 1: Wikipedia Research research_prompt = PromptTemplate( - input_variable = ["topic"], - template = " Research this topic and provide the key facts: {topic}" + input_variables=["topic"], + template="Research this topic and provide key facts: {topic}" ) -# Step 2: Summarization +# Step 2: Summarization summary_prompt = PromptTemplate( input_variables=["research"], template="Summarize this in 3 bullet points: {research}" @@ -32,13 +29,41 @@ # Step 3: Sentiment Analysis sentiment_prompt = PromptTemplate( - inpute_variable=['summary'], - template="Analyze the sentiment of this text (positive/negative/neutral):{summary}" + input_variables=["summary"], + template="Analyze the sentiment of this text (positive/negative/neutral): {summary}" ) -# Create the Chain -research_chain = LLMChain(llm=llm, prompt =research_prompt, output_key ="research") +# Create the chains +research_chain = LLMChain(llm=llm, prompt=research_prompt, output_key="research") +summary_chain = LLMChain(llm=llm, prompt=summary_prompt, output_key="summary") +sentiment_chain = LLMChain(llm=llm, prompt=sentiment_prompt, output_key="sentiment") -summary_chain = LLMChain(llm=llm, prompt= summary_prompt, output_key="summary") +# Connect them sequentially +full_chain = SequentialChain( + chains=[research_chain, summary_chain, sentiment_chain], + input_variables=["topic"], + output_variables=["research", "summary", "sentiment"] +) -sentiment_chain = LLMChain(llm=llm, prompt = sentiment_prompt, output_key="sentiment") \ No newline at end of file +def research_topic(topic: str): + """Chain Wikipedia research + summarization + sentiment analysis""" + try: + # Get Wikipedia content first + wiki_content = wiki.run(topic) + + if not wiki_content or "No good Wikipedia search result" in wiki_content: + return {"error": f"No Wikipedia results found for '{topic}'"} + + # Run through the AI chain + result = full_chain({"topic": wiki_content[:1000]}) # Limit length + + return { + "topic": topic, + "research_source": "Wikipedia", + "summary": result["summary"], + "sentiment": result["sentiment"], + "full_chain": "Wikipedia → Summarize → Sentiment" + } + + except Exception as e: + return {"error": f"Research failed: {str(e)}"} \ No newline at end of file From e689f59a51dcf601fb3c3a0eb8757100dc95defd Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Thu, 2 Oct 2025 11:37:59 +0100 Subject: [PATCH 29/33] Exercise 9 done --- done.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/done.txt b/done.txt index e458d59..abd31aa 100644 --- a/done.txt +++ b/done.txt @@ -5,6 +5,7 @@ Exercise 4 completed exercise 5 done exercise 6 done exercise 7 done with Google Vision +exercise 8 done .. Challenges Models size to large to download From 5dfd513b2ec11fc95a21dc636eb02cd3ff89f2bf Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Sun, 5 Oct 2025 23:49:41 +0100 Subject: [PATCH 30/33] Answered interview questions --- 9- Intelligent Chat/interview_qa.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 9- Intelligent Chat/interview_qa.txt diff --git a/9- Intelligent Chat/interview_qa.txt b/9- Intelligent Chat/interview_qa.txt new file mode 100644 index 0000000..0020573 --- /dev/null +++ b/9- Intelligent Chat/interview_qa.txt @@ -0,0 +1,14 @@ +1- Model routing? Automatically sending queries to the right AI tool based on content. + +2- Intent detection? Using keyword matching, ML classifiers, or rule-based logic. + +3- RAG vs LLM decision? RAG for specific facts/knowledge, LLM for general conversation. + +4- Risks of routing? Wrong routing, cascading failures, increased latency. + +5- Logging & tracing? Track which route was chosen, response times, success rates. + +6- Evaluation metrics? Response accuracy, user satisfaction, routing accuracy, latency. + +7- Enterprise scaling? Load balancing, caching, circuit breakers, monitoring. + From c5dc64ae7b4954124def443bd348a99b8b5d760e Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Mon, 6 Oct 2025 00:04:58 +0100 Subject: [PATCH 31/33] Updated code with simple routing based on key words --- 9- Intelligent Chat/intelligent_chat.py | 20 +++++++ 9- Intelligent Chat/multimodal_qa.py | 20 +++++++ 9- Intelligent Chat/research_chain.py | 69 +++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 9- Intelligent Chat/intelligent_chat.py create mode 100644 9- Intelligent Chat/multimodal_qa.py create mode 100644 9- Intelligent Chat/research_chain.py diff --git a/9- Intelligent Chat/intelligent_chat.py b/9- Intelligent Chat/intelligent_chat.py new file mode 100644 index 0000000..3344e51 --- /dev/null +++ b/9- Intelligent Chat/intelligent_chat.py @@ -0,0 +1,20 @@ +from langchain.chains import RouterChain +from langchain.chains.llm import LLMChain +from langchain.prompts import PromptTemplate +from research_chain import research_topic +from multimodal_qa import analyze_image_with_question + +class IntelligentChat: + def __init__(self): + # Simple outing Logic - no complex langchain router needed for basic routing + self.image_keywords= ['image', 'picture', 'photo', 'analyze this', 'whatis in this'] + self.research_keywords = ['research', 'what is ', 'who is', 'explain', 'tell me about'] + + def route_query(self,query: str, has_image:bool=False) + """Simple but effective routing logic""" + + # Priority 1: Image queries + if has_image: + return "image_analysis" + # Prioroty 2: Research /Knowlwedge queries + query_lower=query.lower() \ No newline at end of file diff --git a/9- Intelligent Chat/multimodal_qa.py b/9- Intelligent Chat/multimodal_qa.py new file mode 100644 index 0000000..ef9f367 --- /dev/null +++ b/9- Intelligent Chat/multimodal_qa.py @@ -0,0 +1,20 @@ +import google.generativeai as genai +import os +from dotenv import load_dotenv +from PIL import Image + + +load_dotenv() + +# Configure Gemini +genai.configure(api_key=os.getenv('GOOGLE_API_KEY')) +model = genai.GenerativeModel('gemini-2.5-flash') + +def analyze_image_with_question(image: Image.Image, question : str): + """Use Gemini to answer questions about images""" + try: + response = model.generate_content([question, image]) + return response.text + except Exception as e: + return f"Error: {str(e)}" + diff --git a/9- Intelligent Chat/research_chain.py b/9- Intelligent Chat/research_chain.py new file mode 100644 index 0000000..433787c --- /dev/null +++ b/9- Intelligent Chat/research_chain.py @@ -0,0 +1,69 @@ +from langchain_community.utilities import WikipediaAPIWrapper +from langchain.chains import LLMChain, SequentialChain +from langchain.prompts import PromptTemplate +from langchain_community.llms.huggingface_pipeline import HuggingFacePipeline # FIXED IMPORT +from transformers import pipeline + +# Initialize components +wiki = WikipediaAPIWrapper() + +# LLM for summarization and sentiment - FIXED for T5 +llm_pipeline = pipeline( + "text2text-generation", # T5 models use text2text-generation + model="google/flan-t5-small", + max_length=200 +) +llm = HuggingFacePipeline(pipeline=llm_pipeline) # FIXED: Use the class, not module + +# Step 1: Wikipedia Research +research_prompt = PromptTemplate( + input_variables=["topic"], + template="Research this topic and provide key facts: {topic}" +) + +# Step 2: Summarization +summary_prompt = PromptTemplate( + input_variables=["research"], + template="Summarize this in 3 bullet points: {research}" +) + +# Step 3: Sentiment Analysis +sentiment_prompt = PromptTemplate( + input_variables=["summary"], + template="Analyze the sentiment of this text (positive/negative/neutral): {summary}" +) + +# Create the chains +research_chain = LLMChain(llm=llm, prompt=research_prompt, output_key="research") +summary_chain = LLMChain(llm=llm, prompt=summary_prompt, output_key="summary") +sentiment_chain = LLMChain(llm=llm, prompt=sentiment_prompt, output_key="sentiment") + +# Connect them sequentially +full_chain = SequentialChain( + chains=[research_chain, summary_chain, sentiment_chain], + input_variables=["topic"], + output_variables=["research", "summary", "sentiment"] +) + +def research_topic(topic: str): + """Chain Wikipedia research + summarization + sentiment analysis""" + try: + # Get Wikipedia content first + wiki_content = wiki.run(topic) + + if not wiki_content or "No good Wikipedia search result" in wiki_content: + return {"error": f"No Wikipedia results found for '{topic}'"} + + # Run through the AI chain + result = full_chain({"topic": wiki_content[:1000]}) # Limit length + + return { + "topic": topic, + "research_source": "Wikipedia", + "summary": result["summary"], + "sentiment": result["sentiment"], + "full_chain": "Wikipedia → Summarize → Sentiment" + } + + except Exception as e: + return {"error": f"Research failed: {str(e)}"} \ No newline at end of file From 736a940356172af79ab052ec0f9f05a87a6750d5 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Mon, 6 Oct 2025 01:17:23 +0100 Subject: [PATCH 32/33] Updated code with simple routing based on key words --- 9- Intelligent Chat/intelligent_chat.py | 80 ++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/9- Intelligent Chat/intelligent_chat.py b/9- Intelligent Chat/intelligent_chat.py index 3344e51..d4e63ac 100644 --- a/9- Intelligent Chat/intelligent_chat.py +++ b/9- Intelligent Chat/intelligent_chat.py @@ -10,11 +10,75 @@ def __init__(self): self.image_keywords= ['image', 'picture', 'photo', 'analyze this', 'whatis in this'] self.research_keywords = ['research', 'what is ', 'who is', 'explain', 'tell me about'] - def route_query(self,query: str, has_image:bool=False) - """Simple but effective routing logic""" - - # Priority 1: Image queries - if has_image: - return "image_analysis" - # Prioroty 2: Research /Knowlwedge queries - query_lower=query.lower() \ No newline at end of file + def route_query(self, query:str, has_image:bool=False): + """Simple but effective routing logic""" + + # Priority 1: Image queries + if has_image: + return "image_analysis" + # Prioroty 2: Research /Knowlwedge queries + query_lower=query.lower() + if any(keyword in query_lower for keyword in self.research_keywords): + return "research" + # Default: General LLM chat + return "general_chat" + + def handle_chat(self, query:str, image_data:dict=None): + """Main Chat handler with Router""" + + has_image = image_data is not None + route = self.route_query(query, has_image) + + if route == "image_analysis": + # Use your existing image analysis + image = image_data['image'] # PIL Image Object + answer = analyze_image_with_question(image, query) + return { + "query": query, + "route": "image_analysis", + "answer": answer, + "tool": "Gemini Vision" + } + elif route == "research": + # Use your research chain + + result = research_topic(query) + return { + "query": query, + "route": "research", + "answer": result.get("summary","Research failed"), + "sentiment": result.get('sentiment','unknown'), + "tool": "Wikipedia + Summarization" + } + + else: #General chat + # Use simple LLM for general conversation + from transformers import pipeline + chat_llm = pipeline('text-generation', model = 'distilgpt2', max_length=100) + + answer = chat_llm(query)[0]['generated_text'] + + return { + "query": query, + "route": "general_chat", + "answer": answer, + "tool": "DistilGPT2" + } + +# Initialize the intelligent chat system +chat_system = IntelligentChat() + +def intelligent_chat(query:str, image_file =None): + """Main function for the chat endpoint""" + image_data = None + if image_file: + from PIL import Image + import io + image = Image.open(io.BytesIO(image_file)) + image_data = { 'image': image} + + return chat_system.handle_chat(query, image_data) + + + + \ No newline at end of file From 4d44a83ed296dc277d46839fe4c57c3fbca590c0 Mon Sep 17 00:00:00 2001 From: Agentic-JJ-Web3 Date: Tue, 7 Oct 2025 01:16:28 +0100 Subject: [PATCH 33/33] Removed return element from __init__ --- .../intelligent_chat.cpython-313.pyc | Bin 0 -> 3419 bytes .../__pycache__/main.cpython-313.pyc | Bin 0 -> 785 bytes .../__pycache__/multimodal_qa.cpython-313.pyc | Bin 0 -> 1157 bytes .../research_chain.cpython-313.pyc | Bin 0 -> 2289 bytes 9- Intelligent Chat/intelligent_chat.py | 18 +++++++++--------- 9- Intelligent Chat/main.py | 15 +++++++++++++++ 6 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 9- Intelligent Chat/__pycache__/intelligent_chat.cpython-313.pyc create mode 100644 9- Intelligent Chat/__pycache__/main.cpython-313.pyc create mode 100644 9- Intelligent Chat/__pycache__/multimodal_qa.cpython-313.pyc create mode 100644 9- Intelligent Chat/__pycache__/research_chain.cpython-313.pyc create mode 100644 9- Intelligent Chat/main.py diff --git a/9- Intelligent Chat/__pycache__/intelligent_chat.cpython-313.pyc b/9- Intelligent Chat/__pycache__/intelligent_chat.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4b842c44c3d3a4b2d8029cb393bb35295089ee9 GIT binary patch literal 3419 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 bWBa+Y$5`2eZ2xZ^cQ6=zZ9{pYPgVO17%8w2 literal 0 HcmV?d00001 diff --git a/9- Intelligent Chat/__pycache__/multimodal_qa.cpython-313.pyc b/9- Intelligent Chat/__pycache__/multimodal_qa.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ec18768095d46139cb61b4e8214659ba2a965ca GIT binary patch literal 1157 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 literal 0 HcmV?d00001 diff --git a/9- Intelligent Chat/intelligent_chat.py b/9- Intelligent Chat/intelligent_chat.py index d4e63ac..790980e 100644 --- a/9- Intelligent Chat/intelligent_chat.py +++ b/9- Intelligent Chat/intelligent_chat.py @@ -10,16 +10,16 @@ def __init__(self): self.image_keywords= ['image', 'picture', 'photo', 'analyze this', 'whatis in this'] self.research_keywords = ['research', 'what is ', 'who is', 'explain', 'tell me about'] - def route_query(self, query:str, has_image:bool=False): - """Simple but effective routing logic""" + def route_query(self, query:str, has_image:bool=False): + """Simple but effective routing logic""" - # Priority 1: Image queries - if has_image: - return "image_analysis" - # Prioroty 2: Research /Knowlwedge queries - query_lower=query.lower() - if any(keyword in query_lower for keyword in self.research_keywords): - return "research" + # Priority 1: Image queries + if has_image: + return "image_analysis" + # Prioroty 2: Research /Knowlwedge queries + query_lower=query.lower() + if any(keyword in query_lower for keyword in self.research_keywords): + return "research" # Default: General LLM chat return "general_chat" diff --git a/9- Intelligent Chat/main.py b/9- Intelligent Chat/main.py new file mode 100644 index 0000000..f1571dc --- /dev/null +++ b/9- Intelligent Chat/main.py @@ -0,0 +1,15 @@ +from intelligent_chat import intelligent_chat +from fastapi import FastAPI, UploadFile,File + +app = FastAPI() + +@app.post('/chat') +async def chat_endpoint( + query: str, + file: UploadFile= File(None) # Optional imahe upload +): + image_data= None + if file: + image_data = await file.read() + + return intelligent_chat(query,image_data) \ No newline at end of file