Commit ·
08ee52a
1
Parent(s): 1b12d0c
Real gateway: chat completions + Drive storage
Browse files- Dockerfile +14 -0
- app.py +73 -0
- requirements.txt +7 -0
Dockerfile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.10
|
| 2 |
+
|
| 3 |
+
RUN useradd -m -u 1000 user
|
| 4 |
+
USER user
|
| 5 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
| 6 |
+
|
| 7 |
+
WORKDIR /app
|
| 8 |
+
|
| 9 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
| 10 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 11 |
+
|
| 12 |
+
COPY --chown=user . /app
|
| 13 |
+
|
| 14 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
app.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI, UploadFile, File
|
| 2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
+
import httpx, io, json, os
|
| 4 |
+
from googleapiclient.discovery import build
|
| 5 |
+
from googleapiclient.http import MediaIoBaseUpload
|
| 6 |
+
from google.oauth2 import service_account
|
| 7 |
+
|
| 8 |
+
app = FastAPI()
|
| 9 |
+
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
|
| 10 |
+
|
| 11 |
+
DRIVE_FOLDER_ID = os.environ.get("DRIVE_FOLDER_ID", "")
|
| 12 |
+
_creds = None
|
| 13 |
+
drive = None
|
| 14 |
+
|
| 15 |
+
def get_drive():
|
| 16 |
+
global _creds, drive
|
| 17 |
+
if drive is None:
|
| 18 |
+
_creds = service_account.Credentials.from_service_account_info(
|
| 19 |
+
json.loads(os.environ["GOOGLE_SERVICE_ACCOUNT_JSON"]),
|
| 20 |
+
scopes=["https://www.googleapis.com/auth/drive"]
|
| 21 |
+
)
|
| 22 |
+
drive = build("drive", "v3", credentials=_creds)
|
| 23 |
+
return drive
|
| 24 |
+
|
| 25 |
+
@app.get("/")
|
| 26 |
+
def root():
|
| 27 |
+
return {"status": "Dolor D Prince API Gateway running"}
|
| 28 |
+
|
| 29 |
+
@app.post("/v1/chat/completions")
|
| 30 |
+
async def chat_completions(body: dict):
|
| 31 |
+
api_key = os.environ.get("OPENROUTER_API_KEY", "")
|
| 32 |
+
async with httpx.AsyncClient(timeout=60) as client:
|
| 33 |
+
res = await client.post(
|
| 34 |
+
"https://openrouter.ai/api/v1/chat/completions",
|
| 35 |
+
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
|
| 36 |
+
json=body,
|
| 37 |
+
)
|
| 38 |
+
return res.json()
|
| 39 |
+
|
| 40 |
+
@app.post("/v1/projects/{page_id}")
|
| 41 |
+
async def save_project(page_id: str, body: dict):
|
| 42 |
+
d = get_drive()
|
| 43 |
+
fname = f"{page_id}.json"
|
| 44 |
+
media = MediaIoBaseUpload(io.BytesIO(json.dumps(body).encode()), mimetype="application/json")
|
| 45 |
+
existing = d.files().list(q=f"name='{fname}' and '{DRIVE_FOLDER_ID}' in parents").execute()
|
| 46 |
+
if existing["files"]:
|
| 47 |
+
d.files().update(fileId=existing["files"][0]["id"], media_body=media).execute()
|
| 48 |
+
else:
|
| 49 |
+
d.files().create(body={"name": fname, "parents": [DRIVE_FOLDER_ID]}, media_body=media).execute()
|
| 50 |
+
return {"status": "ok"}
|
| 51 |
+
|
| 52 |
+
@app.get("/v1/projects/{page_id}")
|
| 53 |
+
async def load_project(page_id: str):
|
| 54 |
+
d = get_drive()
|
| 55 |
+
fname = f"{page_id}.json"
|
| 56 |
+
res = d.files().list(q=f"name='{fname}' and '{DRIVE_FOLDER_ID}' in parents").execute()
|
| 57 |
+
if not res["files"]:
|
| 58 |
+
return {"data": {}}
|
| 59 |
+
content = d.files().get_media(fileId=res["files"][0]["id"]).execute()
|
| 60 |
+
return {"data": json.loads(content)}
|
| 61 |
+
|
| 62 |
+
@app.post("/v1/assets/upload")
|
| 63 |
+
async def upload_asset(files: list[UploadFile] = File(...)):
|
| 64 |
+
d = get_drive()
|
| 65 |
+
urls = []
|
| 66 |
+
for f in files:
|
| 67 |
+
media = MediaIoBaseUpload(io.BytesIO(await f.read()), mimetype=f.content_type)
|
| 68 |
+
created = d.files().create(
|
| 69 |
+
body={"name": f.filename, "parents": [DRIVE_FOLDER_ID]}, media_body=media, fields="id"
|
| 70 |
+
).execute()
|
| 71 |
+
d.permissions().create(fileId=created["id"], body={"role": "reader", "type": "anyone"}).execute()
|
| 72 |
+
urls.append(f"https://drive.google.com/uc?id={created['id']}")
|
| 73 |
+
return {"data": [{"src": u} for u in urls]}
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn[standard]
|
| 3 |
+
httpx
|
| 4 |
+
python-multipart
|
| 5 |
+
google-api-python-client
|
| 6 |
+
google-auth
|
| 7 |
+
pydantic
|