Spaces:
Sleeping
Sleeping
Update genesis/providers.py
Browse files- genesis/providers.py +237 -144
genesis/providers.py
CHANGED
@@ -1,164 +1,257 @@
|
|
1 |
# genesis/providers.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import os
|
|
|
3 |
import requests
|
4 |
-
import
|
5 |
-
from
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
-
# Load secrets from environment
|
8 |
-
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
|
9 |
-
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
10 |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
# ------------------------------
|
15 |
-
# 1 β DEEPSEEK SUMMARIZER
|
16 |
-
# ------------------------------
|
17 |
-
def run_deepseek_summary(prompt: str) -> Optional[str]:
|
18 |
-
if not DEEPSEEK_API_KEY:
|
19 |
-
return None
|
20 |
-
try:
|
21 |
-
url = "https://api.deepseek.com/v1/chat/completions"
|
22 |
-
headers = {"Authorization": f"Bearer {DEEPSEEK_API_KEY}"}
|
23 |
-
payload = {
|
24 |
-
"model": "deepseek-chat",
|
25 |
-
"messages": [{"role": "user", "content": prompt}],
|
26 |
-
"temperature": 0.3
|
27 |
-
}
|
28 |
-
resp = requests.post(url, headers=headers, json=payload, timeout=60)
|
29 |
-
resp.raise_for_status()
|
30 |
-
return resp.json()["choices"][0]["message"]["content"]
|
31 |
-
except Exception as e:
|
32 |
-
print(f"[DeepSeek] Failed: {e}")
|
33 |
-
return None
|
34 |
|
|
|
35 |
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
def run_gemini_summary(prompt: str) -> Optional[str]:
|
40 |
-
if not GEMINI_API_KEY:
|
41 |
-
return None
|
42 |
-
try:
|
43 |
-
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key={GEMINI_API_KEY}"
|
44 |
-
headers = {"Content-Type": "application/json"}
|
45 |
-
payload = {"contents": [{"parts": [{"text": prompt}]}]}
|
46 |
-
resp = requests.post(url, headers=headers, json=payload, timeout=60)
|
47 |
-
resp.raise_for_status()
|
48 |
-
return resp.json()["candidates"][0]["content"]["parts"][0]["text"]
|
49 |
-
except Exception as e:
|
50 |
-
print(f"[Gemini] Failed: {e}")
|
51 |
-
return None
|
52 |
|
|
|
|
|
53 |
|
54 |
-
|
55 |
-
|
56 |
-
# ------------------------------
|
57 |
-
def run_openai_summary(prompt: str) -> Optional[str]:
|
58 |
-
if not OPENAI_API_KEY:
|
59 |
-
return None
|
60 |
try:
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
}
|
68 |
-
resp = requests.post(url, headers=headers, json=payload, timeout=60)
|
69 |
-
resp.raise_for_status()
|
70 |
-
return resp.json()["choices"][0]["message"]["content"]
|
71 |
except Exception as e:
|
72 |
-
|
73 |
return None
|
74 |
|
|
|
|
|
|
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
|
|
96 |
|
97 |
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
if not OPENAI_API_KEY:
|
103 |
-
return None
|
104 |
-
try:
|
105 |
-
url = "https://api.openai.com/v1/images/generations"
|
106 |
-
headers = {"Authorization": f"Bearer {OPENAI_API_KEY}"}
|
107 |
-
payload = {"model": "gpt-image-1", "prompt": prompt, "size": "1024x1024"}
|
108 |
-
resp = requests.post(url, headers=headers, json=payload, timeout=60)
|
109 |
-
resp.raise_for_status()
|
110 |
-
return resp.json()["data"][0]["url"]
|
111 |
-
except Exception as e:
|
112 |
-
print(f"[OpenAI Image] Failed: {e}")
|
113 |
-
return None
|
114 |
|
115 |
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
if not HF_API_KEY:
|
121 |
-
return None
|
122 |
-
try:
|
123 |
-
url = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-2"
|
124 |
-
headers = {"Authorization": f"Bearer {HF_API_KEY}"}
|
125 |
-
payload = {"inputs": prompt}
|
126 |
-
resp = requests.post(url, headers=headers, json=payload, timeout=120)
|
127 |
-
resp.raise_for_status()
|
128 |
-
if resp.headers.get("content-type") == "image/png":
|
129 |
-
filename = f"generated_{hash(prompt)}.png"
|
130 |
-
with open(filename, "wb") as f:
|
131 |
-
f.write(resp.content)
|
132 |
-
return filename
|
133 |
-
return None
|
134 |
-
except Exception as e:
|
135 |
-
print(f"[HF Image] Failed: {e}")
|
136 |
-
return None
|
137 |
|
138 |
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
# genesis/providers.py
|
2 |
+
"""
|
3 |
+
Providers module for GENESIS-AI
|
4 |
+
Handles:
|
5 |
+
1. Medical/Biological APIs (PubMed, ChEMBL, BioPortal, UMLS, NCBI)
|
6 |
+
2. AI Text Generation (Gemini, OpenAI, Claude, DeepSeek)
|
7 |
+
3. Image Generation (Gemini Vision, OpenAI DALLΒ·E, Hugging Face Diffusion)
|
8 |
+
4. Text-to-Speech (ElevenLabs + fallback)
|
9 |
+
5. Graph DB Integration (Neo4j for pathways/funding)
|
10 |
+
"""
|
11 |
+
|
12 |
import os
|
13 |
+
import json
|
14 |
import requests
|
15 |
+
import logging
|
16 |
+
from neo4j import GraphDatabase
|
17 |
+
from dotenv import load_dotenv
|
18 |
+
|
19 |
+
# ========================
|
20 |
+
# SECTION 1 β SETUP & LOGGING
|
21 |
+
# ========================
|
22 |
+
load_dotenv()
|
23 |
+
logging.basicConfig(level=logging.INFO)
|
24 |
+
|
25 |
+
# API KEYS from Hugging Face Secrets or local .env
|
26 |
+
PUBMED_API_KEY = os.getenv("PUBMED_API_KEY")
|
27 |
+
CHEMBL_API_KEY = os.getenv("CHEMBL_API_KEY")
|
28 |
+
BIOPORTAL_API_KEY = os.getenv("BIOPORTAL_API_KEY")
|
29 |
+
UMLS_API_KEY = os.getenv("UMLS_API_KEY")
|
30 |
+
NCBI_API_KEY = os.getenv("NCBI_API_KEY")
|
31 |
|
|
|
|
|
|
|
32 |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
33 |
+
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
34 |
+
CLAUDE_API_KEY = os.getenv("CLAUDE_API_KEY")
|
35 |
+
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
+
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
|
38 |
|
39 |
+
NEO4J_URI = os.getenv("NEO4J_URI")
|
40 |
+
NEO4J_USER = os.getenv("NEO4J_USER")
|
41 |
+
NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
+
# Neo4j Driver
|
44 |
+
neo4j_driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
|
45 |
|
46 |
+
|
47 |
+
def safe_request(url, headers=None, params=None, data=None, method="GET", json_data=None):
|
|
|
|
|
|
|
|
|
48 |
try:
|
49 |
+
if method == "GET":
|
50 |
+
r = requests.get(url, headers=headers, params=params, timeout=20)
|
51 |
+
elif method == "POST":
|
52 |
+
r = requests.post(url, headers=headers, data=data, json=json_data, timeout=30)
|
53 |
+
r.raise_for_status()
|
54 |
+
return r.json()
|
|
|
|
|
|
|
|
|
55 |
except Exception as e:
|
56 |
+
logging.error(f"Request failed: {e}")
|
57 |
return None
|
58 |
|
59 |
+
# ========================
|
60 |
+
# SECTION 2 β MEDICAL & BIOLOGY API CLIENTS
|
61 |
+
# ========================
|
62 |
|
63 |
+
def run_pubmed_literature(query, max_results=5):
|
64 |
+
url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"
|
65 |
+
params = {
|
66 |
+
"db": "pubmed",
|
67 |
+
"term": query,
|
68 |
+
"retmode": "json",
|
69 |
+
"retmax": max_results,
|
70 |
+
"api_key": PUBMED_API_KEY
|
71 |
+
}
|
72 |
+
data = safe_request(url, params=params)
|
73 |
+
if not data:
|
74 |
+
return []
|
75 |
+
ids = data.get("esearchresult", {}).get("idlist", [])
|
76 |
+
results = []
|
77 |
+
for pmid in ids:
|
78 |
+
fetch_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi"
|
79 |
+
fetch_params = {"db": "pubmed", "id": pmid, "retmode": "json"}
|
80 |
+
summary = safe_request(fetch_url, params=fetch_params)
|
81 |
+
if summary:
|
82 |
+
results.append(summary)
|
83 |
+
return results
|
84 |
|
85 |
|
86 |
+
def run_chembl_search(molecule_name):
|
87 |
+
url = f"https://www.ebi.ac.uk/chembl/api/data/molecule"
|
88 |
+
params = {"molecule_synonyms__icontains": molecule_name, "format": "json"}
|
89 |
+
return safe_request(url, params=params)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
|
92 |
+
def run_bioportal_ontology(term):
|
93 |
+
url = f"https://data.bioontology.org/search"
|
94 |
+
params = {"q": term, "apikey": BIOPORTAL_API_KEY}
|
95 |
+
return safe_request(url, params=params)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
|
98 |
+
def run_umls_search(term):
|
99 |
+
url = f"https://uts-ws.nlm.nih.gov/rest/search/current"
|
100 |
+
params = {"string": term, "apiKey": UMLS_API_KEY}
|
101 |
+
return safe_request(url, params=params)
|
102 |
+
|
103 |
+
|
104 |
+
def run_ncbi_gene_lookup(gene_id):
|
105 |
+
url = f"https://api.ncbi.nlm.nih.gov/gene/{gene_id}"
|
106 |
+
headers = {"api-key": NCBI_API_KEY}
|
107 |
+
return safe_request(url, headers=headers)
|
108 |
+
|
109 |
+
|
110 |
+
# ========================
|
111 |
+
# SECTION 3 β AI TEXT GENERATION PROVIDERS
|
112 |
+
# ========================
|
113 |
+
|
114 |
+
def ai_generate_text(prompt, model="gemini"):
|
115 |
+
"""Fallback order: Gemini β OpenAI β Claude β DeepSeek"""
|
116 |
+
if model == "gemini" and GEMINI_API_KEY:
|
117 |
+
resp = safe_request(
|
118 |
+
f"https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key={GEMINI_API_KEY}",
|
119 |
+
method="POST",
|
120 |
+
json_data={"contents": [{"parts": [{"text": prompt}]}]}
|
121 |
+
)
|
122 |
+
if resp:
|
123 |
+
return resp.get("candidates", [{}])[0].get("content", {}).get("parts", [{}])[0].get("text", "")
|
124 |
+
|
125 |
+
if OPENAI_API_KEY:
|
126 |
+
try:
|
127 |
+
import openai
|
128 |
+
openai.api_key = OPENAI_API_KEY
|
129 |
+
completion = openai.ChatCompletion.create(
|
130 |
+
model="gpt-4o",
|
131 |
+
messages=[{"role": "user", "content": prompt}]
|
132 |
+
)
|
133 |
+
return completion.choices[0].message["content"]
|
134 |
+
except Exception as e:
|
135 |
+
logging.error(f"OpenAI error: {e}")
|
136 |
+
|
137 |
+
if CLAUDE_API_KEY:
|
138 |
+
resp = safe_request(
|
139 |
+
"https://api.anthropic.com/v1/messages",
|
140 |
+
headers={"x-api-key": CLAUDE_API_KEY, "Content-Type": "application/json"},
|
141 |
+
method="POST",
|
142 |
+
json_data={"model": "claude-3-opus-20240229", "messages": [{"role": "user", "content": prompt}], "max_tokens": 500}
|
143 |
+
)
|
144 |
+
if resp:
|
145 |
+
return resp.get("content", [{}])[0].get("text", "")
|
146 |
+
|
147 |
+
if DEEPSEEK_API_KEY:
|
148 |
+
resp = safe_request(
|
149 |
+
"https://api.deepseek.com/v1/chat/completions",
|
150 |
+
headers={"Authorization": f"Bearer {DEEPSEEK_API_KEY}", "Content-Type": "application/json"},
|
151 |
+
method="POST",
|
152 |
+
json_data={"model": "deepseek-chat", "messages": [{"role": "user", "content": prompt}]}
|
153 |
+
)
|
154 |
+
if resp:
|
155 |
+
return resp.get("choices", [{}])[0].get("message", {}).get("content", "")
|
156 |
+
|
157 |
+
return "No AI provider available or all failed."
|
158 |
+
|
159 |
+
|
160 |
+
# ========================
|
161 |
+
# SECTION 4 β IMAGE GENERATION PROVIDERS
|
162 |
+
# ========================
|
163 |
+
|
164 |
+
def ai_generate_image(prompt):
|
165 |
+
"""Fallback: Gemini Vision β OpenAI β Hugging Face"""
|
166 |
+
if GEMINI_API_KEY:
|
167 |
+
resp = safe_request(
|
168 |
+
f"https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateImage?key={GEMINI_API_KEY}",
|
169 |
+
method="POST",
|
170 |
+
json_data={"prompt": prompt}
|
171 |
+
)
|
172 |
+
if resp:
|
173 |
+
return resp
|
174 |
+
|
175 |
+
if OPENAI_API_KEY:
|
176 |
+
try:
|
177 |
+
import openai
|
178 |
+
openai.api_key = OPENAI_API_KEY
|
179 |
+
image = openai.Image.create(model="dall-e-3", prompt=prompt, size="1024x1024")
|
180 |
+
return image.data[0].url
|
181 |
+
except Exception as e:
|
182 |
+
logging.error(f"OpenAI Image error: {e}")
|
183 |
+
|
184 |
+
# Hugging Face fallback
|
185 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
186 |
+
if HF_TOKEN:
|
187 |
+
resp = safe_request(
|
188 |
+
"https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-2",
|
189 |
+
headers={"Authorization": f"Bearer {HF_TOKEN}"},
|
190 |
+
method="POST",
|
191 |
+
json_data={"inputs": prompt}
|
192 |
+
)
|
193 |
+
if resp:
|
194 |
+
return resp
|
195 |
+
|
196 |
+
return None
|
197 |
+
|
198 |
+
|
199 |
+
# ========================
|
200 |
+
# SECTION 5 β TEXT-TO-SPEECH PROVIDERS
|
201 |
+
# ========================
|
202 |
+
|
203 |
+
def run_tts(text, voice="Rachel"):
|
204 |
+
if ELEVENLABS_API_KEY:
|
205 |
+
url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice}"
|
206 |
+
headers = {"xi-api-key": ELEVENLABS_API_KEY, "Content-Type": "application/json"}
|
207 |
+
resp = requests.post(url, headers=headers, json={"text": text, "voice_settings": {"stability": 0.5, "similarity_boost": 0.8}})
|
208 |
+
if resp.status_code == 200:
|
209 |
+
return resp.content
|
210 |
+
return None
|
211 |
+
|
212 |
+
|
213 |
+
# ========================
|
214 |
+
# SECTION 6 β NEO4J GRAPH FUNCTIONS
|
215 |
+
# ========================
|
216 |
+
|
217 |
+
def query_funding_network(keyword):
|
218 |
+
with neo4j_driver.session() as session:
|
219 |
+
result = session.run(
|
220 |
+
"""
|
221 |
+
MATCH (c:Company)-[r:RECEIVED_FUNDING_FROM]->(i:Investor)
|
222 |
+
WHERE toLower(c.name) CONTAINS toLower($keyword)
|
223 |
+
RETURN c.name as company, collect(i.name) as investors
|
224 |
+
""",
|
225 |
+
keyword=keyword
|
226 |
+
)
|
227 |
+
return [dict(record) for record in result]
|
228 |
+
|
229 |
+
|
230 |
+
def query_pathway_graph(pathway):
|
231 |
+
with neo4j_driver.session() as session:
|
232 |
+
result = session.run(
|
233 |
+
"""
|
234 |
+
MATCH (p:Pathway {name: $pathway})-[r:INVOLVES]->(g:Gene)
|
235 |
+
RETURN p.name as pathway, collect(g.name) as genes
|
236 |
+
""",
|
237 |
+
pathway=pathway
|
238 |
+
)
|
239 |
+
return [dict(record) for record in result]
|
240 |
+
|
241 |
+
|
242 |
+
# ========================
|
243 |
+
# SECTION 7 β EXPORTS
|
244 |
+
# ========================
|
245 |
+
|
246 |
+
__all__ = [
|
247 |
+
"run_pubmed_literature",
|
248 |
+
"run_chembl_search",
|
249 |
+
"run_bioportal_ontology",
|
250 |
+
"run_umls_search",
|
251 |
+
"run_ncbi_gene_lookup",
|
252 |
+
"ai_generate_text",
|
253 |
+
"ai_generate_image",
|
254 |
+
"run_tts",
|
255 |
+
"query_funding_network",
|
256 |
+
"query_pathway_graph"
|
257 |
+
]
|