Research-Stack/2-Search-Space/manifold/api/server.py

838 lines
24 KiB
Python

#!/usr/bin/env python3
"""
Manifold Surface API Server
Provides REST API for manifold navigation interface
"""
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Optional
import sqlite3
import json
import numpy as np
import sys
import os
# Add parent directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from projection_engine import ProjectionEngine, ConceptVector14, ProjectionMethod
from soliton_search import SolitonSearchEngine
from collapse_editor import CollapseEditor, StateType
from particle_interaction import ParticleInteractionEngine, ParticleType
from self_typing_engine import SelfTypingEngine, InteractionType
from relativity_adapter import RelativityAdapter, CognitiveLoadLevel
from substrate_bridge import SubstrateBridge
app = FastAPI(title="Manifold Surface API")
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Database path
DB_PATH = "/home/allaun/Documents/Research Stack/data/substrate_index.db"
# Global projection engine
projection_engine = None
soliton_engine = None
collapse_editor = CollapseEditor()
particle_engine = ParticleInteractionEngine()
self_typing_engine = SelfTypingEngine()
relativity_adapter = RelativityAdapter()
substrate_bridge = SubstrateBridge(DB_PATH)
class VectorData(BaseModel):
vectors: List[List[float]]
archive_ids: List[str]
class ProjectionRequest(BaseModel):
vectors: List[List[float]]
archive_ids: List[str]
method: str = "PCA"
slice_axis_x: int = 3
slice_axis_y: int = 4
class ProjectionResponse(BaseModel):
points: List[dict]
projection_matrix: List[List[float]]
mean_vector: List[float]
def get_db_connection():
"""Get database connection"""
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def load_concept_vectors_from_ene() -> List[ConceptVector14]:
"""Load concept vectors from ENE database"""
vectors = []
try:
conn = get_db_connection()
cursor = conn.cursor()
# Query concept vectors from packages table
cursor.execute("""
SELECT archive_id, concept_vector_14
FROM packages
WHERE concept_vector_14 IS NOT NULL
""")
for row in cursor.fetchall():
archive_id = row['archive_id']
vector_str = row['concept_vector_14']
try:
# Parse vector string (assuming JSON format)
vector_data = json.loads(vector_str)
vector = np.array(vector_data, dtype=np.float32)
if len(vector) != 14:
continue # Skip invalid vectors
vectors.append(ConceptVector14(vector=vector, archive_id=archive_id))
except (json.JSONDecodeError, ValueError) as e:
print(f"Error parsing vector for {archive_id}: {e}")
continue
conn.close()
except Exception as e:
print(f"Error loading concept vectors: {e}")
return vectors
@app.get("/health")
def health_check():
"""Health check endpoint"""
return {"status": "ok", "service": "manifold-surface-api"}
@app.get("/api/load-concept-vectors")
def load_concept_vectors():
"""Load concept vectors from ENE database"""
global projection_engine
try:
vectors = load_concept_vectors_from_ene()
if not vectors:
return {"vectors": [], "count": 0}
# Initialize projection engine
projection_engine = ProjectionEngine(method=ProjectionMethod.PCA)
# Fit and transform
projected = projection_engine.fit_transform(vectors)
# Convert to response format
vector_data = [v.vector.tolist() for v in vectors]
archive_ids = [v.archive_id for v in vectors]
return {
"vectors": vector_data,
"archive_ids": archive_ids,
"count": len(vectors),
"projection_matrix": projection_engine._projection_matrix.tolist() if projection_engine._projection_matrix is not None else [],
"mean_vector": projection_engine._mean.tolist() if projection_engine._mean is not None else []
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/project")
def project_vectors(request: ProjectionRequest):
"""Project vectors using specified method"""
global projection_engine
try:
# Convert to ConceptVector14 objects
vectors = [
ConceptVector14(vector=np.array(v, dtype=np.float32), archive_id=aid)
for v, aid in zip(request.vectors, request.archive_ids)
]
# Create projection engine with specified method
method_map = {
"PCA": ProjectionMethod.PCA,
"tSNE": ProjectionMethod.T_SNE,
"UMAP": ProjectionMethod.UMAP,
"ManifoldChart": ProjectionMethod.MANIFOLD_CHART
}
method = method_map.get(request.method, ProjectionMethod.PCA)
projection_engine = ProjectionEngine(method=method)
# Fit and transform
projected = projection_engine.fit_transform(vectors)
# Convert to response format
points = [p.to_dict() for p in projected]
return {
"points": points,
"projection_matrix": projection_engine._projection_matrix.tolist() if projection_engine._projection_matrix is not None else [],
"mean_vector": projection_engine._mean.tolist() if projection_engine._mean is not None else []
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
class SolitonSearchRequest(BaseModel):
query_vector: List[float]
max_results: int = 10
class CreateSuperpositionRequest(BaseModel):
initial_content: str
state_type: str = "text"
class AddStateRequest(BaseModel):
superposition_id: str
branch_id: str
content: str
state_type: str = "text"
class CreateBranchRequest(BaseModel):
superposition_id: str
parent_branch_id: Optional[str] = None
content: str = ""
state_type: str = "text"
class CollapseRequest(BaseModel):
superposition_id: str
branch_id: str
class CreateParticleRequest(BaseModel):
particle_type: str
position: Tuple[float, float]
velocity: Tuple[float, float] = (0.0, 0.0)
class EmitPhotonRequest(BaseModel):
from_particle_id: str
to_particle_id: str
class AbsorbPhotonRequest(BaseModel):
photon_id: str
target_particle_id: str
class RecordInteractionRequest(BaseModel):
interaction_type: str
source_layer: str
target_layer: str
context: Optional[Dict[str, str]] = None
class InferMetatypeRequest(BaseModel):
context: Dict[str, str]
class MeasureCognitiveLoadRequest(BaseModel):
information_density: float
complexity: float
novelty: float
uncertainty: float
class TransformRequest(BaseModel):
input_vector: List[float]
from_topology: Optional[str] = None
to_topology: Optional[str] = None
@app.post("/api/soliton-search")
def soliton_search(request: SolitonSearchRequest):
"""Search using soliton propagation with AVMR O(√N) indexing"""
global soliton_engine
try:
# Load vectors if not already loaded
if soliton_engine is None:
vectors = load_concept_vectors_from_ene()
if not vectors:
return {"results": [], "count": 0}
vector_data = [v.vector.tolist() for v in vectors]
archive_ids = [v.archive_id for v in vectors]
soliton_engine = SolitonSearchEngine(vector_data, archive_ids)
# Perform search
query = np.array(request.query_vector, dtype=np.float32)
results = soliton_engine.search(query, max_results=request.max_results)
return {
"results": [{"archive_id": aid, "confidence": conf} for aid, conf in results],
"count": len(results)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/superposition/create")
def create_superposition(request: CreateSuperpositionRequest):
"""Create new superposition with single branch"""
global collapse_editor
try:
state_type = StateType[request.state_type.upper()]
superposition = collapse_editor.create_superposition(request.initial_content, state_type)
return {
"superposition_id": superposition.superposition_id,
"current_branch_id": superposition.current_branch_id,
"branches": len(superposition.branches)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/superposition/add-state")
def add_state_to_branch(request: AddStateRequest):
"""Add new state to existing branch"""
global collapse_editor
try:
state_type = StateType[request.state_type.upper()]
collapse_editor.add_state_to_branch(
request.superposition_id,
request.branch_id,
request.content,
state_type
)
return {"status": "ok"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/superposition/create-branch")
def create_branch(request: CreateBranchRequest):
"""Create new branch in superposition"""
global collapse_editor
try:
state_type = StateType[request.state_type.upper()]
branch = collapse_editor.create_branch(
request.superposition_id,
request.parent_branch_id,
request.content,
state_type
)
return {
"branch_id": branch.branch_id,
"amplitude": branch.amplitude,
"states": len(branch.states)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/superposition/collapse")
def collapse_superposition(request: CollapseRequest):
"""Collapse superposition to observable state"""
global collapse_editor
try:
observable = collapse_editor.collapse(request.superposition_id, request.branch_id)
return {
"archive_id": observable.archive_id,
"witness_hash": observable.witness_hash,
"collapsed_at": observable.collapsed_at.isoformat()
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/superposition/{superposition_id}/branches")
def get_superposition_branches(superposition_id: str):
"""Get all branches for superposition"""
global collapse_editor
try:
branches = collapse_editor.get_branches(superposition_id)
return {
"branches": [
{
"branch_id": b.branch_id,
"amplitude": b.amplitude,
"states": len(b.states),
"parent_branch_id": b.parent_branch_id
}
for b in branches
]
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/superposition/{superposition_id}/tree")
def get_branch_tree(superposition_id: str):
"""Get branch tree structure for visualization"""
global collapse_editor
try:
tree = collapse_editor.get_branch_tree(superposition_id)
return {"tree": tree}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/collapse-editor/undo")
def undo_collapse():
"""Revert to previous observable state"""
global collapse_editor
try:
previous_state = collapse_editor.undo()
if previous_state is None:
return {"status": "no_undo_available"}
return {
"archive_id": previous_state.archive_id,
"witness_hash": previous_state.witness_hash
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/collapse-editor/witnesses")
def get_witness_history():
"""Get all witness records"""
global collapse_editor
try:
witnesses = collapse_editor.get_witness_history()
return {
"witnesses": [
{
"witness_hash": w.witness_hash,
"superposition_id": w.superposition_id,
"collapsed_branch_id": w.collapsed_branch_id,
"timestamp": w.timestamp.isoformat()
}
for w in witnesses
],
"count": len(witnesses)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/particle/create")
def create_particle(request: CreateParticleRequest):
"""Create new particle"""
global particle_engine
try:
particle_type = ParticleType[request.particle_type.upper()]
particle = particle_engine.create_particle(
particle_type,
request.position,
request.velocity
)
return particle.to_dict()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/particle/emit-photon")
def emit_photon(request: EmitPhotonRequest):
"""Emit photon from one particle to another"""
global particle_engine
try:
interaction = particle_engine.emit_photon(request.from_particle_id, request.to_particle_id)
return {
"interaction_id": len(particle_engine.interactions),
"from_particle_id": interaction.from_particle_id,
"to_particle_id": interaction.to_particle_id,
"interaction_type": interaction.interaction_type,
"energy_transfer": interaction.energy_transfer
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/particle/absorb-photon")
def absorb_photon(request: AbsorbPhotonRequest):
"""Absorb photon by target particle"""
global particle_engine
try:
interaction = particle_engine.absorb_photon(request.photon_id, request.target_particle_id)
return {
"interaction_id": len(particle_engine.interactions),
"from_particle_id": interaction.from_particle_id,
"to_particle_id": interaction.to_particle_id,
"interaction_type": interaction.interaction_type,
"energy_transfer": interaction.energy_transfer
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/particle/detect-neutrino/{particle_id}")
def detect_neutrino(particle_id: str):
"""Attempt to detect neutrino (weakly-interacting inference)"""
global particle_engine
try:
detected = particle_engine.detect_neutrino(particle_id)
return {"detected": detected}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/particle/update")
def update_particles():
"""Update particle positions and velocities"""
global particle_engine
try:
particle_engine.update()
return {"time": particle_engine.time}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/particle/conservation")
def check_conservation():
"""Check all conservation laws"""
global particle_engine
try:
conservation = particle_engine.check_conservation()
return conservation
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/particle/graph")
def get_interaction_graph():
"""Get interaction graph for visualization"""
global particle_engine
try:
graph = particle_engine.get_interaction_graph()
return graph
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/particle/type/{particle_type}")
def get_particles_by_type(particle_type: str):
"""Get all particles of specific type"""
global particle_engine
try:
ptype = ParticleType[particle_type.upper()]
particles = particle_engine.get_particles_by_type(ptype)
return {
"particles": [p.to_dict() for p in particles],
"count": len(particles)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/self-typing/record-interaction")
def record_interaction(request: RecordInteractionRequest):
"""Record interaction between layers"""
global self_typing_engine
try:
interaction_type = InteractionType[request.interaction_type.upper()]
interaction = self_typing_engine.record_interaction(
interaction_type,
request.source_layer,
request.target_layer,
request.context
)
return {
"interaction_id": interaction.interaction_id,
"interaction_type": interaction.interaction_type.value,
"source_layer": interaction.source_layer,
"target_layer": interaction.target_layer,
"timestamp": interaction.timestamp.isoformat()
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/self-typing/infer-metatype")
def infer_metatype(request: InferMetatypeRequest):
"""Infer metatype from interaction patterns"""
global self_typing_engine
try:
metatype = self_typing_engine.infer_metatype(request.context)
return {
"metatype_id": metatype.metatype_id,
"type_signature": metatype.type_signature,
"confidence": metatype.confidence,
"suggestions": metatype.suggestions,
"created_at": metatype.created_at.isoformat()
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/self-typing/interactions")
def get_interaction_history(limit: int = 100):
"""Get recent interaction history"""
global self_typing_engine
try:
interactions = self_typing_engine.get_interaction_history(limit)
return {
"interactions": [
{
"interaction_id": i.interaction_id,
"interaction_type": i.interaction_type.value,
"source_layer": i.source_layer,
"target_layer": i.target_layer,
"timestamp": i.timestamp.isoformat()
}
for i in interactions
],
"count": len(interactions)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/self-typing/statistics")
def get_type_statistics():
"""Get statistics about type inference"""
global self_typing_engine
try:
stats = self_typing_engine.get_type_statistics()
return stats
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/relativity/measure-cognitive-load")
def measure_cognitive_load(request: MeasureCognitiveLoadRequest):
"""Measure cognitive load"""
global relativity_adapter
try:
load_vector = relativity_adapter.measure_cognitive_load(
request.information_density,
request.complexity,
request.novelty,
request.uncertainty
)
return {
"level": load_vector.get_level().value,
"information_density": load_vector.information_density,
"complexity": load_vector.complexity,
"novelty": load_vector.novelty,
"uncertainty": load_vector.uncertainty,
"timestamp": load_vector.timestamp
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/relativity/adapt-topology")
def adapt_topology(request: MeasureCognitiveLoadRequest):
"""Adapt topology based on cognitive load"""
global relativity_adapter
try:
load_vector = relativity_adapter.measure_cognitive_load(
request.information_density,
request.complexity,
request.novelty,
request.uncertainty
)
topology = relativity_adapter.adapt_topology(load_vector)
return {
"topology_id": topology.topology_id,
"distance_metric": topology.distance_metric,
"cognitive_load_level": topology.cognitive_load_level.value
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/relativity/transform")
def transform_coordinates(request: TransformRequest):
"""Transform coordinates between topologies"""
global relativity_adapter
try:
input_vector = np.array(request.input_vector, dtype=np.float32)
transformed = relativity_adapter.transform(
input_vector,
request.from_topology,
request.to_topology
)
return {
"transformed_vector": transformed.tolist(),
"from_topology": request.from_topology,
"to_topology": request.to_topology
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/relativity/enable-dolphin-mode")
def enable_dolphin_mode():
"""Enable dolphin mode (non-Euclidean visualization)"""
global relativity_adapter
try:
relativity_adapter.enable_dolphin_mode()
return {
"status": "dolphin_mode_enabled",
"current_topology": relativity_adapter.current_topology.topology_id if relativity_adapter.current_topology else None
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/relativity/cognitive-load-history")
def get_cognitive_load_history(limit: int = 100):
"""Get cognitive load history"""
global relativity_adapter
try:
history = relativity_adapter.get_cognitive_load_history(limit)
return {
"history": [
{
"level": h.get_level().value,
"information_density": h.information_density,
"complexity": h.complexity,
"novelty": h.novelty,
"uncertainty": h.uncertainty,
"timestamp": h.timestamp
}
for h in history
],
"count": len(history)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/relativity/statistics")
def get_topology_statistics():
"""Get topology statistics"""
global relativity_adapter
try:
stats = relativity_adapter.get_topology_statistics()
return stats
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/stats")
def get_stats():
"""Get database statistics"""
try:
conn = get_db_connection()
cursor = conn.cursor()
# Count total packages
cursor.execute("SELECT COUNT(*) as count FROM packages")
total_count = cursor.fetchone()['count']
# Count packages with concept vectors
cursor.execute("SELECT COUNT(*) as count FROM packages WHERE concept_vector_14 IS NOT NULL")
vector_count = cursor.fetchone()['count']
conn.close()
return {
"total_packages": total_count,
"packages_with_vectors": vector_count,
"coverage": vector_count / total_count if total_count > 0 else 0
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
import uvicorn
print("Starting Manifold Surface API Server...")
print(f"Database: {DB_PATH}")
uvicorn.run(app, host="0.0.0.0", port=8000)