File size: 5,712 Bytes
96a881b
4986fe4
d38c2eb
ef215d3
a111cf9
378f2c3
8834a20
a111cf9
 
 
 
378f2c3
d38c2eb
4986fe4
378f2c3
 
b955cc1
4986fe4
 
 
b955cc1
a111cf9
4986fe4
a111cf9
 
b955cc1
 
 
 
378f2c3
 
 
 
b955cc1
378f2c3
a111cf9
 
 
 
 
 
 
afe2e88
a111cf9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d5656a9
a111cf9
 
 
 
 
 
 
 
 
 
 
 
 
2c1c62a
7ef5d89
c613f2b
 
 
 
 
 
 
 
 
7ef5d89
a68045e
8834a20
 
e2e24f9
8834a20
 
 
 
7ef5d89
ac4bad0
3109050
 
 
96a881b
ef215d3
a111cf9
b955cc1
96a881b
b955cc1
 
96a881b
 
3109050
8834a20
 
b955cc1
8834a20
114ca84
 
3109050
 
 
 
 
 
 
 
96a881b
7ef5d89
 
 
 
 
a111cf9
 
6a84e5c
 
 
8e4491b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

import os
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import StreamingResponse, HTMLResponse, JSONResponse
from pydantic import BaseModel
import httpx
import requests
import re
import json
from typing import Optional

load_dotenv()

app = FastAPI()

# Get API keys and secret endpoint from environment variables
api_keys_str = os.getenv('API_KEYS')
valid_api_keys = api_keys_str.split(',') if api_keys_str else []
secret_api_endpoint = os.getenv('SECRET_API_ENDPOINT')
secret_api_endpoint_2 = os.getenv('SECRET_API_ENDPOINT_2')
secret_api_endpoint_3 = os.getenv('SECRET_API_ENDPOINT_3')  # New endpoint for searchgpt

# Validate if the main secret API endpoints are set
if not secret_api_endpoint or not secret_api_endpoint_2 or not secret_api_endpoint_3:
    raise HTTPException(status_code=500, detail="API endpoint(s) are not configured in environment variables.")

# Define models that should use the secondary endpoint
alternate_models = {"gpt-4o-mini", "claude-3-haiku", "llama-3.1-70b", "mixtral-8x7b"}

class Payload(BaseModel):
    model: str
    messages: list
    stream: bool

def generate_search(query: str, stream: bool = True) -> str:
    headers = {"User-Agent": ""}
    prompt = [
        {"role": "user", "content": query},
    ]
    
    # Insert the system prompt at the beginning of the conversation history
    prompt.insert(0, {"content": "Be Helpful and Friendly", "role": "system"})
    
    payload = {
        "is_vscode_extension": True,
        "message_history": prompt,
        "requested_model": "searchgpt",
        "user_input": prompt[-1]["content"],
    }
    
    # Use the newly added SECRET_API_ENDPOINT_3 for the search API call
    chat_endpoint = secret_api_endpoint_3
    response = requests.post(chat_endpoint, headers=headers, json=payload, stream=True)
    
    # Collect streamed text content
    streaming_text = ""
    for value in response.iter_lines(decode_unicode=True, chunk_size=12):
        modified_value = re.sub("data:", "", value)
        if modified_value:
            try:
                json_modified_value = json.loads(modified_value)
                content = json_modified_value["choices"][0]["delta"]["content"]
                if stream:
                    yield f"data: {content}\n\n"
                streaming_text += content
            except:
                continue
    
    if not stream:
        yield streaming_text

@app.get("/searchgpt")
async def search_gpt(q: str, stream: Optional[bool] = False):
    if not q:
        raise HTTPException(status_code=400, detail="Query parameter 'q' is required")
    
    if stream:
        return StreamingResponse(
            generate_search(q, stream=True),
            media_type="text/event-stream"
        )
    else:
        # For non-streaming response, collect all content and return as JSON
        response_text = "".join([chunk for chunk in generate_search(q, stream=False)])
        return JSONResponse(content={"response": response_text})

@app.get("/", response_class=HTMLResponse)
async def root():
    # Open and read the content of index.html (in the same folder as the app)
    file_path = "index.html"

    try:
        with open(file_path, "r") as file:
            html_content = file.read()
        return HTMLResponse(content=html_content)
    except FileNotFoundError:
        return HTMLResponse(content="<h1>File not found</h1>", status_code=404)

async def get_models():
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(f"{secret_api_endpoint}/v1/models", timeout=3)
            response.raise_for_status()
            return response.json()
        except httpx.RequestError as e:
            raise HTTPException(status_code=500, detail=f"Request failed: {e}")

@app.get("/models")
async def fetch_models():
    return await get_models()

@app.post(["/chat/completions", "/v1/chat/completions"])
async def get_completion(payload: Payload, request: Request):
    # Use the correct endpoint depending on the model type (no authentication now πŸ˜‰)
    endpoint = secret_api_endpoint_2 if payload.model in alternate_models else secret_api_endpoint
    
    # Use the payload directly as it includes stream and other user data
    payload_dict = payload.dict()
    print(payload_dict) # coz i m curious af heheheh :)
    #data is kept to me only so dont worry
    async def stream_generator(payload_dict):
        async with httpx.AsyncClient() as client:
            try:
                async with client.stream("POST", f"{endpoint}/v1/chat/completions", json=payload_dict, timeout=10) as response:
                    response.raise_for_status()
                    async for line in response.aiter_lines():
                        if line:
                            yield f"{line}\n"
            except httpx.HTTPStatusError as status_err:
                raise HTTPException(status_code=status_err.response.status_code, detail=f"HTTP error: {status_err}")
            except httpx.RequestError as req_err:
                raise HTTPException(status_code=500, detail=f"Streaming failed: {req_err}")
            except Exception as e:
                raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {e}")
    
    return StreamingResponse(stream_generator(openai_payload), media_type="application/json")
@app.on_event("startup")
async def startup_event():
    print("API endpoints:")
    print("GET /")
    print("GET /models")
    print("GET /searchgpt")  # We now have the new search API
    print("POST /chat/completions")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)