memra 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- memra/__init__.py +6 -2
- memra/execution.py +53 -0
- memra/tool_registry.py +162 -0
- memra-0.2.4.dist-info/METADATA +145 -0
- memra-0.2.4.dist-info/RECORD +58 -0
- {memra-0.2.2.dist-info → memra-0.2.4.dist-info}/WHEEL +1 -1
- memra-0.2.4.dist-info/top_level.txt +4 -0
- memra-ops/app.py +710 -0
- memra-ops/config/config.py +25 -0
- memra-ops/config.py +34 -0
- memra-ops/scripts/release.py +133 -0
- memra-ops/scripts/start_memra.py +334 -0
- memra-ops/scripts/stop_memra.py +132 -0
- memra-ops/server_tool_registry.py +188 -0
- memra-ops/tests/test_llm_text_to_sql.py +115 -0
- memra-ops/tests/test_llm_vs_pattern.py +130 -0
- memra-ops/tests/test_mcp_schema_aware.py +124 -0
- memra-ops/tests/test_schema_aware_sql.py +139 -0
- memra-ops/tests/test_schema_aware_sql_simple.py +66 -0
- memra-ops/tests/test_text_to_sql_demo.py +140 -0
- memra-ops/tools/mcp_bridge_server.py +851 -0
- memra-sdk/examples/accounts_payable.py +215 -0
- memra-sdk/examples/accounts_payable_client.py +217 -0
- memra-sdk/examples/accounts_payable_mcp.py +200 -0
- memra-sdk/examples/ask_questions.py +123 -0
- memra-sdk/examples/invoice_processing.py +116 -0
- memra-sdk/examples/propane_delivery.py +87 -0
- memra-sdk/examples/simple_text_to_sql.py +158 -0
- memra-sdk/memra/__init__.py +31 -0
- memra-sdk/memra/discovery.py +15 -0
- memra-sdk/memra/discovery_client.py +49 -0
- memra-sdk/memra/execution.py +481 -0
- memra-sdk/memra/models.py +99 -0
- memra-sdk/memra/tool_registry.py +343 -0
- memra-sdk/memra/tool_registry_client.py +106 -0
- memra-sdk/scripts/release.py +133 -0
- memra-sdk/setup.py +52 -0
- memra-workflows/accounts_payable/accounts_payable.py +215 -0
- memra-workflows/accounts_payable/accounts_payable_client.py +216 -0
- memra-workflows/accounts_payable/accounts_payable_mcp.py +200 -0
- memra-workflows/accounts_payable/accounts_payable_smart.py +221 -0
- memra-workflows/invoice_processing/invoice_processing.py +116 -0
- memra-workflows/invoice_processing/smart_invoice_processor.py +220 -0
- memra-workflows/logic/__init__.py +1 -0
- memra-workflows/logic/file_tools.py +50 -0
- memra-workflows/logic/invoice_tools.py +501 -0
- memra-workflows/logic/propane_agents.py +52 -0
- memra-workflows/mcp_bridge_server.py +230 -0
- memra-workflows/propane_delivery/propane_delivery.py +87 -0
- memra-workflows/text_to_sql/complete_invoice_workflow_with_queries.py +208 -0
- memra-workflows/text_to_sql/complete_text_to_sql_system.py +266 -0
- memra-workflows/text_to_sql/file_discovery_demo.py +156 -0
- memra-0.2.2.dist-info/METADATA +0 -148
- memra-0.2.2.dist-info/RECORD +0 -13
- memra-0.2.2.dist-info/top_level.txt +0 -1
- {memra-0.2.2.dist-info → memra-0.2.4.dist-info}/entry_points.txt +0 -0
- {memra-0.2.2.dist-info → memra-0.2.4.dist-info/licenses}/LICENSE +0 -0
memra-ops/app.py
ADDED
@@ -0,0 +1,710 @@
|
|
1
|
+
from fastapi import FastAPI, HTTPException, Depends, Header
|
2
|
+
from fastapi.responses import HTMLResponse
|
3
|
+
from pydantic import BaseModel
|
4
|
+
from typing import Dict, Any, Optional, List
|
5
|
+
import importlib
|
6
|
+
import logging
|
7
|
+
import os
|
8
|
+
import sys
|
9
|
+
from pathlib import Path
|
10
|
+
import json
|
11
|
+
import asyncio
|
12
|
+
import hashlib
|
13
|
+
import hmac
|
14
|
+
import aiohttp
|
15
|
+
from server_tool_registry import ServerToolRegistry
|
16
|
+
|
17
|
+
# Add current directory to path for imports
|
18
|
+
sys.path.append(str(Path(__file__).parent))
|
19
|
+
|
20
|
+
# Configure logging
|
21
|
+
logging.basicConfig(level=logging.INFO)
|
22
|
+
logger = logging.getLogger(__name__)
|
23
|
+
|
24
|
+
app = FastAPI(
|
25
|
+
title="Memra Tool Execution API",
|
26
|
+
description="API for executing Memra workflow tools",
|
27
|
+
version="1.0.0"
|
28
|
+
)
|
29
|
+
|
30
|
+
# Initialize server-side tool registry
|
31
|
+
tool_registry = ServerToolRegistry()
|
32
|
+
|
33
|
+
# Request/Response models
|
34
|
+
class ToolExecutionRequest(BaseModel):
|
35
|
+
tool_name: str
|
36
|
+
hosted_by: str
|
37
|
+
input_data: Dict[str, Any]
|
38
|
+
config: Optional[Dict[str, Any]] = None
|
39
|
+
|
40
|
+
class ToolExecutionResponse(BaseModel):
|
41
|
+
success: bool
|
42
|
+
data: Optional[Dict[str, Any]] = None
|
43
|
+
error: Optional[str] = None
|
44
|
+
|
45
|
+
class ToolDiscoveryResponse(BaseModel):
|
46
|
+
tools: List[Dict[str, str]]
|
47
|
+
|
48
|
+
# Authentication
|
49
|
+
def verify_api_key(api_key: str) -> bool:
|
50
|
+
"""Verify if the provided API key is valid"""
|
51
|
+
# Get valid keys from environment variable only - no defaults
|
52
|
+
valid_keys_str = os.getenv("MEMRA_API_KEYS")
|
53
|
+
if not valid_keys_str:
|
54
|
+
# If no keys are set, deny all access
|
55
|
+
return False
|
56
|
+
|
57
|
+
valid_keys = valid_keys_str.split(",")
|
58
|
+
return api_key.strip() in [key.strip() for key in valid_keys]
|
59
|
+
|
60
|
+
# FastAPI dependency for API key verification
|
61
|
+
async def get_api_key(x_api_key: Optional[str] = Header(None)):
|
62
|
+
"""FastAPI dependency to verify API key from header"""
|
63
|
+
if not x_api_key:
|
64
|
+
raise HTTPException(
|
65
|
+
status_code=401,
|
66
|
+
detail="Missing API key. Please provide X-API-Key header."
|
67
|
+
)
|
68
|
+
|
69
|
+
if not verify_api_key(x_api_key):
|
70
|
+
raise HTTPException(
|
71
|
+
status_code=401,
|
72
|
+
detail="Invalid API key. Please contact info@memra.co for access."
|
73
|
+
)
|
74
|
+
|
75
|
+
logger.info(f"Valid API key used: {x_api_key}")
|
76
|
+
return x_api_key
|
77
|
+
|
78
|
+
@app.get("/", response_class=HTMLResponse)
|
79
|
+
async def landing_page():
|
80
|
+
"""API documentation landing page"""
|
81
|
+
return """
|
82
|
+
<!DOCTYPE html>
|
83
|
+
<html lang="en">
|
84
|
+
<head>
|
85
|
+
<meta charset="UTF-8">
|
86
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
87
|
+
<title>memra API - Declarative AI Workflows</title>
|
88
|
+
<style>
|
89
|
+
@import url('https://fonts.cdnfonts.com/css/effra');
|
90
|
+
|
91
|
+
* {
|
92
|
+
margin: 0;
|
93
|
+
padding: 0;
|
94
|
+
box-sizing: border-box;
|
95
|
+
}
|
96
|
+
|
97
|
+
body {
|
98
|
+
font-family: 'Effra', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
99
|
+
line-height: 1.6;
|
100
|
+
color: #ffffff;
|
101
|
+
background: #0f0f23;
|
102
|
+
min-height: 100vh;
|
103
|
+
overflow-x: hidden;
|
104
|
+
}
|
105
|
+
|
106
|
+
/* Animated gradient background */
|
107
|
+
.bg-gradient {
|
108
|
+
position: fixed;
|
109
|
+
top: 0;
|
110
|
+
left: 0;
|
111
|
+
right: 0;
|
112
|
+
bottom: 0;
|
113
|
+
background: radial-gradient(ellipse at top left, rgba(88, 28, 135, 0.8) 0%, transparent 40%),
|
114
|
+
radial-gradient(ellipse at bottom right, rgba(59, 130, 246, 0.6) 0%, transparent 40%),
|
115
|
+
radial-gradient(ellipse at center, rgba(147, 51, 234, 0.4) 0%, transparent 60%),
|
116
|
+
#1a1a2e;
|
117
|
+
z-index: -2;
|
118
|
+
}
|
119
|
+
|
120
|
+
/* Navigation */
|
121
|
+
nav {
|
122
|
+
position: fixed;
|
123
|
+
top: 0;
|
124
|
+
left: 0;
|
125
|
+
right: 0;
|
126
|
+
background: rgba(15, 15, 35, 0.7);
|
127
|
+
backdrop-filter: blur(20px);
|
128
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
129
|
+
z-index: 1000;
|
130
|
+
padding: 1.5rem 2rem;
|
131
|
+
}
|
132
|
+
|
133
|
+
.nav-content {
|
134
|
+
max-width: 1400px;
|
135
|
+
margin: 0 auto;
|
136
|
+
display: flex;
|
137
|
+
justify-content: space-between;
|
138
|
+
align-items: center;
|
139
|
+
}
|
140
|
+
|
141
|
+
.logo {
|
142
|
+
font-size: 1.75rem;
|
143
|
+
font-weight: 300;
|
144
|
+
color: #ffffff;
|
145
|
+
letter-spacing: -0.02em;
|
146
|
+
}
|
147
|
+
|
148
|
+
.status-badge {
|
149
|
+
background: rgba(34, 197, 94, 0.15);
|
150
|
+
border: 1px solid rgba(34, 197, 94, 0.3);
|
151
|
+
color: #22c55e;
|
152
|
+
padding: 0.4rem 1rem;
|
153
|
+
border-radius: 999px;
|
154
|
+
font-size: 0.875rem;
|
155
|
+
font-weight: 400;
|
156
|
+
animation: pulse 3s ease-in-out infinite;
|
157
|
+
}
|
158
|
+
|
159
|
+
@keyframes pulse {
|
160
|
+
0%, 100% { opacity: 1; }
|
161
|
+
50% { opacity: 0.7; }
|
162
|
+
}
|
163
|
+
|
164
|
+
/* Main content */
|
165
|
+
.container {
|
166
|
+
max-width: 1200px;
|
167
|
+
margin: 0 auto;
|
168
|
+
padding: 10rem 2rem 4rem;
|
169
|
+
}
|
170
|
+
|
171
|
+
/* Hero section */
|
172
|
+
.hero {
|
173
|
+
text-align: center;
|
174
|
+
margin-bottom: 8rem;
|
175
|
+
}
|
176
|
+
|
177
|
+
.hero h1 {
|
178
|
+
font-size: clamp(2.5rem, 6vw, 4rem);
|
179
|
+
font-weight: 300;
|
180
|
+
margin-bottom: 1.5rem;
|
181
|
+
color: #ffffff;
|
182
|
+
letter-spacing: -0.02em;
|
183
|
+
}
|
184
|
+
|
185
|
+
.hero .tagline {
|
186
|
+
font-size: 1.25rem;
|
187
|
+
color: rgba(255, 255, 255, 0.6);
|
188
|
+
margin-bottom: 4rem;
|
189
|
+
font-weight: 300;
|
190
|
+
max-width: 600px;
|
191
|
+
margin-left: auto;
|
192
|
+
margin-right: auto;
|
193
|
+
}
|
194
|
+
|
195
|
+
/* Glass card effect */
|
196
|
+
.glass-card {
|
197
|
+
background: rgba(255, 255, 255, 0.03);
|
198
|
+
backdrop-filter: blur(20px);
|
199
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
200
|
+
border-radius: 20px;
|
201
|
+
padding: 2.5rem;
|
202
|
+
margin-bottom: 2rem;
|
203
|
+
transition: all 0.3s ease;
|
204
|
+
}
|
205
|
+
|
206
|
+
.glass-card:hover {
|
207
|
+
background: rgba(255, 255, 255, 0.05);
|
208
|
+
border-color: rgba(255, 255, 255, 0.12);
|
209
|
+
}
|
210
|
+
|
211
|
+
/* Code blocks */
|
212
|
+
.code-block {
|
213
|
+
background: rgba(0, 0, 0, 0.5);
|
214
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
215
|
+
border-radius: 16px;
|
216
|
+
padding: 1.5rem;
|
217
|
+
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
218
|
+
font-size: 0.9rem;
|
219
|
+
color: rgba(255, 255, 255, 0.9);
|
220
|
+
overflow-x: auto;
|
221
|
+
margin: 1.5rem 0;
|
222
|
+
}
|
223
|
+
|
224
|
+
/* Use cases grid */
|
225
|
+
.use-cases-grid {
|
226
|
+
display: grid;
|
227
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
228
|
+
gap: 1.5rem;
|
229
|
+
margin: 2rem 0 4rem 0;
|
230
|
+
}
|
231
|
+
|
232
|
+
.use-case-card {
|
233
|
+
background: rgba(147, 51, 234, 0.05);
|
234
|
+
border: 1px solid rgba(147, 51, 234, 0.2);
|
235
|
+
border-radius: 16px;
|
236
|
+
padding: 2rem;
|
237
|
+
transition: all 0.3s ease;
|
238
|
+
}
|
239
|
+
|
240
|
+
.use-case-card:hover {
|
241
|
+
background: rgba(147, 51, 234, 0.08);
|
242
|
+
border-color: rgba(147, 51, 234, 0.4);
|
243
|
+
transform: translateY(-2px);
|
244
|
+
}
|
245
|
+
|
246
|
+
.use-case-header {
|
247
|
+
display: flex;
|
248
|
+
align-items: center;
|
249
|
+
gap: 1rem;
|
250
|
+
margin-bottom: 1rem;
|
251
|
+
}
|
252
|
+
|
253
|
+
.use-case-icon {
|
254
|
+
font-size: 2rem;
|
255
|
+
}
|
256
|
+
|
257
|
+
.use-case-card h3 {
|
258
|
+
font-size: 1.25rem;
|
259
|
+
font-weight: 400;
|
260
|
+
color: #ffffff;
|
261
|
+
}
|
262
|
+
|
263
|
+
.use-case-card p {
|
264
|
+
color: rgba(255, 255, 255, 0.7);
|
265
|
+
margin-bottom: 1rem;
|
266
|
+
line-height: 1.6;
|
267
|
+
}
|
268
|
+
|
269
|
+
.code-snippet {
|
270
|
+
background: rgba(0, 0, 0, 0.3);
|
271
|
+
border-radius: 8px;
|
272
|
+
padding: 0.75rem;
|
273
|
+
font-size: 0.8rem;
|
274
|
+
overflow-x: auto;
|
275
|
+
}
|
276
|
+
|
277
|
+
.code-snippet code {
|
278
|
+
color: #a78bfa;
|
279
|
+
font-family: 'Monaco', 'Menlo', monospace;
|
280
|
+
}
|
281
|
+
|
282
|
+
/* Features grid */
|
283
|
+
.features-grid {
|
284
|
+
display: grid;
|
285
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
286
|
+
gap: 2rem;
|
287
|
+
margin: 3rem 0;
|
288
|
+
}
|
289
|
+
|
290
|
+
.feature-card {
|
291
|
+
background: rgba(255, 255, 255, 0.02);
|
292
|
+
border: 1px solid rgba(255, 255, 255, 0.06);
|
293
|
+
border-radius: 16px;
|
294
|
+
padding: 2.5rem;
|
295
|
+
text-align: center;
|
296
|
+
transition: all 0.3s ease;
|
297
|
+
}
|
298
|
+
|
299
|
+
.feature-card:hover {
|
300
|
+
background: rgba(255, 255, 255, 0.04);
|
301
|
+
border-color: rgba(147, 51, 234, 0.3);
|
302
|
+
transform: translateY(-4px);
|
303
|
+
}
|
304
|
+
|
305
|
+
.feature-icon {
|
306
|
+
font-size: 2.5rem;
|
307
|
+
margin-bottom: 1rem;
|
308
|
+
opacity: 0.8;
|
309
|
+
}
|
310
|
+
|
311
|
+
.feature-title {
|
312
|
+
font-size: 1.25rem;
|
313
|
+
font-weight: 400;
|
314
|
+
margin-bottom: 0.5rem;
|
315
|
+
color: #ffffff;
|
316
|
+
}
|
317
|
+
|
318
|
+
.feature-desc {
|
319
|
+
color: rgba(255, 255, 255, 0.6);
|
320
|
+
font-size: 0.95rem;
|
321
|
+
line-height: 1.5;
|
322
|
+
}
|
323
|
+
|
324
|
+
/* Endpoints section */
|
325
|
+
.endpoint {
|
326
|
+
background: rgba(0, 0, 0, 0.2);
|
327
|
+
border-left: 3px solid rgba(147, 51, 234, 0.5);
|
328
|
+
padding: 1.5rem;
|
329
|
+
margin: 1rem 0;
|
330
|
+
border-radius: 0 12px 12px 0;
|
331
|
+
transition: all 0.3s ease;
|
332
|
+
}
|
333
|
+
|
334
|
+
.endpoint:hover {
|
335
|
+
background: rgba(0, 0, 0, 0.3);
|
336
|
+
border-left-color: rgba(147, 51, 234, 0.8);
|
337
|
+
}
|
338
|
+
|
339
|
+
.method {
|
340
|
+
display: inline-block;
|
341
|
+
background: rgba(147, 51, 234, 0.15);
|
342
|
+
color: #a78bfa;
|
343
|
+
padding: 0.3rem 0.8rem;
|
344
|
+
border-radius: 8px;
|
345
|
+
font-weight: 500;
|
346
|
+
font-size: 0.875rem;
|
347
|
+
margin-right: 1rem;
|
348
|
+
}
|
349
|
+
|
350
|
+
/* CTA section */
|
351
|
+
.cta-section {
|
352
|
+
background: rgba(255, 255, 255, 0.02);
|
353
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
354
|
+
border-radius: 24px;
|
355
|
+
padding: 4rem;
|
356
|
+
text-align: center;
|
357
|
+
margin: 4rem 0;
|
358
|
+
}
|
359
|
+
|
360
|
+
.cta-button {
|
361
|
+
display: inline-block;
|
362
|
+
background: #e879f9;
|
363
|
+
color: #0f0f23;
|
364
|
+
padding: 1rem 2.5rem;
|
365
|
+
border-radius: 12px;
|
366
|
+
text-decoration: none;
|
367
|
+
font-weight: 500;
|
368
|
+
transition: all 0.3s ease;
|
369
|
+
font-size: 1rem;
|
370
|
+
}
|
371
|
+
|
372
|
+
.cta-button:hover {
|
373
|
+
transform: translateY(-2px);
|
374
|
+
box-shadow: 0 10px 30px rgba(232, 121, 249, 0.3);
|
375
|
+
background: #f0abfc;
|
376
|
+
}
|
377
|
+
|
378
|
+
/* Section headers */
|
379
|
+
h2 {
|
380
|
+
font-size: 2rem;
|
381
|
+
font-weight: 300;
|
382
|
+
margin-bottom: 2rem;
|
383
|
+
color: #ffffff;
|
384
|
+
letter-spacing: -0.02em;
|
385
|
+
}
|
386
|
+
|
387
|
+
/* Accent text */
|
388
|
+
.accent {
|
389
|
+
color: #e879f9;
|
390
|
+
}
|
391
|
+
|
392
|
+
/* Warning box */
|
393
|
+
.warning-box {
|
394
|
+
background: rgba(251, 191, 36, 0.1);
|
395
|
+
border: 1px solid rgba(251, 191, 36, 0.3);
|
396
|
+
border-radius: 12px;
|
397
|
+
padding: 1rem 1.5rem;
|
398
|
+
margin: 1.5rem 0;
|
399
|
+
color: #fbbf24;
|
400
|
+
}
|
401
|
+
|
402
|
+
.warning-box strong {
|
403
|
+
color: #f59e0b;
|
404
|
+
}
|
405
|
+
|
406
|
+
/* Links */
|
407
|
+
a {
|
408
|
+
color: #a78bfa;
|
409
|
+
text-decoration: none;
|
410
|
+
transition: color 0.3s ease;
|
411
|
+
}
|
412
|
+
|
413
|
+
a:hover {
|
414
|
+
color: #e879f9;
|
415
|
+
}
|
416
|
+
|
417
|
+
/* Footer links */
|
418
|
+
.footer-links {
|
419
|
+
text-align: center;
|
420
|
+
margin-top: 6rem;
|
421
|
+
padding-top: 3rem;
|
422
|
+
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
423
|
+
}
|
424
|
+
|
425
|
+
.footer-links a {
|
426
|
+
margin: 0 1.5rem;
|
427
|
+
color: rgba(255, 255, 255, 0.5);
|
428
|
+
font-size: 0.95rem;
|
429
|
+
}
|
430
|
+
|
431
|
+
.footer-links a:hover {
|
432
|
+
color: rgba(255, 255, 255, 0.8);
|
433
|
+
}
|
434
|
+
|
435
|
+
/* Responsive */
|
436
|
+
@media (max-width: 768px) {
|
437
|
+
.hero h1 {
|
438
|
+
font-size: 2.5rem;
|
439
|
+
}
|
440
|
+
|
441
|
+
.hero .tagline {
|
442
|
+
font-size: 1.1rem;
|
443
|
+
}
|
444
|
+
|
445
|
+
.container {
|
446
|
+
padding: 7rem 1.5rem 2rem;
|
447
|
+
}
|
448
|
+
|
449
|
+
.glass-card {
|
450
|
+
padding: 2rem;
|
451
|
+
}
|
452
|
+
|
453
|
+
.cta-section {
|
454
|
+
padding: 3rem 2rem;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
</style>
|
458
|
+
</head>
|
459
|
+
<body>
|
460
|
+
<div class="bg-gradient"></div>
|
461
|
+
|
462
|
+
<nav>
|
463
|
+
<div class="nav-content">
|
464
|
+
<div class="logo">
|
465
|
+
<span>memra API</span>
|
466
|
+
</div>
|
467
|
+
<div class="status-badge">● API Running</div>
|
468
|
+
</div>
|
469
|
+
</nav>
|
470
|
+
|
471
|
+
<div class="container">
|
472
|
+
<section class="hero">
|
473
|
+
<h1>Build AI Agents That Actually Do Work</h1>
|
474
|
+
<p class="tagline">Stop writing boilerplate. Define what you want done, not how to do it. memra handles the AI orchestration so you can ship faster.</p>
|
475
|
+
|
476
|
+
<div class="glass-card">
|
477
|
+
<h2>🚀 Quick Start</h2>
|
478
|
+
<div class="code-block">pip install memra</div>
|
479
|
+
<div class="warning-box">
|
480
|
+
<strong>🔑 API Access Required:</strong>
|
481
|
+
Contact <a href="mailto:info@memra.co">info@memra.co</a> for early access to the memra API
|
482
|
+
</div>
|
483
|
+
<div style="margin-top: 2rem; padding-top: 2rem; border-top: 1px solid rgba(255, 255, 255, 0.1);">
|
484
|
+
<h3 style="font-size: 1.25rem; margin-bottom: 1rem; color: #e879f9;">Next Steps:</h3>
|
485
|
+
<ol style="color: rgba(255, 255, 255, 0.8); line-height: 2;">
|
486
|
+
<li>Install the SDK: <code style="background: rgba(0,0,0,0.3); padding: 0.2rem 0.5rem; border-radius: 4px;">pip install memra</code></li>
|
487
|
+
<li>Get your API key from <a href="mailto:info@memra.co">info@memra.co</a></li>
|
488
|
+
<li>Check out the examples below to see what you can build</li>
|
489
|
+
<li>Start with a simple agent and expand from there</li>
|
490
|
+
</ol>
|
491
|
+
</div>
|
492
|
+
</div>
|
493
|
+
</section>
|
494
|
+
|
495
|
+
<section>
|
496
|
+
<h2>🛠️ What Can You Build?</h2>
|
497
|
+
<div class="use-cases-grid">
|
498
|
+
<div class="use-case-card">
|
499
|
+
<div class="use-case-header">
|
500
|
+
<span class="use-case-icon">📄</span>
|
501
|
+
<h3>Document Processing Pipeline</h3>
|
502
|
+
</div>
|
503
|
+
<p>Auto-extract data from PDFs, invoices, contracts. Parse, validate, and push to your database.</p>
|
504
|
+
<div class="code-snippet">
|
505
|
+
<code>Agent(role="Invoice Parser", tools=["PDFProcessor", "DatabaseWriter"])</code>
|
506
|
+
</div>
|
507
|
+
</div>
|
508
|
+
<div class="use-case-card">
|
509
|
+
<div class="use-case-header">
|
510
|
+
<span class="use-case-icon">📧</span>
|
511
|
+
<h3>Customer Support Automation</h3>
|
512
|
+
</div>
|
513
|
+
<p>Handle support tickets, categorize issues, draft responses, and escalate complex cases.</p>
|
514
|
+
<div class="code-snippet">
|
515
|
+
<code>Agent(role="Support Analyst", tools=["EmailReader", "TicketClassifier"])</code>
|
516
|
+
</div>
|
517
|
+
</div>
|
518
|
+
<div class="use-case-card">
|
519
|
+
<div class="use-case-header">
|
520
|
+
<span class="use-case-icon">📊</span>
|
521
|
+
<h3>Data Analysis Workflows</h3>
|
522
|
+
</div>
|
523
|
+
<p>Connect to databases, run analysis, generate reports, and send insights to Slack.</p>
|
524
|
+
<div class="code-snippet">
|
525
|
+
<code>Agent(role="Data Analyst", tools=["SQLQuery", "ChartGenerator", "SlackNotifier"])</code>
|
526
|
+
</div>
|
527
|
+
</div>
|
528
|
+
<div class="use-case-card">
|
529
|
+
<div class="use-case-header">
|
530
|
+
<span class="use-case-icon">🔄</span>
|
531
|
+
<h3>API Integration Chains</h3>
|
532
|
+
</div>
|
533
|
+
<p>Chain multiple APIs together with AI decision-making between steps.</p>
|
534
|
+
<div class="code-snippet">
|
535
|
+
<code>Agent(role="Integration Expert", tools=["HTTPClient", "JSONTransformer"])</code>
|
536
|
+
</div>
|
537
|
+
</div>
|
538
|
+
<div class="use-case-card">
|
539
|
+
<div class="use-case-header">
|
540
|
+
<span class="use-case-icon">🔍</span>
|
541
|
+
<h3>Content Moderation Pipeline</h3>
|
542
|
+
</div>
|
543
|
+
<p>Review user content, flag issues, apply policies, and maintain compliance automatically.</p>
|
544
|
+
<div class="code-snippet">
|
545
|
+
<code>Agent(role="Content Reviewer", tools=["TextAnalyzer", "PolicyEngine", "FlagSystem"])</code>
|
546
|
+
</div>
|
547
|
+
</div>
|
548
|
+
<div class="use-case-card">
|
549
|
+
<div class="use-case-header">
|
550
|
+
<span class="use-case-icon">🚀</span>
|
551
|
+
<h3>Lead Qualification System</h3>
|
552
|
+
</div>
|
553
|
+
<p>Score leads, enrich data from multiple sources, and route to the right sales team.</p>
|
554
|
+
<div class="code-snippet">
|
555
|
+
<code>Agent(role="Lead Scorer", tools=["CRMConnector", "DataEnricher", "RouterAgent"])</code>
|
556
|
+
</div>
|
557
|
+
</div>
|
558
|
+
</div>
|
559
|
+
</section>
|
560
|
+
|
561
|
+
<section>
|
562
|
+
<h2>✨ Why <span class="accent">memra</span>?</h2>
|
563
|
+
<div class="features-grid">
|
564
|
+
<div class="feature-card">
|
565
|
+
<div class="feature-icon">📋</div>
|
566
|
+
<div class="feature-title">Declarative Design</div>
|
567
|
+
<div class="feature-desc">Define workflows like Kubernetes YAML. Version control your AI business logic.</div>
|
568
|
+
</div>
|
569
|
+
<div class="feature-card">
|
570
|
+
<div class="feature-icon">🤖</div>
|
571
|
+
<div class="feature-title">Multi-LLM Support</div>
|
572
|
+
<div class="feature-desc">Seamlessly integrate OpenAI, Anthropic, and other providers with zero config changes.</div>
|
573
|
+
</div>
|
574
|
+
<div class="feature-card">
|
575
|
+
<div class="feature-icon">💬</div>
|
576
|
+
<div class="feature-title">Self-Documenting</div>
|
577
|
+
<div class="feature-desc">Agents explain their decisions in natural language for full transparency.</div>
|
578
|
+
</div>
|
579
|
+
<div class="feature-card">
|
580
|
+
<div class="feature-icon">🏗️</div>
|
581
|
+
<div class="feature-title">Enterprise Ready</div>
|
582
|
+
<div class="feature-desc">Battle-tested on real databases, files, and complex business workflows.</div>
|
583
|
+
</div>
|
584
|
+
</div>
|
585
|
+
</section>
|
586
|
+
|
587
|
+
<section>
|
588
|
+
<h2>📡 API Endpoints</h2>
|
589
|
+
<div class="glass-card">
|
590
|
+
<div class="endpoint">
|
591
|
+
<span class="method">GET</span>/health
|
592
|
+
<div>Health check and API status verification</div>
|
593
|
+
</div>
|
594
|
+
<div class="endpoint">
|
595
|
+
<span class="method">GET</span>/tools/discover
|
596
|
+
<div>Discover available workflow tools and their capabilities</div>
|
597
|
+
</div>
|
598
|
+
<div class="endpoint">
|
599
|
+
<span class="method">POST</span>/tools/execute
|
600
|
+
<div>Execute workflow tools with structured input data</div>
|
601
|
+
</div>
|
602
|
+
</div>
|
603
|
+
</section>
|
604
|
+
|
605
|
+
<section>
|
606
|
+
<h2>📚 Full Example: Invoice Processing</h2>
|
607
|
+
<div class="glass-card">
|
608
|
+
<p style="color: rgba(255, 255, 255, 0.7); margin-bottom: 1.5rem;">
|
609
|
+
Here's how you'd build an invoice processing system that extracts data and updates your database:
|
610
|
+
</p>
|
611
|
+
<div class="code-block">from memra import Agent, Department
|
612
|
+
from memra.execution import ExecutionEngine
|
613
|
+
|
614
|
+
# 1. Define what you want done (not how)
|
615
|
+
invoice_processor = Agent(
|
616
|
+
role="Invoice Processor",
|
617
|
+
job="Extract vendor, amount, and line items from PDF invoices",
|
618
|
+
tools=[
|
619
|
+
{"name": "PDFProcessor", "hosted_by": "memra"},
|
620
|
+
{"name": "DataValidator", "hosted_by": "memra"},
|
621
|
+
{"name": "DatabaseWriter", "hosted_by": "memra"}
|
622
|
+
]
|
623
|
+
)
|
624
|
+
|
625
|
+
# 2. Create a department (group related agents)
|
626
|
+
finance_dept = Department(
|
627
|
+
name="Accounts Payable",
|
628
|
+
agents=[invoice_processor]
|
629
|
+
)
|
630
|
+
|
631
|
+
# 3. Execute - memra handles the AI orchestration
|
632
|
+
engine = ExecutionEngine()
|
633
|
+
result = engine.execute_department(
|
634
|
+
finance_dept,
|
635
|
+
{"file": "invoice.pdf", "database": "postgresql://..."}
|
636
|
+
)
|
637
|
+
|
638
|
+
# Result: Structured data extracted and saved to your DB
|
639
|
+
print(result.summary) # "Extracted invoice #INV-001 for $1,234.56 from Acme Corp"</div>
|
640
|
+
</div>
|
641
|
+
</section>
|
642
|
+
|
643
|
+
<div class="cta-section">
|
644
|
+
<h2>Ready to Build Your AI Workforce?</h2>
|
645
|
+
<p style="color: rgba(255, 255, 255, 0.6); margin-bottom: 2rem;">Join innovative teams automating their workflows with memra</p>
|
646
|
+
<a href="mailto:info@memra.co" class="cta-button">Get Started Now</a>
|
647
|
+
</div>
|
648
|
+
|
649
|
+
<div class="footer-links">
|
650
|
+
<a href="https://pypi.org/project/memra/">PyPI Package</a>
|
651
|
+
<a href="https://github.com/memra-platform/memra-sdk">GitHub</a>
|
652
|
+
<a href="https://memra.co">Website</a>
|
653
|
+
<a href="mailto:info@memra.co">Contact</a>
|
654
|
+
</div>
|
655
|
+
</div>
|
656
|
+
</body>
|
657
|
+
</html>
|
658
|
+
"""
|
659
|
+
|
660
|
+
@app.get("/health")
|
661
|
+
async def health_check():
|
662
|
+
"""Health check for Fly.io"""
|
663
|
+
return {"status": "healthy"}
|
664
|
+
|
665
|
+
@app.post("/tools/execute", response_model=ToolExecutionResponse)
|
666
|
+
async def execute_tool(
|
667
|
+
request: ToolExecutionRequest,
|
668
|
+
api_key: Optional[str] = Depends(get_api_key)
|
669
|
+
):
|
670
|
+
"""Execute a tool with the given input data"""
|
671
|
+
try:
|
672
|
+
logger.info(f"Executing tool: {request.tool_name}")
|
673
|
+
|
674
|
+
# Create registry and execute tool
|
675
|
+
result = tool_registry.execute_tool(
|
676
|
+
request.tool_name,
|
677
|
+
request.hosted_by,
|
678
|
+
request.input_data,
|
679
|
+
request.config
|
680
|
+
)
|
681
|
+
|
682
|
+
return ToolExecutionResponse(
|
683
|
+
success=result.get("success", False),
|
684
|
+
data=result.get("data"),
|
685
|
+
error=result.get("error")
|
686
|
+
)
|
687
|
+
|
688
|
+
except Exception as e:
|
689
|
+
logger.error(f"Tool execution failed: {str(e)}")
|
690
|
+
return ToolExecutionResponse(
|
691
|
+
success=False,
|
692
|
+
error=str(e)
|
693
|
+
)
|
694
|
+
|
695
|
+
@app.get("/tools/discover", response_model=ToolDiscoveryResponse)
|
696
|
+
async def discover_tools(api_key: Optional[str] = Depends(get_api_key)):
|
697
|
+
"""Discover available tools"""
|
698
|
+
try:
|
699
|
+
tools = tool_registry.discover_tools()
|
700
|
+
|
701
|
+
return ToolDiscoveryResponse(tools=tools)
|
702
|
+
|
703
|
+
except Exception as e:
|
704
|
+
logger.error(f"Tool discovery failed: {str(e)}")
|
705
|
+
raise HTTPException(status_code=500, detail=str(e))
|
706
|
+
|
707
|
+
if __name__ == "__main__":
|
708
|
+
import uvicorn
|
709
|
+
port = int(os.getenv("PORT", 8080))
|
710
|
+
uvicorn.run(app, host="0.0.0.0", port=port)
|