-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from chat-apropo/query-params-config
reestructure project
- Loading branch information
Showing
9 changed files
with
191 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
FROM python:3.12.2-slim-bullseye | ||
|
||
WORKDIR /app | ||
COPY . /app | ||
WORKDIR /backend | ||
COPY backend/ backend | ||
COPY requirements.txt . | ||
|
||
RUN pip install --no-cache-dir -r requirements.txt | ||
|
||
ENTRYPOINT ["python3", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] | ||
ENTRYPOINT ["python3", "-m", "backend.run"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from fastapi import FastAPI | ||
|
||
from backend.errors import add_exception_handlers | ||
from backend.routes import add_routers | ||
|
||
app = FastAPI( | ||
title="G4F API", | ||
description="Get text completions from various models and providers using https://github.com/xtekky/gpt4free", | ||
version="0.0.1", | ||
) | ||
|
||
add_exception_handlers(app) | ||
add_routers(app) | ||
|
||
__all__ = ["app"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from typing import Literal, TypeVar | ||
|
||
import g4f | ||
from fastapi import Query | ||
from fastapi.openapi.models import Example | ||
from g4f import ModelUtils | ||
from pydantic import BaseModel, ConfigDict, Field | ||
|
||
all_models = list(ModelUtils.convert.keys()) | ||
|
||
all_working_providers = [provider.__name__ for provider in g4f.Provider.__providers__ if provider.working] | ||
|
||
A = TypeVar("A") | ||
|
||
|
||
def generate_examples_from_values(values: list) -> dict[str, Example]: | ||
return {str(v or "--"): Example(value=v) for v in values} | ||
|
||
|
||
def allowed_values_or_none(v: A | None, allowed: list[A]) -> A | None: | ||
if v is None: | ||
return v | ||
if v not in allowed: | ||
raise ValueError(f"Value {v} not in allowed values: {allowed}") | ||
return v | ||
|
||
|
||
class Message(BaseModel): | ||
role: Literal["user", "assistant"] = Field(..., description="Who is sending the message") | ||
content: str = Field(..., description="Content of the message") | ||
|
||
|
||
class CompletionRequest(BaseModel): | ||
messages: list[Message] = Field(..., description="List of messages to use for completion") | ||
model_config = ConfigDict(extra="forbid") | ||
|
||
|
||
class CompletionParams: | ||
def __init__( | ||
self, | ||
model: str | ||
| None = Query( | ||
None, | ||
description="LLM model to use for completion. Cannot be specified together with provider.", | ||
openapi_examples=generate_examples_from_values([None] + all_models), | ||
), | ||
provider: str | ||
| None = Query( | ||
None, | ||
description="Provider to use for completion. Cannot be specified together with model.", | ||
openapi_examples=generate_examples_from_values([None] + all_working_providers), | ||
), | ||
): | ||
allowed_values_or_none(model, all_models) | ||
allowed_values_or_none(provider, all_working_providers) | ||
if model and provider: | ||
raise ValueError("model and provider cannot be provided together yet") | ||
if not (model or provider): | ||
raise ValueError("one of model or provider must be specified") | ||
|
||
self.model = model | ||
self.provider = provider | ||
|
||
|
||
def chat_completion() -> type[g4f.ChatCompletion]: | ||
return g4f.ChatCompletion |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import json | ||
|
||
from fastapi import FastAPI, Request | ||
from fastapi.responses import JSONResponse | ||
from pydantic import ValidationError | ||
|
||
|
||
def add_exception_handlers(app: FastAPI) -> None: | ||
@app.exception_handler(ValueError) | ||
def _(_: Request, exc: ValueError) -> JSONResponse: | ||
return JSONResponse(status_code=422, content={"detail": str(exc)}) | ||
|
||
@app.exception_handler(ValidationError) | ||
def _(_: Request, exc: ValidationError) -> JSONResponse: | ||
return JSONResponse(status_code=422, content=json.loads(exc.json())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import g4f | ||
from fastapi import APIRouter, Depends, FastAPI | ||
from fastapi.responses import RedirectResponse | ||
|
||
from backend.dependencies import CompletionParams, CompletionRequest, all_models, all_working_providers, chat_completion | ||
|
||
router_root = APIRouter() | ||
router_api = APIRouter(prefix="/api") | ||
|
||
|
||
def add_routers(app: FastAPI) -> None: | ||
app.include_router(router_root) | ||
app.include_router(router_api) | ||
|
||
|
||
@router_root.get("/") | ||
def get_root(): | ||
return RedirectResponse(url="/docs") | ||
|
||
|
||
@router_api.post("/completions") | ||
def post_completion( | ||
completion: CompletionRequest, | ||
params: CompletionParams = Depends(), | ||
chat: type[g4f.ChatCompletion] = Depends(chat_completion), | ||
): | ||
response = chat.create( | ||
model=params.model, | ||
provider=params.provider, | ||
messages=[msg.model_dump() for msg in completion.messages], | ||
stream=False, | ||
) | ||
return {"completion": response} | ||
|
||
|
||
@router_api.get("/providers") | ||
def get_list_providers(): | ||
return {"providers": all_working_providers} | ||
|
||
|
||
@router_api.get("/models") | ||
def get_list_models(): | ||
return {"models": all_models} | ||
|
||
|
||
@router_api.get("/health") | ||
def get_health_check(): | ||
return {"status": "ok"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import uvicorn | ||
|
||
if __name__ == "__main__": | ||
uvicorn.run( | ||
"backend:app", | ||
host="0.0.0.0", | ||
port=8000, | ||
reload=False, | ||
workers=1, | ||
timeout_keep_alive=30, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters