drrobot9 commited on
Commit
6584be3
·
verified ·
1 Parent(s): 501a498

push updated backend changes and auto start buiding

Browse files
.env ADDED
File without changes
Dockerfile CHANGED
@@ -3,23 +3,30 @@ FROM python:3.10-slim
3
  # Install system dependencies
4
  RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
5
 
6
- # Set Hugging Face cache to a writable directory
7
- ENV HF_HOME=/app/.cache/huggingface
8
- ENV TRANSFORMERS_CACHE=/app/.cache/huggingface/transformers
9
- ENV HF_HUB_CACHE=/app/.cache/huggingface/hub
 
 
 
 
10
 
11
  # Set working directory
12
  WORKDIR /app
13
 
14
- # Copy project files
15
- COPY . /app
16
 
17
  # Install Python dependencies
18
  RUN pip install --no-cache-dir --upgrade pip \
19
  && pip install --no-cache-dir -r requirements.txt
20
 
 
 
 
21
  # Expose the port Hugging Face Spaces expects
22
  EXPOSE 7860
23
 
24
- # Run FastAPI with Uvicorn
25
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
3
  # Install system dependencies
4
  RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
5
 
6
+ # Set Hugging Face cache to a writable directory in /tmp
7
+ ENV HF_HOME=/tmp/huggingface
8
+ ENV TRANSFORMERS_CACHE=/tmp/huggingface
9
+ ENV HUGGINGFACE_HUB_CACHE=/tmp/huggingface
10
+ ENV HF_HUB_CACHE=/tmp/huggingface
11
+
12
+ # Create cache directory with proper permissions
13
+ RUN mkdir -p /tmp/huggingface && chmod 777 /tmp/huggingface
14
 
15
  # Set working directory
16
  WORKDIR /app
17
 
18
+ # Copy requirements first for better caching
19
+ COPY requirements.txt .
20
 
21
  # Install Python dependencies
22
  RUN pip install --no-cache-dir --upgrade pip \
23
  && pip install --no-cache-dir -r requirements.txt
24
 
25
+ # Copy project files
26
+ COPY . /app
27
+
28
  # Expose the port Hugging Face Spaces expects
29
  EXPOSE 7860
30
 
31
+ # Run FastAPI with Uvicorn (with reload disabled for production)
32
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
__pycache__/agents.cpython-312.pyc ADDED
Binary file (6.32 kB). View file
 
__pycache__/app.cpython-312.pyc ADDED
Binary file (1.49 kB). View file
 
__pycache__/config.cpython-312.pyc ADDED
Binary file (1.47 kB). View file
 
__pycache__/rag.cpython-312.pyc ADDED
Binary file (8.72 kB). View file
 
agents.py CHANGED
@@ -1,99 +1,195 @@
1
- # bioinformatics_ai/agents.py
2
  import torch
3
- from transformers import AutoModelForCausalLM, AutoTokenizer
4
- from autogen import AssistantAgent, UserProxyAgent
5
  from config import LLM_MODEL, CONFIDENCE_THRESHOLD, VECTORSTORE_DIR
6
- from rag import RAGAgent
7
  import os
8
  import sys
 
 
 
 
 
9
 
10
- # Ensure Hugging Face cache is in a writable directory (important on HF Spaces)
11
- if "HF_HOME" not in os.environ:
12
- hf_cache = "/home/user/.cache/huggingface"
13
- os.environ["HF_HOME"] = hf_cache
14
- os.environ["TRANSFORMERS_CACHE"] = os.path.join(hf_cache, "transformers")
15
- os.environ["HF_HUB_CACHE"] = os.path.join(hf_cache, "hub")
16
 
17
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
18
  if BASE_DIR not in sys.path:
19
  sys.path.insert(0, BASE_DIR)
20
 
21
-
22
  # Load BioMistral once
23
  class BioMistralModel:
24
  def __init__(self, model_name=LLM_MODEL, device=None):
25
- print(f"[BioMistralModel] Loading model: {model_name}")
26
  self.device = device or ("cuda" if torch.cuda.is_available() else "cpu")
27
- self.tokenizer = AutoTokenizer.from_pretrained(model_name)
28
- self.model = AutoModelForCausalLM.from_pretrained(
29
- model_name,
30
- torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
31
- device_map="auto"
32
- )
33
-
34
- def generate_answer(self, query: str) -> str:
35
- prompt = f"You are a helpful bioinformatics tutor. Answer clearly:\n\nQuestion: {query}\nAnswer:"
36
- inputs = self.tokenizer(prompt, return_tensors="pt").to(self.device)
37
-
38
- with torch.no_grad():
39
- outputs = self.model.generate(
40
- **inputs,
41
- max_new_tokens=512,
42
- do_sample=True,
43
- top_p=0.95,
44
- temperature=0.7,
45
- pad_token_id=self.tokenizer.eos_token_id
46
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- text = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
49
- return text.split("Answer:", 1)[-1].strip()
50
-
51
-
52
- # Formatting Agent
53
- class FormattingAgent(AssistantAgent):
54
- def __init__(self, name="FormattingAgent", **kwargs):
55
- super().__init__(name=name, **kwargs)
56
 
57
- def format_text(self, text: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  cleaned = " ".join(text.split())
59
  if cleaned:
60
  cleaned = cleaned[0].upper() + cleaned[1:]
 
 
 
61
  return cleaned
62
 
63
-
64
- # Tutor Agent
65
- class TutorAgent(AssistantAgent):
66
- def __init__(self, name="TutorAgent", **kwargs):
67
- super().__init__(name=name, **kwargs)
68
  self.model = BioMistralModel()
69
- self.format_agent = FormattingAgent()
70
- self.rag_agent = RAGAgent(vectorstore_dir=str(VECTORSTORE_DIR)) # safe conversion
 
 
 
 
 
 
 
 
 
 
71
 
72
  def process_query(self, query: str) -> str:
73
- print(f"[TutorAgent] Received query: {query}")
 
 
 
74
 
 
75
  answer = self.model.generate_answer(query)
76
  confidence = self.estimate_confidence(answer)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- print(f"[TutorAgent] Confidence: {confidence:.2f}")
79
- if confidence < CONFIDENCE_THRESHOLD:
80
- print("[TutorAgent] Confidence low, but still using BioMistral (RAG unused).")
81
-
82
- return self.format_agent.format_text(answer)
 
 
 
 
 
 
 
 
 
 
83
 
84
  def estimate_confidence(self, answer: str) -> float:
85
- length = len(answer.strip())
86
- if length > 100:
87
- return 0.9
88
- elif length > 50:
89
- return 0.75
90
- else:
 
 
 
 
 
91
  return 0.5
92
-
93
-
94
- # User Agent
95
- class BioUser(UserProxyAgent):
96
- def __init__(self, name="BioUser", **kwargs):
97
- # disable docker-based execution (not available in HF Spaces)
98
- kwargs.setdefault("code_execution_config", {"use_docker": False})
99
- super().__init__(name=name, **kwargs)
 
 
 
1
+
2
  import torch
3
+ from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
 
4
  from config import LLM_MODEL, CONFIDENCE_THRESHOLD, VECTORSTORE_DIR
 
5
  import os
6
  import sys
7
+ import logging
8
+
9
+ # Set up logging
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
 
13
+ hf_cache = "/tmp/huggingface"
14
+ os.environ["HF_HOME"] = hf_cache
15
+ os.environ["TRANSFORMERS_CACHE"] = hf_cache
16
+ os.environ["HUGGINGFACE_HUB_CACHE"] = hf_cache
17
+ os.makedirs(hf_cache, exist_ok=True)
 
18
 
19
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
20
  if BASE_DIR not in sys.path:
21
  sys.path.insert(0, BASE_DIR)
22
 
 
23
  # Load BioMistral once
24
  class BioMistralModel:
25
  def __init__(self, model_name=LLM_MODEL, device=None):
26
+ logger.info(f"Loading model: {model_name}")
27
  self.device = device or ("cuda" if torch.cuda.is_available() else "cpu")
28
+
29
+ try:
30
+ self.tokenizer = AutoTokenizer.from_pretrained(
31
+ model_name,
32
+ cache_dir=hf_cache
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  )
34
+ self.model = AutoModelForCausalLM.from_pretrained(
35
+ model_name,
36
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
37
+ device_map="auto" if self.device == "cuda" else None,
38
+ cache_dir=hf_cache
39
+ )
40
+ logger.info("Model loaded successfully")
41
+ except Exception as e:
42
+ logger.error(f"Error loading model: {e}")
43
+ # Fallback to pipeline
44
+ self.pipeline = pipeline(
45
+ "text-generation",
46
+ model=model_name,
47
+ device=0 if self.device == "cuda" else -1,
48
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
49
+ )
50
+ self.use_pipeline = True
51
+ else:
52
+ self.use_pipeline = False
53
 
54
+ def generate_answer(self, query: str) -> str:
55
+ prompt = f"""You are a helpful bioinformatics tutor. Answer clearly and concisely.
 
 
 
 
 
 
56
 
57
+ Question: {query}
58
+ Answer:"""
59
+
60
+ try:
61
+ if hasattr(self, 'use_pipeline') and self.use_pipeline:
62
+ # Use pipeline fallback
63
+ result = self.pipeline(
64
+ prompt,
65
+ max_new_tokens=256,
66
+ do_sample=True,
67
+ top_p=0.9,
68
+ temperature=0.7,
69
+ pad_token_id=self.pipeline.tokenizer.eos_token_id
70
+ )
71
+ full_text = result[0]['generated_text']
72
+ else:
73
+ # Use model directly
74
+ inputs = self.tokenizer(prompt, return_tensors="pt").to(self.device)
75
+
76
+ with torch.no_grad():
77
+ outputs = self.model.generate(
78
+ **inputs,
79
+ max_new_tokens=256,
80
+ do_sample=True,
81
+ top_p=0.9,
82
+ temperature=0.7,
83
+ pad_token_id=self.tokenizer.eos_token_id
84
+ )
85
+
86
+ full_text = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
87
+
88
+ # Extract only the answer part
89
+ if "Answer:" in full_text:
90
+ return full_text.split("Answer:", 1)[-1].strip()
91
+ else:
92
+ return full_text.replace(prompt, "").strip()
93
+
94
+ except Exception as e:
95
+ logger.error(f"Error generating answer: {e}")
96
+ return f"I apologize, but I encountered an error while processing your question: {str(e)}"
97
+
98
+ # Formatting utility
99
+ class TextFormatter:
100
+ @staticmethod
101
+ def format_text(text: str) -> str:
102
+ """Clean and format text output"""
103
+ if not text:
104
+ return "I don't have an answer for that question. Could you please rephrase or ask something else?"
105
+
106
+ # Basic cleaning
107
  cleaned = " ".join(text.split())
108
  if cleaned:
109
  cleaned = cleaned[0].upper() + cleaned[1:]
110
+ # Ensure it ends with punctuation
111
+ if not cleaned[-1] in {'.', '!', '?'}:
112
+ cleaned += '.'
113
  return cleaned
114
 
115
+ # Tutor Agent
116
+ class TutorAgent:
117
+ def __init__(self):
118
+ logger.info("Initializing TutorAgent")
 
119
  self.model = BioMistralModel()
120
+ self.formatter = TextFormatter()
121
+
122
+ # Initialize RAG
123
+ self.rag_agent = None
124
+ try:
125
+ from rag import RAGAgent
126
+ self.rag_agent = RAGAgent(vectorstore_dir=str(VECTORSTORE_DIR))
127
+ logger.info("RAG agent initialized")
128
+ except ImportError as e:
129
+ logger.warning(f"RAG not available: {e}")
130
+ except Exception as e:
131
+ logger.warning(f"Failed to initialize RAG: {e}")
132
 
133
  def process_query(self, query: str) -> str:
134
+ logger.info(f"Processing query: {query}")
135
+
136
+ if not query or len(query.strip()) < 2:
137
+ return "Please ask a meaningful question about bioinformatics."
138
 
139
+ # Generate answer
140
  answer = self.model.generate_answer(query)
141
  confidence = self.estimate_confidence(answer)
142
+
143
+ logger.info(f"Confidence: {confidence:.2f}")
144
+
145
+ # If confidence is low and RAG is available, try to enhance
146
+ if confidence < CONFIDENCE_THRESHOLD and self.rag_agent:
147
+ logger.info("Low confidence, attempting RAG enhancement")
148
+ try:
149
+ rag_answer = self._enhance_with_rag(query)
150
+ if rag_answer and len(rag_answer) > len(answer):
151
+ answer = rag_answer
152
+ except Exception as e:
153
+ logger.warning(f"RAG enhancement failed: {e}")
154
+
155
+ return self.formatter.format_text(answer)
156
 
157
+ def _enhance_with_rag(self, query: str) -> str:
158
+ """Enhance answer using RAG if available"""
159
+ if not self.rag_agent:
160
+ return ""
161
+
162
+ try:
163
+ # Assuming RAGAgent has an answer method
164
+ if hasattr(self.rag_agent, 'answer'):
165
+ result = self.rag_agent.answer(query)
166
+ return result.get('answer', '') if isinstance(result, dict) else str(result)
167
+ else:
168
+ return ""
169
+ except Exception as e:
170
+ logger.error(f"RAG error: {e}")
171
+ return ""
172
 
173
  def estimate_confidence(self, answer: str) -> float:
174
+ """Simple confidence estimation"""
175
+ answer = answer.strip()
176
+ if not answer:
177
+ return 0.0
178
+
179
+ length = len(answer)
180
+ if length > 150:
181
+ return 0.85
182
+ elif length > 80:
183
+ return 0.7
184
+ elif length > 30:
185
  return 0.5
186
+ else:
187
+ return 0.3
188
+
189
+ # User class (
190
+ class BioUser:
191
+ def __init__(self, name="BioUser"):
192
+ self.name = name
193
+
194
+ def ask_question(self, question: str, tutor: TutorAgent) -> str:
195
+ return tutor.process_query(question)
app.py CHANGED
@@ -1,15 +1,31 @@
1
- # main.py
 
2
  import uvicorn
3
  from fastapi import FastAPI
4
  from pydantic import BaseModel
 
 
 
 
 
 
 
 
 
 
5
  from agents import TutorAgent, BioUser
6
 
7
  # Initialize FastAPI
8
  app = FastAPI(title="Bioinformatics Tutor API")
9
 
10
- # Initialize agents
11
- user_agent = BioUser()
12
- tutor_agent = TutorAgent()
 
 
 
 
 
13
 
14
  # Request model
15
  class QueryRequest(BaseModel):
@@ -24,10 +40,19 @@ def ask_tutor(request: QueryRequest):
24
  """
25
  Ask the Bioinformatics Tutor a question.
26
  """
27
- answer = tutor_agent.process_query(request.question)
28
- return QueryResponse(answer=answer)
 
 
 
 
 
 
29
 
30
  @app.get("/")
31
  def root():
32
- return {"message": "Bioinformatics Tutor API is running."}
33
 
 
 
 
 
1
+ # app.py
2
+ import os
3
  import uvicorn
4
  from fastapi import FastAPI
5
  from pydantic import BaseModel
6
+
7
+
8
+ os.environ['HF_HOME'] = '/tmp/huggingface'
9
+ os.environ['TRANSFORMERS_CACHE'] = '/tmp/huggingface'
10
+ os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/huggingface'
11
+
12
+ # Create cache directory
13
+ os.makedirs('/tmp/huggingface', exist_ok=True)
14
+
15
+
16
  from agents import TutorAgent, BioUser
17
 
18
  # Initialize FastAPI
19
  app = FastAPI(title="Bioinformatics Tutor API")
20
 
21
+ # Initialize agents
22
+ try:
23
+ user_agent = BioUser()
24
+ tutor_agent = TutorAgent()
25
+ agents_loaded = True
26
+ except Exception as e:
27
+ print(f"Error loading agents: {e}")
28
+ agents_loaded = False
29
 
30
  # Request model
31
  class QueryRequest(BaseModel):
 
40
  """
41
  Ask the Bioinformatics Tutor a question.
42
  """
43
+ if not agents_loaded:
44
+ return QueryResponse(answer="Error: Agents not loaded. Please check the server logs.")
45
+
46
+ try:
47
+ answer = tutor_agent.process_query(request.question)
48
+ return QueryResponse(answer=answer)
49
+ except Exception as e:
50
+ return QueryResponse(answer=f"Error processing query: {str(e)}")
51
 
52
  @app.get("/")
53
  def root():
54
+ return {"message": "Bioinformatics Tutor API is running.", "agents_loaded": agents_loaded}
55
 
56
+ @app.get("/health")
57
+ def health_check():
58
+ return {"status": "healthy", "agents_loaded": agents_loaded}
untitled ADDED
File without changes