from fastapi import FastAPI
import json
import os
from typing import Dict, List, Any, TypedDict
from upstash_workflow.fastapi import Serve
from upstash_workflow import AsyncWorkflowContext, CallResponse
from utils import (
aggregate_results,
generate_report,
send_report,
get_dataset_url,
split_into_chunks,
)
app = FastAPI()
serve = Serve(app)
class RequestPayload(TypedDict):
dataset_id: str
user_id: str
@serve.post("/ai-generation")
async def ai_generation(context: AsyncWorkflowContext[RequestPayload]) -> None:
request = context.request_payload
dataset_id = request["dataset_id"]
user_id = request["user_id"]
# Step 1: Download the dataset
async def _get_dataset_url() -> str:
return await get_dataset_url(dataset_id)
dataset_url = await context.run("get-dataset-url", _get_dataset_url)
# HTTP request with much longer timeout (2hrs)
response: CallResponse[Any] = await context.call(
"download-dataset", url=dataset_url, method="GET"
)
dataset = response.body
# Step 2: Process data in chunks using OpenAI
chunk_size = 1000
chunks = split_into_chunks(dataset, chunk_size)
processed_chunks: List[str] = []
for i, chunk in enumerate(chunks):
openai_response: CallResponse[Dict[str, str]] = await context.call(
f"process-chunk-{i}",
url="https://api.openai.com/v1/chat/completions",
method="POST",
headers={
"authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}",
},
body={
"model": "gpt-4",
"messages": [
{
"role": "system",
"content":
"You are an AI assistant tasked with analyzing data chunks. Provide a brief summary and key insights for the given data.",
},
{
"role": "user",
"content": f"Analyze this data chunk: {json.dumps(chunk)}",
},
],
"max_tokens": 150,
},
)
processed_chunks.append(
openai_response.body["choices"][0]["message"]["content"]
)
# Every 10 chunks, we'll aggregate intermediate results
if i % 10 == 9 or i == len(chunks) - 1:
async def _aggregate_results() -> None:
await aggregate_results(processed_chunks)
processed_chunks.clear()
await context.run(f"aggregate-results{i}", _aggregate_results)
# Step 3: Generate and send data report
async def _generate_report() -> Any:
return await generate_report(dataset_id)
report = await context.run("generate-report", _generate_report)
async def _send_report() -> None:
await send_report(report, user_id)
await context.run("send-report", _send_report)