| import os, io, json, re, requests, httpx |
| from fastapi import FastAPI, Request, HTTPException, Body, Depends |
| from fastapi.responses import StreamingResponse, RedirectResponse |
| from fastapi.templating import Jinja2Templates |
| from datetime import datetime |
| from .engine import PrecisionEngine |
| from pydantic import BaseModel, Field, field_validator |
| from typing import Optional |
|
|
| app = FastAPI() |
| templates = Jinja2Templates(directory="app/templates") |
| engine = PrecisionEngine() |
|
|
| class BirthDataInput(BaseModel): |
| name: str = Field(..., min_length=2, max_length=100) |
| date: str = Field(..., pattern=r'^\d{4}-\d{2}-\d{2}$') |
| time: str = Field(..., pattern=r'^\d{2}:\d{2}$') |
| city: str = Field(..., min_length=2, max_length=100) |
| state: str = Field(..., min_length=2, max_length=50) |
|
|
| @field_validator('name') |
| def validate_name(cls, v): |
| if not re.match(r'^[a-zA-Z\s]+$', v): |
| raise ValueError('Name must contain only letters and spaces') |
| return v.strip() |
|
|
| def get_coordinates(city, state): |
| try: |
| url = f"https://nominatim.openstreetmap.org/search?city={city}&state={state}&format=json" |
| headers = {'User-Agent': 'DefragPrecisionEngine/1.0'} |
| response = requests.get(url, headers=headers, timeout=5) |
| if response.status_code == 200 and len(response.json()) > 0: |
| data = response.json()[0] |
| return {"lat": float(data['lat']), "lon": float(data['lon'])} |
| except: pass |
| return {"lat": 34.1064, "lon": -117.5931} |
|
|
| def reduce_number(n): |
| while n > 9 and n not in [11, 22, 33]: |
| n = sum(int(d) for d in str(n)) |
| return n |
|
|
| def calculate_life_path(date_str: str) -> int: |
| y, m, d = date_str.split('-') |
| y_red = reduce_number(sum(int(digit) for digit in y)) |
| m_red = reduce_number(sum(int(digit) for digit in m)) |
| d_red = reduce_number(sum(int(digit) for digit in d)) |
| return reduce_number(y_red + m_red + d_red) |
|
|
| @app.get("/") |
| async def index(request: Request): |
| return templates.TemplateResponse("dashboard.html", {"request": request}) |
|
|
| @app.get("/api/get-signed-url") |
| async def get_signed_url(): |
| ELEVENLABS_API_KEY = os.environ.get("ELEVENLABS_API_KEY") |
| AGENT_ID = "agent_4101kfyny563e168da90yze4vva4" |
| async with httpx.AsyncClient() as client: |
| response = await client.get( |
| f"https://api.elevenlabs.io/v1/convai/conversation/get_signed_url?agent_id={AGENT_ID}", |
| headers={"xi-api-key": ELEVENLABS_API_KEY} |
| ) |
| if response.status_code != 200: |
| raise HTTPException(status_code=500, detail="Failed to get signed URL") |
| return response.json() |
|
|
| @app.post("/v1/analyze/clinical") |
| async def clinical_analysis(data: BirthDataInput): |
| coords = get_coordinates(data.city, data.state) |
| natal_dt = datetime.fromisoformat(f"{data.date}T{data.time}") |
| engine_data = engine.calculate_chart(natal_dt, {"latitude": coords['lat'], "longitude": coords['lon']}) |
| life_path = calculate_life_path(data.date) |
| zodiac = ['Aries', 'Taurus', 'Gemini', 'Cancer', 'Leo', 'Virgo', 'Libra', 'Scorpio', 'Sagittarius', 'Capricorn', 'Aquarius', 'Pisces'] |
| planets_rich = {n: {"longitude": round(p.longitude, 4), "gate": p.gate, "line": p.line, "sign": zodiac[int(p.longitude / 30) % 12]} for n, p in engine_data.items()} |
| sun_sign = planets_rich.get('Sun', {}).get('sign', 'Unknown') |
| return { |
| "synthesis": f"Natal Profile: {data.name}. Alignment secured at {coords['lat']:.2f}, {coords['lon']:.2f}.", |
| "planets": planets_rich, |
| "numerology": {"life_path_number": life_path, "sun_sign": sun_sign} |
| } |
|
|