From 8e3e391e458db9ac40d9bda05f34e3a67cec3ca9 Mon Sep 17 00:00:00 2001 From: madhavialla Date: Wed, 17 Sep 2025 21:22:13 -0700 Subject: [PATCH 1/2] add --- api/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/app.py b/api/app.py index 4fe8d0ba8..c1351d35f 100644 --- a/api/app.py +++ b/api/app.py @@ -69,5 +69,4 @@ async def health_check(): # Entry point for running the application directly if __name__ == "__main__": import uvicorn - # Start the server on all network interfaces (0.0.0.0) on port 8000 uvicorn.run(app, host="0.0.0.0", port=8000) From 0665b451af6eb96cebf41ec8f2fd4eb97ddd3f52 Mon Sep 17 00:00:00 2001 From: madhavialla Date: Wed, 17 Sep 2025 21:24:36 -0700 Subject: [PATCH 2/2] add --- api/app.py | 113 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/api/app.py b/api/app.py index c1351d35f..cefce9cd3 100644 --- a/api/app.py +++ b/api/app.py @@ -1,5 +1,5 @@ # Import required FastAPI components for building the API -from fastapi import FastAPI, HTTPException +from fastapi import FastAPI, HTTPException, Body from fastapi.responses import StreamingResponse from fastapi.middleware.cors import CORSMiddleware # Import Pydantic for data validation and settings management @@ -7,65 +7,126 @@ # Import OpenAI client for interacting with OpenAI's API from openai import OpenAI import os -from typing import Optional +from typing import Optional, List +from datetime import datetime +import json # Initialize FastAPI application with a title app = FastAPI(title="OpenAI Chat API") +@app.get("/health") +def health(): + return {"status": "ok"} + # Configure CORS (Cross-Origin Resource Sharing) middleware -# This allows the API to be accessed from different domains/origins app.add_middleware( CORSMiddleware, - allow_origins=["*"], # Allows requests from any origin - allow_credentials=True, # Allows cookies to be included in requests - allow_methods=["*"], # Allows all HTTP methods (GET, POST, etc.) - allow_headers=["*"], # Allows all headers in requests + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], ) -# Define the data model for chat requests using Pydantic -# This ensures incoming request data is properly validated +# ---------- Models ---------- class ChatRequest(BaseModel): - developer_message: str # Message from the developer/system - user_message: str # Message from the user - model: Optional[str] = "gpt-4.1-mini" # Optional model selection with default - api_key: str # OpenAI API key for authentication + developer_message: str # system/developer guidance + user_message: str # user prompt + model: Optional[str] = "gpt-4.1-mini" + api_key: str # OpenAI API key for authentication + +# For the coffee application example (response shape) +class CoffeePlace(BaseModel): + name: str + neighborhood: Optional[str] = None + why: str + signature_drink: Optional[str] = None + notes: Optional[str] = None -# Define the main chat endpoint that handles POST requests +class CoffeeResponse(BaseModel): + city: str + generated_at: str + results: List[CoffeePlace] + raw_text: Optional[str] = None # fallback if JSON parsing fails + +# ---------- Streaming chat (keep this exactly as your general chat endpoint) ---------- @app.post("/api/chat") async def chat(request: ChatRequest): try: - # Initialize OpenAI client with the provided API key client = OpenAI(api_key=request.api_key) - - # Create an async generator function for streaming responses + async def generate(): - # Create a streaming chat completion request stream = client.chat.completions.create( model=request.model, messages=[ - {"role": "developer", "content": request.developer_message}, + {"role": "system", "content": request.developer_message}, # use valid role {"role": "user", "content": request.user_message} ], - stream=True # Enable streaming response + stream=True ) - - # Yield each chunk of the response as it becomes available for chunk in stream: if chunk.choices[0].delta.content is not None: yield chunk.choices[0].delta.content - # Return a streaming response to the client return StreamingResponse(generate(), media_type="text/plain") - + except Exception as e: - # Handle any errors that occur during processing raise HTTPException(status_code=500, detail=str(e)) -# Define a health check endpoint to verify API status @app.get("/api/health") async def health_check(): return {"status": "ok"} +# ---------- Coffee application example (non-streaming, returns structured JSON) ---------- +@app.post("/api/coffee", response_model=CoffeeResponse) +async def coffee_recommendations( + city: str = Body(..., embed=True), + api_key: str = Body(...), + model: str = Body("gpt-4.1-mini") +): + """ + Application Example: Recommend top coffee places for a city (e.g., 'San Diego'). + Returns structured JSON; if parsing fails, returns raw_text with the model’s answer. + """ + try: + client = OpenAI(api_key=api_key) + + system_prompt = ( + "You are a coffee expert. Return ONLY JSON (no markdown). " + "Schema: [{\"name\":\"...\",\"neighborhood\":\"...\",\"why\":\"...\"," + "\"signature_drink\":\"...\",\"notes\":\"...\"}] " + "Provide 5–7 entries. Keep 'why' short and practical." + ) + user_prompt = f"Best coffee places in {city}. Include well-known local favorites." + + completion = client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt} + ] + ) + + content = completion.choices[0].message.content.strip() + + try: + data = json.loads(content) + places = [CoffeePlace(**item) for item in data] + return CoffeeResponse( + city=city, + generated_at=datetime.utcnow().isoformat() + "Z", + results=places + ) + except Exception: + return CoffeeResponse( + city=city, + generated_at=datetime.utcnow().isoformat() + "Z", + results=[], + raw_text=content + ) + + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + # Entry point for running the application directly if __name__ == "__main__": import uvicorn