Files
Michael Ikehi a91613efe2 Add tiered summarization based on pricing plans
- Implement advanced AI summarization with action items for Pro plan
- Create basic bullet-point summarization for Freemium plan
- Add plan tier validation and feature differentiation
- Support speaker identification in transcripts
- Define plan limits (600 mins Pro/200 mins Freemium)
2025-04-24 17:18:53 +01:00

188 lines
6.3 KiB
Python

import os
from typing import Optional
from fastapi import FastAPI, HTTPException, Security, Depends
from fastapi.security import APIKeyHeader
from fastapi.middleware.cors import CORSMiddleware
from dotenv import load_dotenv
import json
from pydantic import BaseModel
from fastapi import HTTPException
import os
from scripts.transcriber import transcribe_media, group_words_into_sentences
from scripts.generate_summary import general_summary, custom_summary
from src.models import PlanTier, PlanLimits
# Load environment variables
load_dotenv()
API_KEY = os.getenv("API_KEY_ACCESS")
# Initialize FastAPI app
app = FastAPI(
title="Microdot AI API",
description="API For fire fighter",
version="1.0.0"
)
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Setup API key authentication
api_key_header = APIKeyHeader(name="Authorization", auto_error=False)
async def get_api_key(api_key_header: str = Security(api_key_header)) -> str:
"""Validate API key from header"""
if not api_key_header or not api_key_header.startswith('Bearer '):
raise HTTPException(
status_code=401,
detail={"error": "Unauthorized", "message": "API key is missing or invalid."}
)
token = api_key_header.split(' ')[1]
if token != API_KEY:
raise HTTPException(
status_code=401,
detail={"error": "Unauthorized", "message": "API key does not match."}
)
return token
class TranscribeRequest(BaseModel):
media_url: Optional[str] = None
media_type: Optional[str] # Corrected type hint for media_type
plan_tier: Optional[str] = "freemium" # Default to freemium plan if not specified
class ChatResp(BaseModel): # Added BaseModel inheritance
error: Optional[str] = None
class TranscriptResponse(BaseModel):
transcript: dict # Changed type hint for transcript to a dictionary
class GeneralSummaryRequest(BaseModel):
transcript: Optional[str] = None
plan_tier: Optional[str] = "pro" # Default to pro plan if not specified
class TemplateSummaryRequest(BaseModel):
transcript: Optional[str] = None
template: Optional[str] = None
@app.post("/microdot-ai/transcribe")
async def chat_endpoint(
request: TranscribeRequest,
api_key: str = Depends(get_api_key)
):
try:
# Get the plan tier from the request or default to freemium
plan_tier = request.plan_tier.lower() if request.plan_tier else "freemium"
# Validate plan tier using our PlanTier enum
valid_tiers = [t.value for t in PlanTier]
if plan_tier not in valid_tiers:
plan_tier = PlanTier.FREEMIUM.value # Default to freemium if invalid tier
# Check if the plan includes speaker identification
include_speakers = PlanLimits.get_limit(plan_tier, "speaker_identification")
# Use the transcribe_media function to transcribe the media
if request.media_url:
transcription_response = transcribe_media(request.media_url, media_type=request.media_type)
if transcription_response is None:
raise HTTPException(status_code=500, detail="Transcription failed.")
print(f"Transcription response: {transcription_response}") # Debugging print
# Parse response
words = transcription_response["results"]["channels"][0]["alternatives"][0]["words"]
transcript = group_words_into_sentences(words=words, include_speakers=include_speakers)
return TranscriptResponse(
transcript=transcript, # Corrected to return the transcript
error=None
)
except Exception as e:
print(f"Error processing chat request: {str(e)}") # Print statement added
raise HTTPException(
status_code=500,
detail=f"Error processing chat request: {str(e)}"
)
@app.post("/microdot-ai/general-summary")
async def general_summary_endpoint(
request: GeneralSummaryRequest,
api_key: str = Depends(get_api_key)
):
try:
if not request.transcript:
raise HTTPException(status_code=400, detail="Transcript is required.")
# Get the plan tier from the request or default to pro
plan_tier = request.plan_tier.lower() if request.plan_tier else "pro"
# Validate plan tier using our PlanTier enum
valid_tiers = [t.value for t in PlanTier]
if plan_tier not in valid_tiers:
plan_tier = PlanTier.PRO.value # Default to pro if invalid tier
# Get the appropriate summary type for this plan tier
summary_type = PlanLimits.get_limit(plan_tier, "summary_type")
# Generate the summary based on the plan tier
response = general_summary(json.loads(request.transcript), plan_tier=plan_tier)
return TranscriptResponse(
transcript=response
)
except Exception as e:
print(f"Error processing general summary request: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Error processing general summary request: {str(e)}"
)
@app.post("/microdot-ai/template-summary")
async def template_summary_endpoint( # Corrected function name to avoid conflict
request: TemplateSummaryRequest,
api_key: str = Depends(get_api_key)
):
try:
if not request.transcript:
raise HTTPException(status_code=400, detail="Transcript is required.")
if not request.template:
raise HTTPException(status_code=400, detail="Template is required.")
transcript = json.loads(request.transcript)
template = json.loads(request.template) # Removed the check for missing template as it's now required
response = custom_summary(template, transcript)
return TranscriptResponse(
transcript=response
)
except Exception as e:
print(f"Error processing template summary request: {str(e)}") # Updated print statement for clarity
raise HTTPException(
status_code=500,
detail=f"Error processing template summary request: {str(e)}"
)
@app.on_event("startup")
async def startup_event():
"""Initialize required components on startup"""
pass
if __name__ == "__main__":
import uvicorn
uvicorn.run("app:app", host="0.0.0.0", port=5056, reload=True)