|
|
|
|
|
import os |
|
|
import httpx |
|
|
from dotenv import load_dotenv |
|
|
from typing import Dict, Optional, List |
|
|
from fastapi import HTTPException |
|
|
load_dotenv() |
|
|
|
|
|
SUPABASE_URL = os.getenv("SUPABASE_URL").rstrip("/") |
|
|
SUPABASE_KEY = os.getenv("SUPABASE_KEY") |
|
|
database_service_Key = os.getenv("database_service_Key") |
|
|
TABLE = os.getenv("TABLE_NAME", "idioms") |
|
|
|
|
|
HEADERS = { |
|
|
"apikey": database_service_Key, |
|
|
"Authorization": f"Bearer {database_service_Key}", |
|
|
"Content-Type": "application/json", |
|
|
"Accept": "application/json", |
|
|
} |
|
|
|
|
|
|
|
|
async def _client(): |
|
|
return httpx.AsyncClient(timeout=30.0) |
|
|
|
|
|
|
|
|
async def get_idioms(skip: int = 0, limit: int = 100000): |
|
|
async with httpx.AsyncClient() as client: |
|
|
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?select=*&offset={skip}&limit={limit}" |
|
|
print("Supabase GET URL:", url) |
|
|
r = await client.get(url, headers=HEADERS) |
|
|
print("Supabase GET status:", r.status_code) |
|
|
print("Supabase GET response:", r.text) |
|
|
r.raise_for_status() |
|
|
return r.json() |
|
|
|
|
|
async def get_all_idioms(): |
|
|
all_idioms = [] |
|
|
limit = 1000 |
|
|
offset = 0 |
|
|
|
|
|
async with httpx.AsyncClient(timeout=60.0) as client: |
|
|
while True: |
|
|
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?select=*&limit={limit}&offset={offset}" |
|
|
r = await client.get(url, headers=HEADERS) |
|
|
r.raise_for_status() |
|
|
data = r.json() |
|
|
if not data: |
|
|
break |
|
|
|
|
|
for item in data: |
|
|
if not isinstance(item.get("validation_count"), dict): |
|
|
item["validation_count"] = {} |
|
|
all_idioms.extend(data) |
|
|
offset += limit |
|
|
|
|
|
return all_idioms |
|
|
|
|
|
async def get_idiom(idiom_id: str): |
|
|
async with httpx.AsyncClient() as client: |
|
|
try: |
|
|
|
|
|
url = ( |
|
|
f"{SUPABASE_URL}/rest/v1/{TABLE}?" |
|
|
f"id=eq.{idiom_id}&" |
|
|
f"select=*," |
|
|
f"idiom_meanings!idiom_meanings_idiom_id_fkey(*)," |
|
|
f"examples!examples_idiom_id_fkey(*)" |
|
|
|
|
|
) |
|
|
print(f"Fetching idiom from Supabase: {url}") |
|
|
r = await client.get(url, headers=HEADERS) |
|
|
print("HTTP status code:", r.status_code) |
|
|
r.raise_for_status() |
|
|
data = r.json() |
|
|
print("Raw data from Supabase:", data) |
|
|
except httpx.RequestError as e: |
|
|
print("Request failed:", e) |
|
|
raise HTTPException(status_code=500, detail=f"Supabase request failed: {e}") |
|
|
except httpx.HTTPStatusError as e: |
|
|
print("HTTP error:", e) |
|
|
raise HTTPException(status_code=500, detail=f"Supabase HTTP error: {e}") |
|
|
except Exception as e: |
|
|
print("Unexpected error:", e) |
|
|
raise HTTPException(status_code=500, detail=f"Unexpected error: {e}") |
|
|
|
|
|
if not data: |
|
|
print(f"No idiom found for id: {idiom_id}") |
|
|
return None |
|
|
|
|
|
idiom = data[0] |
|
|
if not isinstance(idiom, dict): |
|
|
print(f"Unexpected data type for idiom: {type(idiom)}") |
|
|
raise ValueError(f"Expected dict, got: {type(idiom)}") |
|
|
|
|
|
|
|
|
raw_examples = idiom.get("examples") or [] |
|
|
idiom["examples"] = [ |
|
|
{ |
|
|
"id": ex.get("id"), |
|
|
"source_text": ex.get("source_text") or "", |
|
|
"source_language": ex.get("source_language") or idiom.get("language"), |
|
|
"translations": json.loads(ex["translations"]) if isinstance(ex.get("translations"), str) else ex.get("translations") or [], |
|
|
"dialect": ex.get("dialect"), |
|
|
"url": ex.get("url"), |
|
|
"source": ex.get("source"), |
|
|
} |
|
|
for ex in raw_examples |
|
|
] |
|
|
print(f"Found {len(idiom['examples'])} examples") |
|
|
|
|
|
|
|
|
raw_meanings = idiom.get("idiom_meanings") or [] |
|
|
print("Raw meanings data:", raw_meanings) |
|
|
idiom["meanings"] = [ |
|
|
{ |
|
|
"meaning_id": m.get("meaning_id"), |
|
|
"idiom_id": m.get("idiom_id"), |
|
|
"sense_number": m.get("sense_number"), |
|
|
"register": m.get("register") or [], |
|
|
"region": m.get("region") or [], |
|
|
"definitions": m.get("definitions") or [], |
|
|
"version": m.get("version"), |
|
|
} |
|
|
for m in raw_meanings |
|
|
] |
|
|
print("Transformed meanings data:", idiom["meanings"]) |
|
|
print(f"Found {len(idiom['meanings'])} meanings") |
|
|
return idiom |
|
|
|
|
|
|
|
|
|
|
|
async def search_idioms(query: str = "", language: Optional[str] = None, skip: int = 0, limit: int = 50): |
|
|
async with httpx.AsyncClient() as client: |
|
|
|
|
|
select_query = "*,idiom_meanings!idiom_meanings_idiom_id_fkey(*)" |
|
|
|
|
|
url = ( |
|
|
f"{SUPABASE_URL}/rest/v1/{TABLE}" |
|
|
f"?offset={skip}&limit={limit}&select={select_query}" |
|
|
) |
|
|
|
|
|
|
|
|
if query: |
|
|
url += f"&idiom=ilike.*{query}*" |
|
|
|
|
|
|
|
|
if language and language.lower() not in ("all", "*"): |
|
|
url += f"&language=eq.{language}" |
|
|
|
|
|
r = await client.get(url, headers=HEADERS) |
|
|
r.raise_for_status() |
|
|
data = r.json() |
|
|
|
|
|
|
|
|
for item in data: |
|
|
if not isinstance(item.get("validation_count"), dict): |
|
|
item["validation_count"] = {} |
|
|
|
|
|
|
|
|
raw_meanings = item.get("idiom_meanings") or [] |
|
|
item["meanings"] = [ |
|
|
{ |
|
|
"meaning_id": m.get("meaning_id"), |
|
|
"idiom_id": m.get("idiom_id"), |
|
|
"sense_number": m.get("sense_number"), |
|
|
"register": m.get("register") or [], |
|
|
"region": m.get("region") or [], |
|
|
"definitions": m.get("definitions") or [], |
|
|
"version": m.get("version"), |
|
|
} |
|
|
for m in raw_meanings |
|
|
] |
|
|
|
|
|
return data |
|
|
|
|
|
|
|
|
|
|
|
async def create_idiom(item: dict): |
|
|
async with httpx.AsyncClient() as client: |
|
|
url = f"{SUPABASE_URL}/rest/v1/{TABLE}" |
|
|
r = await client.post(url, json=item, headers=HEADERS) |
|
|
r.raise_for_status() |
|
|
|
|
|
try: |
|
|
data = r.json() |
|
|
except ValueError: |
|
|
|
|
|
data = item |
|
|
|
|
|
if isinstance(data, list) and data: |
|
|
return data[0] |
|
|
if isinstance(data, dict) and data: |
|
|
return data |
|
|
|
|
|
return item |
|
|
async def update_idiom(idiom_id: str, item: dict): |
|
|
async with httpx.AsyncClient() as client: |
|
|
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?id=eq.{idiom_id}" |
|
|
r = await client.patch(url, json=item, headers=HEADERS) |
|
|
if r.status_code not in (200, 204): |
|
|
raise httpx.HTTPStatusError("Update failed", request=r.request, response=r) |
|
|
|
|
|
return await get_idiom(idiom_id) |
|
|
|
|
|
async def delete_idiom(idiom_id: str): |
|
|
async with httpx.AsyncClient() as client: |
|
|
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?id=eq.{idiom_id}" |
|
|
r = await client.delete(url, headers=HEADERS) |
|
|
if r.status_code not in (200, 204): |
|
|
raise httpx.HTTPStatusError("Delete failed", request=r.request, response=r) |
|
|
return {"status": "deleted"} |
|
|
|