|
|
import time |
|
|
import uuid |
|
|
import json |
|
|
import re |
|
|
from fastapi import FastAPI |
|
|
from fastapi.responses import StreamingResponse |
|
|
from pydantic import BaseModel |
|
|
from typing import List |
|
|
from meta_ai_api import MetaAI |
|
|
|
|
|
class Message(BaseModel): |
|
|
role: str |
|
|
content: str |
|
|
|
|
|
class ChatRequest(BaseModel): |
|
|
messages: List[Message] |
|
|
|
|
|
app = FastAPI() |
|
|
meta = MetaAI() |
|
|
|
|
|
@app.get("/") |
|
|
def read_root(): |
|
|
return {"msg": "Try POST /v1/chat/completions with stream=True"} |
|
|
|
|
|
@app.post("/v1/chat/completions") |
|
|
async def chat_completions(req: ChatRequest): |
|
|
user_msgs = [m.content for m in req.messages if m.role == "user"] |
|
|
if not user_msgs: |
|
|
return {"error": "No user message provided"} |
|
|
last_user = user_msgs[-1] |
|
|
|
|
|
def normalize_text(text): |
|
|
"""Normalize text by removing spaces before punctuation and collapsing multiple spaces.""" |
|
|
text = re.sub(r'\s+([.,!?;:])', r'\1', text) |
|
|
text = re.sub(r'\s+', ' ', text) |
|
|
text = text.strip() |
|
|
return text |
|
|
|
|
|
def event_stream(): |
|
|
last_normalized = "" |
|
|
for chunk in meta.prompt(message=last_user, stream=True): |
|
|
full_text = str(chunk.get("message", "")) |
|
|
if not full_text: |
|
|
continue |
|
|
|
|
|
|
|
|
normalized_full = normalize_text(full_text) |
|
|
|
|
|
|
|
|
if normalized_full.startswith(last_normalized): |
|
|
new_piece = normalized_full[len(last_normalized):] |
|
|
else: |
|
|
new_piece = normalized_full |
|
|
|
|
|
if new_piece: |
|
|
data = { |
|
|
"id": f"meta-{uuid.uuid4()}", |
|
|
"object": "chat.completion.chunk", |
|
|
"created": int(time.time()), |
|
|
"choices": [{ |
|
|
"delta": {"content": new_piece}, |
|
|
"index": 0, |
|
|
"finish_reason": None |
|
|
}] |
|
|
} |
|
|
yield f"data: {json.dumps(data)}\n\n" |
|
|
|
|
|
|
|
|
last_normalized = normalized_full |
|
|
|
|
|
|
|
|
done = { |
|
|
"id": f"meta-{uuid.uuid4()}", |
|
|
"object": "chat.completion.chunk", |
|
|
"created": int(time.time()), |
|
|
"choices": [{"delta": {}, "index": 0, "finish_reason": "stop"}] |
|
|
} |
|
|
yield f"data: {json.dumps(done)}\n\n" |
|
|
|
|
|
return StreamingResponse(event_stream(), media_type="text/event-stream") |