feat: Initial commit of LLM Tool Proxy

This commit is contained in:
Vertex-AI-Step-Builder
2025-12-31 06:35:08 +00:00
commit 0d14c98cf4
11 changed files with 775 additions and 0 deletions

79
app/main.py Normal file
View File

@@ -0,0 +1,79 @@
import os
import sys
from dotenv import load_dotenv
# --- Explicit Debugging & Env Loading ---
print(f"--- [DEBUG] Current Working Directory: {os.getcwd()}", file=sys.stderr)
load_result = load_dotenv()
print(f"--- [DEBUG] load_dotenv() result: {load_result}", file=sys.stderr)
# ---
import logging
from fastapi import FastAPI, HTTPException, Depends
from starlette.responses import StreamingResponse
from .models import IncomingRequest, ProxyResponse
from .services import process_chat_request, stream_llm_api, inject_tools_into_prompt
from .core.config import get_settings, Settings
# --- Logging Configuration ---
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("llm_proxy.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# --- End of Logging Configuration ---
app = FastAPI(
title="LLM Tool Proxy",
description="A proxy that intercepts LLM requests to inject and handle tool calls.",
version="1.0.0",
)
@app.on_event("startup")
async def startup_event():
logger.info("Application startup complete.")
current_settings = get_settings()
logger.info(f"Loaded LLM API URL: {current_settings.REAL_LLM_API_URL}")
@app.post("/v1/chat/completions")
async def chat_completions(
request: IncomingRequest,
settings: Settings = Depends(get_settings)
):
"""
This endpoint mimics the OpenAI Chat Completions API and supports both
streaming (`stream=True`) and non-streaming (`stream=False`) responses.
"""
if not settings.REAL_LLM_API_KEY or not settings.REAL_LLM_API_URL:
logger.error("REAL_LLM_API_KEY or REAL_LLM_API_URL is not configured.")
raise HTTPException(status_code=500, detail="LLM API Key or URL is not configured.")
# Prepare messages, potentially with tool injection
# This prepares the messages that will be sent to the LLM backend
messages_to_llm = request.messages
if request.tools:
messages_to_llm = inject_tools_into_prompt(request.messages, request.tools)
# Handle streaming request
if request.stream:
logger.info(f"Initiating streaming request with {len(messages_to_llm)} messages.")
generator = stream_llm_api(messages_to_llm, settings)
return StreamingResponse(generator, media_type="text/event-stream")
# Handle non-streaming request
try:
logger.info(f"Initiating non-streaming request with {len(messages_to_llm)} messages.")
response_message = await process_chat_request(messages_to_llm, request.tools, settings)
logger.info("Successfully processed non-streaming request.")
return ProxyResponse(message=response_message)
except Exception as e:
logger.exception("An unexpected error occurred during non-streaming request.")
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
@app.get("/")
def read_root():
return {"message": "LLM Tool Proxy is running."}