socrates-ai-api 1.3.0__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.
- socrates_ai_api-1.3.0.dist-info/METADATA +446 -0
- socrates_ai_api-1.3.0.dist-info/RECORD +11 -0
- socrates_ai_api-1.3.0.dist-info/WHEEL +5 -0
- socrates_ai_api-1.3.0.dist-info/entry_points.txt +2 -0
- socrates_ai_api-1.3.0.dist-info/top_level.txt +1 -0
- socrates_api/__init__.py +12 -0
- socrates_api/database.py +118 -0
- socrates_api/main.py +876 -0
- socrates_api/models.py +929 -0
- socrates_api/monitoring.py +222 -0
- socrates_api/testing_mode.py +77 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: socrates-ai-api
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: REST API server for Socrates AI with GitHub-ready project generation, export, and publishing capabilities
|
|
5
|
+
Author: Socrates AI Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Nireus79/Socrates
|
|
8
|
+
Project-URL: Repository, https://github.com/Nireus79/Socrates
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/Nireus79/Socrates/issues
|
|
10
|
+
Project-URL: Source Code, https://github.com/Nireus79/Socrates/tree/main/socrates-api
|
|
11
|
+
Keywords: api,rest,fastapi,socrates,ai,tutoring,github,export,git,ci-cd
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Environment :: Web Environment
|
|
22
|
+
Classifier: Topic :: Education
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: socrates-ai>=1.3.0
|
|
27
|
+
Requires-Dist: fastapi>=0.100.0
|
|
28
|
+
Requires-Dist: uvicorn[standard]>=0.23.0
|
|
29
|
+
Requires-Dist: pydantic>=2.0.0
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
31
|
+
Requires-Dist: python-multipart>=0.0.5
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
36
|
+
Requires-Dist: httpx>=0.24.0; extra == "dev"
|
|
37
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
39
|
+
|
|
40
|
+
# Socrates API
|
|
41
|
+
|
|
42
|
+
REST API server for the Socrates AI tutoring system. Built with FastAPI, this server provides endpoints for project management, Socratic questioning, code generation, and more.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install socrates-api
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
### 1. Set Environment Variables
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
export ANTHROPIC_API_KEY="your-api-key-here"
|
|
56
|
+
export SOCRATES_DATA_DIR="~/.socrates" # Optional
|
|
57
|
+
export SOCRATES_API_HOST="0.0.0.0" # Optional, default: 127.0.0.1
|
|
58
|
+
export SOCRATES_API_PORT="8000" # Optional, default: 8000
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. Run the Server
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
socrates-api
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or use Python directly:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python -m socrates_api.main
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 3. Access the API
|
|
74
|
+
|
|
75
|
+
- **Swagger Documentation**: http://localhost:8000/docs
|
|
76
|
+
- **ReDoc Documentation**: http://localhost:8000/redoc
|
|
77
|
+
- **Health Check**: http://localhost:8000/health
|
|
78
|
+
|
|
79
|
+
## API Endpoints
|
|
80
|
+
|
|
81
|
+
### System Management
|
|
82
|
+
|
|
83
|
+
- `GET /health` - Health check
|
|
84
|
+
- `POST /initialize` - Initialize API with configuration
|
|
85
|
+
- `GET /info` - Get system information
|
|
86
|
+
|
|
87
|
+
### Projects
|
|
88
|
+
|
|
89
|
+
- `POST /projects` - Create a new project
|
|
90
|
+
- `GET /projects` - List projects (optionally filtered by owner)
|
|
91
|
+
|
|
92
|
+
### Socratic Questions
|
|
93
|
+
|
|
94
|
+
- `POST /projects/{project_id}/question` - Get a Socratic question
|
|
95
|
+
- `POST /projects/{project_id}/response` - Process user response
|
|
96
|
+
|
|
97
|
+
### Code Generation
|
|
98
|
+
|
|
99
|
+
- `POST /code/generate` - Generate code for a project
|
|
100
|
+
|
|
101
|
+
## Usage Examples
|
|
102
|
+
|
|
103
|
+
### Initialize the API
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
curl -X POST http://localhost:8000/initialize \
|
|
107
|
+
-H "Content-Type: application/json" \
|
|
108
|
+
-d '{"api_key": "sk-ant-..."}'
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Create a Project
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
curl -X POST http://localhost:8000/projects \
|
|
115
|
+
-H "Content-Type: application/json" \
|
|
116
|
+
-d '{
|
|
117
|
+
"name": "Python API Development",
|
|
118
|
+
"owner": "alice",
|
|
119
|
+
"description": "Building REST APIs with FastAPI"
|
|
120
|
+
}'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### List Projects
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
curl http://localhost:8000/projects
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Ask a Socratic Question
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
curl -X POST http://localhost:8000/projects/proj_abc123/question \
|
|
133
|
+
-H "Content-Type: application/json" \
|
|
134
|
+
-d '{
|
|
135
|
+
"topic": "REST API design",
|
|
136
|
+
"difficulty_level": "intermediate"
|
|
137
|
+
}'
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Process a Response
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
curl -X POST http://localhost:8000/projects/proj_abc123/response \
|
|
144
|
+
-H "Content-Type: application/json" \
|
|
145
|
+
-d '{
|
|
146
|
+
"question_id": "q_xyz789",
|
|
147
|
+
"user_response": "REST APIs should follow resource-oriented design principles...",
|
|
148
|
+
"project_id": "proj_abc123"
|
|
149
|
+
}'
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Generate Code
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
curl -X POST http://localhost:8000/code/generate \
|
|
156
|
+
-H "Content-Type: application/json" \
|
|
157
|
+
-d '{
|
|
158
|
+
"project_id": "proj_abc123",
|
|
159
|
+
"specification": "Create a FastAPI endpoint for user registration",
|
|
160
|
+
"language": "python"
|
|
161
|
+
}'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Python Client Example
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
import requests
|
|
168
|
+
import json
|
|
169
|
+
|
|
170
|
+
BASE_URL = "http://localhost:8000"
|
|
171
|
+
|
|
172
|
+
# Initialize
|
|
173
|
+
resp = requests.post(f"{BASE_URL}/initialize", json={
|
|
174
|
+
"api_key": "sk-ant-..."
|
|
175
|
+
})
|
|
176
|
+
print(resp.json())
|
|
177
|
+
|
|
178
|
+
# Create project
|
|
179
|
+
resp = requests.post(f"{BASE_URL}/projects", json={
|
|
180
|
+
"name": "My Project",
|
|
181
|
+
"owner": "alice",
|
|
182
|
+
"description": "Learning FastAPI"
|
|
183
|
+
})
|
|
184
|
+
project = resp.json()
|
|
185
|
+
project_id = project["project_id"]
|
|
186
|
+
|
|
187
|
+
# Get a question
|
|
188
|
+
resp = requests.post(f"{BASE_URL}/projects/{project_id}/question", json={
|
|
189
|
+
"topic": "FastAPI basics",
|
|
190
|
+
"difficulty_level": "beginner"
|
|
191
|
+
})
|
|
192
|
+
question = resp.json()
|
|
193
|
+
print(f"Question: {question['question']}")
|
|
194
|
+
|
|
195
|
+
# Process response
|
|
196
|
+
resp = requests.post(f"{BASE_URL}/projects/{project_id}/response", json={
|
|
197
|
+
"question_id": question["question_id"],
|
|
198
|
+
"user_response": "FastAPI is a modern Python web framework...",
|
|
199
|
+
"project_id": project_id
|
|
200
|
+
})
|
|
201
|
+
feedback = resp.json()
|
|
202
|
+
print(f"Feedback: {feedback['feedback']}")
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Async Integration Example
|
|
206
|
+
|
|
207
|
+
The API is built with FastAPI and uses asyncio internally. For high-throughput scenarios:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
import asyncio
|
|
211
|
+
import httpx
|
|
212
|
+
|
|
213
|
+
async def main():
|
|
214
|
+
async with httpx.AsyncClient() as client:
|
|
215
|
+
# Initialize
|
|
216
|
+
resp = await client.post("http://localhost:8000/initialize", json={
|
|
217
|
+
"api_key": "sk-ant-..."
|
|
218
|
+
})
|
|
219
|
+
print(resp.json())
|
|
220
|
+
|
|
221
|
+
# Create multiple projects concurrently
|
|
222
|
+
tasks = [
|
|
223
|
+
client.post("http://localhost:8000/projects", json={
|
|
224
|
+
"name": f"Project {i}",
|
|
225
|
+
"owner": "alice"
|
|
226
|
+
})
|
|
227
|
+
for i in range(5)
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
results = await asyncio.gather(*tasks)
|
|
231
|
+
for r in results:
|
|
232
|
+
print(r.json())
|
|
233
|
+
|
|
234
|
+
asyncio.run(main())
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Event Integration
|
|
238
|
+
|
|
239
|
+
The API automatically registers event listeners with the Socrates library. Events are logged and can be monitored via the logging system:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
import logging
|
|
243
|
+
|
|
244
|
+
logging.basicConfig(level=logging.INFO)
|
|
245
|
+
logger = logging.getLogger("socrates_api.main")
|
|
246
|
+
|
|
247
|
+
# API will log events like:
|
|
248
|
+
# [Event] PROJECT_CREATED: {'project_id': 'proj_abc123', ...}
|
|
249
|
+
# [Event] CODE_GENERATED: {'lines': 150, ...}
|
|
250
|
+
# [Event] AGENT_ERROR: {'agent_name': 'code_generator', ...}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Configuration
|
|
254
|
+
|
|
255
|
+
The API respects these environment variables:
|
|
256
|
+
|
|
257
|
+
| Variable | Default | Description |
|
|
258
|
+
|----------|---------|-------------|
|
|
259
|
+
| `ANTHROPIC_API_KEY` | None | Claude API key (required) |
|
|
260
|
+
| `SOCRATES_DATA_DIR` | `~/.socrates` | Directory for storing data |
|
|
261
|
+
| `SOCRATES_API_HOST` | `127.0.0.1` | Server host |
|
|
262
|
+
| `SOCRATES_API_PORT` | `8000` | Server port |
|
|
263
|
+
| `SOCRATES_API_RELOAD` | `false` | Enable auto-reload in development |
|
|
264
|
+
|
|
265
|
+
## Error Handling
|
|
266
|
+
|
|
267
|
+
The API returns structured error responses:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"error": "ProjectNotFoundError",
|
|
272
|
+
"message": "Project 'proj_abc123' not found",
|
|
273
|
+
"error_code": "PROJECT_NOT_FOUND",
|
|
274
|
+
"details": {"project_id": "proj_abc123"}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
All Socrates library errors are caught and returned with appropriate HTTP status codes.
|
|
279
|
+
|
|
280
|
+
## Deployment
|
|
281
|
+
|
|
282
|
+
### Using Gunicorn (Production)
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
pip install gunicorn
|
|
286
|
+
gunicorn -w 4 -k uvicorn.workers.UvicornWorker socrates_api.main:app
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Using Docker
|
|
290
|
+
|
|
291
|
+
```dockerfile
|
|
292
|
+
FROM python:3.11-slim
|
|
293
|
+
|
|
294
|
+
WORKDIR /app
|
|
295
|
+
|
|
296
|
+
RUN pip install socrates-api
|
|
297
|
+
|
|
298
|
+
ENV SOCRATES_API_HOST=0.0.0.0
|
|
299
|
+
|
|
300
|
+
CMD ["socrates-api"]
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
docker build -t socrates-api .
|
|
305
|
+
docker run -e ANTHROPIC_API_KEY="sk-ant-..." -p 8000:8000 socrates-api
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Using Docker Compose
|
|
309
|
+
|
|
310
|
+
```yaml
|
|
311
|
+
version: '3.8'
|
|
312
|
+
|
|
313
|
+
services:
|
|
314
|
+
socrates-api:
|
|
315
|
+
build: .
|
|
316
|
+
ports:
|
|
317
|
+
- "8000:8000"
|
|
318
|
+
environment:
|
|
319
|
+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
320
|
+
SOCRATES_DATA_DIR: /data
|
|
321
|
+
volumes:
|
|
322
|
+
- socrates_data:/data
|
|
323
|
+
|
|
324
|
+
volumes:
|
|
325
|
+
socrates_data:
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Development
|
|
329
|
+
|
|
330
|
+
### Setup
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
git clone https://github.com/Nireus79/Socrates
|
|
334
|
+
cd socrates-api
|
|
335
|
+
pip install -e ".[dev]"
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Run Tests
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
pytest tests/ -v --cov=socrates_api
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Run in Development Mode
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
export SOCRATES_API_RELOAD=true
|
|
348
|
+
socrates-api
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## API Response Examples
|
|
352
|
+
|
|
353
|
+
### Successful Project Creation
|
|
354
|
+
|
|
355
|
+
```json
|
|
356
|
+
{
|
|
357
|
+
"project_id": "proj_abc123",
|
|
358
|
+
"name": "Python API Development",
|
|
359
|
+
"owner": "alice",
|
|
360
|
+
"description": "Building REST APIs with FastAPI",
|
|
361
|
+
"phase": "active",
|
|
362
|
+
"created_at": "2025-12-04T10:00:00Z",
|
|
363
|
+
"updated_at": "2025-12-04T10:30:00Z",
|
|
364
|
+
"is_archived": false
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Successful Question Generation
|
|
369
|
+
|
|
370
|
+
```json
|
|
371
|
+
{
|
|
372
|
+
"question_id": "q_xyz789",
|
|
373
|
+
"question": "What are the main principles of RESTful API design?",
|
|
374
|
+
"context": "You are designing an API for a tutoring system",
|
|
375
|
+
"hints": [
|
|
376
|
+
"Think about resource-oriented design",
|
|
377
|
+
"Consider HTTP methods and status codes"
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Successful Code Generation
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
{
|
|
386
|
+
"code": "@app.post('/api/users/register')\nasync def register_user(user: User):\n # Implementation here",
|
|
387
|
+
"explanation": "This endpoint handles user registration using FastAPI...",
|
|
388
|
+
"language": "python",
|
|
389
|
+
"token_usage": {
|
|
390
|
+
"input_tokens": 150,
|
|
391
|
+
"output_tokens": 200,
|
|
392
|
+
"total_tokens": 350
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Architecture
|
|
398
|
+
|
|
399
|
+
The API is built on three layers:
|
|
400
|
+
|
|
401
|
+
1. **FastAPI Application** (`main.py`) - HTTP request handling, routing, and middleware
|
|
402
|
+
2. **Pydantic Models** (`models.py`) - Request/response validation and serialization
|
|
403
|
+
3. **Socrates Library** - Business logic via `socrates` package
|
|
404
|
+
|
|
405
|
+
Event flow:
|
|
406
|
+
```
|
|
407
|
+
HTTP Request → FastAPI Route → Socrates Library → Event Emission → HTTP Response
|
|
408
|
+
↓
|
|
409
|
+
Event Listeners (Logging)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Monitoring
|
|
413
|
+
|
|
414
|
+
The API emits events for all significant operations. Monitor them via logging:
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
import logging
|
|
418
|
+
logging.basicConfig(level=logging.INFO)
|
|
419
|
+
|
|
420
|
+
# All events will be logged like:
|
|
421
|
+
# [Event] PROJECT_CREATED: {...}
|
|
422
|
+
# [Event] AGENT_COMPLETE: {...}
|
|
423
|
+
# [Event] TOKEN_USAGE: {...}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Or set up custom event listeners by extending the API:
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
def setup_monitoring(orchestrator):
|
|
430
|
+
def on_token_usage(event_type, data):
|
|
431
|
+
# Send to monitoring system
|
|
432
|
+
send_metrics(data)
|
|
433
|
+
|
|
434
|
+
orchestrator.event_emitter.on(socrates.EventType.TOKEN_USAGE, on_token_usage)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## Support
|
|
438
|
+
|
|
439
|
+
For issues, feature requests, or contributions, visit:
|
|
440
|
+
- GitHub: https://github.com/Nireus79/Socrates
|
|
441
|
+
- Issues: https://github.com/Nireus79/Socrates/issues
|
|
442
|
+
- Documentation: https://socrates-ai.readthedocs.io
|
|
443
|
+
|
|
444
|
+
## License
|
|
445
|
+
|
|
446
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
socrates_api/__init__.py,sha256=tTlDYmdp0cBdwyuMhyejW1zoXwB6Rp-O2PM3bTTYGLg,350
|
|
2
|
+
socrates_api/database.py,sha256=8iajRBwFYCERNFxKhR-j6O42v7TPOFUSps_MES82p0c,3524
|
|
3
|
+
socrates_api/main.py,sha256=kZP2RLLJWd5DCLoCO4CRu9HUQjj2-EPK2CdKOnyDUQA,28762
|
|
4
|
+
socrates_api/models.py,sha256=a65fxK4_AItW0BX7UTLJ7EjnOh2nnAeZdwKJLbZzttA,33098
|
|
5
|
+
socrates_api/monitoring.py,sha256=ASHdvIY3cfxrjzR9c5TMyrrRNJxtx96damcAt0Py77E,7436
|
|
6
|
+
socrates_api/testing_mode.py,sha256=2XOHoBQmddzbQqnP7NxlqsB5kIXZqeplyjIc5TJSpNo,2124
|
|
7
|
+
socrates_ai_api-1.3.0.dist-info/METADATA,sha256=5ZgJBrBlCbE9wq_ONh78PVYLIyOnZKeiLqXXtn03y-Y,11185
|
|
8
|
+
socrates_ai_api-1.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
+
socrates_ai_api-1.3.0.dist-info/entry_points.txt,sha256=NcpMmQfZl4AtovX68-rcj86nLeqgnHRt1_X1XL7qDeA,55
|
|
10
|
+
socrates_ai_api-1.3.0.dist-info/top_level.txt,sha256=U_unXaqUsRAcq2XypQQrO6ZIjSsMw67BL2hD5c1L9bE,13
|
|
11
|
+
socrates_ai_api-1.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
socrates_api
|
socrates_api/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Socrates API - REST API server for Socrates AI
|
|
3
|
+
|
|
4
|
+
A FastAPI-based REST API that provides access to the Socrates AI tutoring system.
|
|
5
|
+
Enables integration with web frontends, mobile apps, and custom clients.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.5.0"
|
|
9
|
+
__author__ = "Socrates AI Contributors"
|
|
10
|
+
__license__ = "MIT"
|
|
11
|
+
|
|
12
|
+
__all__ = ["__version__", "__author__", "__license__"]
|
socrates_api/database.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified database singleton for both CLI and API.
|
|
3
|
+
|
|
4
|
+
This module provides the DatabaseSingleton class that ensures both CLI
|
|
5
|
+
(orchestrator) and API use the same database instance, preventing data
|
|
6
|
+
corruption from dual database access.
|
|
7
|
+
|
|
8
|
+
All components should use DatabaseSingleton.get_instance() to access the database.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from socratic_system.database import ProjectDatabase
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DatabaseSingleton:
|
|
21
|
+
"""
|
|
22
|
+
Unified database singleton for CLI + API.
|
|
23
|
+
|
|
24
|
+
Ensures both the orchestrator and API use the same database instance,
|
|
25
|
+
preventing data inconsistencies from accessing different databases.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
_instance: ProjectDatabase = None
|
|
29
|
+
_db_path: str = None
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def initialize(cls, db_path: str = None) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Initialize the database singleton with a specific path.
|
|
35
|
+
|
|
36
|
+
Should be called once at application startup (before get_instance is used).
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
db_path: Path to projects.db. If None, uses environment or default.
|
|
40
|
+
"""
|
|
41
|
+
if db_path:
|
|
42
|
+
cls._db_path = db_path
|
|
43
|
+
else:
|
|
44
|
+
# Get from environment or use default
|
|
45
|
+
data_dir = os.getenv("SOCRATES_DATA_DIR", str(Path.home() / ".socrates"))
|
|
46
|
+
Path(data_dir).mkdir(parents=True, exist_ok=True)
|
|
47
|
+
cls._db_path = os.path.join(data_dir, "projects.db")
|
|
48
|
+
|
|
49
|
+
# Reset instance so next get_instance() call creates new one with new path
|
|
50
|
+
cls._instance = None
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def get_instance(cls) -> ProjectDatabase:
|
|
54
|
+
"""
|
|
55
|
+
Get or create the global database instance.
|
|
56
|
+
|
|
57
|
+
This is used by both CLI (orchestrator) and API to ensure
|
|
58
|
+
they access the same database.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
ProjectDatabase: The shared database instance
|
|
62
|
+
"""
|
|
63
|
+
if cls._instance is None:
|
|
64
|
+
# Initialize path if not already done
|
|
65
|
+
if cls._db_path is None:
|
|
66
|
+
cls.initialize()
|
|
67
|
+
|
|
68
|
+
# Create database instance
|
|
69
|
+
try:
|
|
70
|
+
cls._instance = ProjectDatabase(cls._db_path)
|
|
71
|
+
logger.info(f"Database singleton initialized at {cls._db_path}")
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.error(f"Failed to initialize database: {e}")
|
|
74
|
+
raise
|
|
75
|
+
|
|
76
|
+
return cls._instance
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def reset(cls) -> None:
|
|
80
|
+
"""Reset the singleton (for testing purposes)"""
|
|
81
|
+
cls._instance = None
|
|
82
|
+
cls._db_path = None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# FastAPI dependency that uses the singleton
|
|
86
|
+
def get_database() -> ProjectDatabase:
|
|
87
|
+
"""
|
|
88
|
+
FastAPI dependency that gets the shared database instance.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
ProjectDatabase: The shared database instance from DatabaseSingleton
|
|
92
|
+
"""
|
|
93
|
+
return DatabaseSingleton.get_instance()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def close_database() -> None:
|
|
97
|
+
"""
|
|
98
|
+
Close the global database connection.
|
|
99
|
+
|
|
100
|
+
This should be called during application shutdown to properly clean up
|
|
101
|
+
database connections.
|
|
102
|
+
"""
|
|
103
|
+
# DatabaseSingleton.reset() clears the cached instance
|
|
104
|
+
try:
|
|
105
|
+
DatabaseSingleton.reset()
|
|
106
|
+
logger.info("Database connection closed")
|
|
107
|
+
except Exception as e:
|
|
108
|
+
logger.error(f"Error closing database: {e}")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def reset_database() -> None:
|
|
112
|
+
"""
|
|
113
|
+
Reset the database instance (mainly for testing).
|
|
114
|
+
|
|
115
|
+
This closes the current connection and clears the cached instance,
|
|
116
|
+
forcing a new connection to be created on the next request.
|
|
117
|
+
"""
|
|
118
|
+
close_database()
|