ZDPLI commited on
Commit
656e743
Β·
verified Β·
1 Parent(s): c170d91

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +169 -0
app.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import torch
4
+ import gradio as gr
5
+ from tqdm import tqdm
6
+ from PIL import Image
7
+
8
+ # LangChain & LangGraph
9
+ from langgraph.graph import StateGraph
10
+ from langgraph.checkpoint.memory import MemorySaver
11
+ from langchain.tools import tool
12
+ from langchain_community.vectorstores import FAISS
13
+ from langchain_community.embeddings import HuggingFaceEmbeddings
14
+ from langchain_community.document_loaders import PyPDFLoader
15
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
16
+ from duckduckgo_search import DDGS
17
+ from llama_cpp import Llama
18
+
19
+ logging.basicConfig(level=logging.INFO)
20
+ logger = logging.getLogger(__name__)
21
+
22
+ # ------------------------------
23
+ # πŸ”Ή Load GGUF Model with llama-cpp-python
24
+ # ------------------------------
25
+ MODEL_PATH = "Bio-Medical-MultiModal-Llama-3-8B-V1.i1-Q4_0.gguf"
26
+
27
+ if not os.path.exists(MODEL_PATH):
28
+ raise FileNotFoundError(f"Model file {MODEL_PATH} not found. Upload it to the same directory.")
29
+
30
+ llm = Llama(
31
+ model_path=MODEL_PATH,
32
+ n_ctx=8192,
33
+ n_gpu_layers=0, # Set to 0 for CPU inference
34
+ logits_all=True,
35
+ n_batch=512
36
+ )
37
+
38
+ logger.info("Llama GGUF Model Loaded Successfully.")
39
+
40
+ # ------------------------------
41
+ # πŸ”Ή Multi-Specialty Prompt
42
+ # ------------------------------
43
+ UNIFIED_MEDICAL_PROMPT = """
44
+ You are an advanced Medical AI Assistant capable of providing thorough,
45
+ comprehensive answers for a wide range of medical specialties:
46
+ General Practice, Radiology, Cardiology, Neurology, Psychiatry, Pediatrics,
47
+ Endocrinology, Oncology, and more.
48
+
49
+ You can:
50
+ 1) Analyze images if provided (Radiology).
51
+ 2) Search the web for up-to-date medical info (Web Search).
52
+ 3) Retrieve relevant documents from a knowledge base (Vector Store).
53
+ 4) Provide scientific, evidence-based explanations and references when possible.
54
+
55
+ Always strive to provide a detailed, helpful, and empathetic response.
56
+ """
57
+
58
+ # ------------------------------
59
+ # πŸ”Ή FAISS Vector Store for RAG
60
+ # ------------------------------
61
+ _vector_store_cache = None
62
+
63
+ def load_vectorstore(pdf_path="medical_docs.pdf"):
64
+ try:
65
+ loader = PyPDFLoader(pdf_path)
66
+ documents = loader.load()
67
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=100)
68
+ docs = text_splitter.split_documents(documents)
69
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
70
+ vector_store = FAISS.from_documents(docs, embeddings)
71
+ logger.info(f"Vector store loaded with {len(docs)} documents.")
72
+ return vector_store
73
+ except Exception as e:
74
+ logger.error(f"Error loading vector store: {str(e)}")
75
+ return None
76
+
77
+ if os.path.exists("medical_docs.pdf"):
78
+ _vector_store_cache = load_vectorstore("medical_docs.pdf")
79
+
80
+ vector_store = _vector_store_cache
81
+
82
+ # ------------------------------
83
+ # πŸ”Ή Define AI Tools
84
+ # ------------------------------
85
+ @tool
86
+ def analyze_medical_image(image_path: str):
87
+ """Analyzes a medical image and returns a diagnostic explanation."""
88
+ try:
89
+ image = Image.open(image_path)
90
+ except Exception as e:
91
+ logger.error(f"Error opening image: {str(e)}")
92
+ return "Error processing image."
93
+ output = llm(f"Analyze this medical image for radiological findings:\n{image}", max_tokens=512)
94
+ return output["choices"][0]["text"]
95
+
96
+ @tool
97
+ def retrieve_medical_knowledge(query: str):
98
+ """Retrieves medical knowledge from FAISS vector store."""
99
+ if vector_store is None:
100
+ return "No external medical knowledge available."
101
+ retriever = vector_store.as_retriever(search_type="similarity", search_kwargs={"k": 5})
102
+ docs = retriever.get_relevant_documents(query)
103
+ citations = [f"[{i+1}] {doc.metadata.get('source', 'Unknown Source')}" for i, doc in enumerate(docs)]
104
+ content = "\n".join([doc.page_content for doc in docs])
105
+ citations_text = "\n".join(citations)
106
+ return content + f"\n\n**Citations:**\n{citations_text}"
107
+
108
+ @tool
109
+ def web_search(query: str):
110
+ """Performs a real-time web search using DuckDuckGo."""
111
+ try:
112
+ results = DDGS().text(query, max_results=5)
113
+ summary = "\n".join([f"{r['title']}: {r['body']} ({r['href']})" for r in results]) or "No relevant results found."
114
+ return summary
115
+ except Exception as e:
116
+ logger.error(f"Web search error: {str(e)}")
117
+ return "Error retrieving web search results."
118
+
119
+ # ------------------------------
120
+ # πŸ”Ή Multi-Context Chat Function
121
+ # ------------------------------
122
+ def chat_with_agent(user_query, image_file, pdf_file):
123
+ image_analysis = analyze_medical_image(image_file) if image_file else ""
124
+ rag_text = retrieve_medical_knowledge(user_query)
125
+ web_text = web_search(user_query)
126
+
127
+ combined_context = f"""
128
+ {UNIFIED_MEDICAL_PROMPT}
129
+
130
+ Additional Context:
131
+ - Radiology Analysis (if any): {image_analysis}
132
+ - Retrieved from Vector Store (RAG): {rag_text}
133
+ - Web Search Results: {web_text}
134
+
135
+ Now, respond to the user's query with detailed, medically accurate information.
136
+ Q: {user_query}
137
+ A:
138
+ """
139
+
140
+ response_accumulator = ""
141
+ for token in llm(
142
+ prompt=combined_context,
143
+ max_tokens=1024,
144
+ temperature=0.7,
145
+ top_p=0.9,
146
+ stream=True
147
+ ):
148
+ partial_text = token["choices"][0]["text"]
149
+ response_accumulator += partial_text
150
+ yield response_accumulator
151
+
152
+ # ------------------------------
153
+ # πŸ”Ή Gradio Interface
154
+ # ------------------------------
155
+ with gr.Blocks(title="πŸ₯ Llama3-Med AI Assistant") as demo:
156
+ gr.Markdown("# πŸ₯ Llama3-Med AI Assistant\n_Your intelligent medical assistant powered by advanced AI._")
157
+
158
+ with gr.Row():
159
+ user_input = gr.Textbox(label="πŸ’¬ Ask a medical question", placeholder="Type your question here...")
160
+ image_file = gr.Image(label="πŸ“· Upload Medical Image", type="filepath")
161
+ pdf_file = gr.File(label="πŸ“„ Upload PDF (Optional)", file_types=[".pdf"])
162
+
163
+ submit_btn = gr.Button("πŸš€ Submit", variant="primary")
164
+ output_text = gr.Textbox(label="πŸ“ Assistant's Response", interactive=False, lines=25)
165
+
166
+ submit_btn.click(fn=chat_with_agent, inputs=[user_input, image_file, pdf_file], outputs=output_text)
167
+
168
+ if __name__ == "__main__":
169
+ demo.queue().launch(server_name="0.0.0.0", server_port=7860)