mgbam commited on
Commit
f9cc55d
Β·
verified Β·
1 Parent(s): 443e9f1

Update genesis/providers.py

Browse files
Files changed (1) hide show
  1. 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 base64
5
- from typing import Optional
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- HF_API_KEY = os.getenv("HF_API_KEY")
12
- ELEVEN_LABS_API_KEY = os.getenv("ELEVEN_LABS_API_KEY")
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
- # 2 β€” GEMINI SUMMARIZER
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
- # 3 β€” OPENAI SUMMARIZER
56
- # ------------------------------
57
- def run_openai_summary(prompt: str) -> Optional[str]:
58
- if not OPENAI_API_KEY:
59
- return None
60
  try:
61
- url = "https://api.openai.com/v1/chat/completions"
62
- headers = {"Authorization": f"Bearer {OPENAI_API_KEY}"}
63
- payload = {
64
- "model": "gpt-4o-mini",
65
- "messages": [{"role": "user", "content": prompt}],
66
- "temperature": 0.3
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
- print(f"[OpenAI] Failed: {e}")
73
  return None
74
 
 
 
 
75
 
76
- # ------------------------------
77
- # 4 β€” GEMINI IMAGE GENERATOR
78
- # ------------------------------
79
- def run_gemini_image(prompt: str) -> Optional[str]:
80
- if not GEMINI_API_KEY:
81
- return None
82
- try:
83
- # Gemini image generation (beta)
84
- url = f"https://generativelanguage.googleapis.com/v1beta/models/imagegeneration:generateImage?key={GEMINI_API_KEY}"
85
- payload = {"prompt": prompt, "size": "1024x1024"}
86
- headers = {"Content-Type": "application/json"}
87
- resp = requests.post(url, headers=headers, json=payload, timeout=60)
88
- resp.raise_for_status()
89
- data = resp.json()
90
- if "data" in data and len(data["data"]) > 0:
91
- return data["data"][0]["url"]
92
- return None
93
- except Exception as e:
94
- print(f"[Gemini Image] Failed: {e}")
95
- return None
 
96
 
97
 
98
- # ------------------------------
99
- # 5 β€” OPENAI IMAGE GENERATOR
100
- # ------------------------------
101
- def run_openai_image(prompt: str) -> Optional[str]:
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
- # 6 β€” HF STABLE DIFFUSION IMAGE
118
- # ------------------------------
119
- def run_hf_image(prompt: str) -> Optional[str]:
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
- # 7 β€” ELEVENLABS TEXT-TO-SPEECH
141
- # ------------------------------
142
- def narrate_text_elevenlabs(text: str) -> Optional[str]:
143
- if not ELEVEN_LABS_API_KEY:
144
- return None
145
- try:
146
- url = "https://api.elevenlabs.io/v1/text-to-speech"
147
- headers = {
148
- "xi-api-key": ELEVEN_LABS_API_KEY,
149
- "Content-Type": "application/json"
150
- }
151
- payload = {
152
- "text": text,
153
- "voice": "Bella", # You can make this configurable
154
- "model_id": "eleven_monolingual_v1"
155
- }
156
- resp = requests.post(url, headers=headers, json=payload, timeout=60)
157
- resp.raise_for_status()
158
- filename = f"narration_{hash(text)}.mp3"
159
- with open(filename, "wb") as f:
160
- f.write(resp.content)
161
- return filename
162
- except Exception as e:
163
- print(f"[ElevenLabs] Failed: {e}")
164
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ]