File size: 7,812 Bytes
f008773
a017406
f008773
 
 
 
c6fc7f7
 
40a4ea0
 
f008773
 
 
 
 
 
 
 
cd2d970
f008773
 
 
 
 
 
 
 
 
 
 
 
 
26cf2e1
a017406
26cf2e1
 
40a4ea0
f008773
 
 
 
 
df514c8
f008773
 
 
 
 
 
 
 
26cf2e1
40a4ea0
 
 
26cf2e1
40a4ea0
 
26cf2e1
f008773
 
 
 
df514c8
 
 
 
 
 
 
 
65a98b9
 
 
 
 
 
 
 
 
 
 
 
df514c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f008773
 
 
 
 
 
 
 
 
 
 
 
 
df514c8
f008773
 
 
b75dd23
f008773
 
 
 
 
40a4ea0
f008773
 
 
 
40a4ea0
 
f008773
 
7af317a
f008773
7af317a
 
 
 
 
 
 
 
 
 
 
 
26cf2e1
40a4ea0
f008773
 
26cf2e1
40a4ea0
 
 
26cf2e1
df514c8
 
 
 
 
f008773
 
40a4ea0
f008773
40a4ea0
f008773
 
40a4ea0
 
94728b8
40a4ea0
f008773
40a4ea0
 
 
 
 
f008773
7af317a
26cf2e1
6f6890a
6c02b49
f008773
6f6890a
40a4ea0
f008773
 
 
 
40a4ea0
f008773
40a4ea0
 
 
 
94728b8
40a4ea0
f008773
40a4ea0
 
 
f008773
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
import time
import os
import base64
import uuid
from datetime import datetime, timedelta, timezone
from google import genai
from google.genai import types
from typing import List
import firebase_admin
from firebase_admin import credentials, auth

certificate = {
  "type": "service_account",
  "project_id": os.environ.get('project'),
  "private_key_id": os.environ.get('key_id'),
  "private_key": os.environ.get('private_key').replace('\\n', '\n'),
  "client_email": os.environ.get('client_email'),
  "client_id": os.environ.get('client_id'),
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": os.environ.get('cert_url'),
  "universe_domain": "googleapis.com"
}

cred = credentials.Certificate(certificate)
firebase_admin.initialize_app(cred)


app = FastAPI()
security = HTTPBearer()


Tokens = []
user = []
# In-memory storage
sessions = {}  # Format: {uid: {conv_id: [history_list]}}


user_data = [] #[[name, gender, nationality, model name, model gender]]
user_inst = [] #[[system prompt, About user, demanded tone, custum instruction]]


Api_key = os.getenv('API_KEY')
System_instruction = '''**System Prompt for a Programmer-Oriented Coding Assistant:**\n\n> You are a highly focused, fast, and expert-level coding assistant built for professional programmers.\n> Your primary role is **to assist with code writing, debugging, refactoring, optimization, and architecture**.\n> Avoid unnecessary explanations unless asked. Do not teach—**support the user like a senior pair programmer** who assumes context and skill. Prioritize clean, correct, and efficient code.\n\n> Always:\n> * Get straight to the point.\n> * Suggest the most practical and scalable solution.\n> * Respond with complete code blocks when needed.\n> * Use strong defaults and modern conventions.\n> * Assume the user knows what they're doing.\n> * Think ahead: anticipate potential pitfalls or better approaches.\n> * Give fast, minimal answers when asked for quick help.\n\n> Only elaborate if specifically requested (e.g., “explain,” “why,” “teach,” “verbose”)'''

client = genai.Client(api_key=Api_key)


class ChatRequest(BaseModel):
    prompt: str
    conv_id: str

class NewConv(BaseModel):
    prompt: str

class VerifyRequest(BaseModel):
    uid: str
    idToken: str

class UpdateSystemRequest(BaseModel):
    category: str
    content: str

def update_details():
    user_data.append(['','','','',''])
    user_inst.append(['','','',''])
    
    

def verify_access_token(auth: HTTPAuthorizationCredentials = Depends(security)):
    token = auth.credentials
    if token not in Tokens:
        raise HTTPException(
            status_code=401, 
            detail="Invalid or expired session token. Please login again."
        )
    return token
    
    
@app.post("/update/system/userInfo")
async def update_Details(info: UpdateSystemRequest, token: str = Depends(verify_access_token)):
    i = Tokens.index(token)
    cat = info.category
    val = info.content
    if cat == 'name':
        user_data[i][0] = val
    if cat == 'gender':
        user_data[i][1] = val
    if cat == 'country':
        user_data[i][2] = val
    if cat == 'model_name':
        user_data[i][3] = val
    if cat == 'model_gender':
        user_data[i][4] = val
    if cat == 'system_prompt':
        user_inst[i][0] =val
    if cat == 'about_user':
        user_inst[i][1] =val
    if cat == 'tone':
        user_inst[i][2] =val
    if cat == 'custum_instruction':
        user_inst[i][3] =val
    else:
        raise HTTPException(status_code=401, detail="Invalid Data.")


@app.post("/api/verify")
def check_token(data: VerifyRequest):
    decoded_token = auth.verify_id_token(data.idToken)
    uid = decoded_token['uid']

    if decoded_token['uid'] == data.uid and decoded_token['email_verified']:
        new_token = base64.urlsafe_b64encode(uuid.uuid4().bytes).rstrip(b'=').decode()

        if uid not in user:
            user.append(uid)
            Tokens.append(new_token)
            sessions[uid] = {}
            update_details()
        else:
            idx = user.index(uid)
            Tokens[idx] = new_token
        return {"customToken": new_token}
    else:
        raise HTTPException(status_code=401, detail="Invalid token. Verification failed.")        


def call_gemini(history: List[types.Content]):
    try:
        response = client.models.generate_content(
            model="gemma-3-4b-it",
            contents=history
        )
        return response.text
    except Exception as e:
        print(f"GenAI Error: {e}")
        raise HTTPException(status_code=500, detail="AI Generation Failed")
        

def gen_title(user, model):
    try:
        response = client.models.generate_content(
            model="gemma-3-1b-it",
            contents= title_prompt(user, model)
        )
        return response.text
    except Exception as e:
        return user

def title_prompt(user, model):
    return f'''---\n**System Role:**\n\n> You are a specialized utility model. Your sole task is to generate a concise, descriptive title (2–6 words) for a chat conversation based on the provided user query and model response.\n\n**Constraints:**\n\n* **Output only the title.** Do not include labels, quotes, full-stop or introductory text.\n* **Focus on the core intent** of the conversation.\n* **Avoid generic terms** like "Chat about..." or "Request for..."\n* **Style:** Professional, catchy, and informative.\n\n---\n\n**User Query:** {user}\n\n**Model Response:** {model}'''

def getSystemPrompt():
    text = ''
    return text #TODO: System Prompt builder later

def getConvId():
    u = uuid.uuid4().bytes[:12]
    return base64.urlsafe_b64encode(u).rstrip(b'=').decode()

def currentTime():
    # IST is UTC + 5:30
    ist_offset = timezone(timedelta(hours=5, minutes=30))
    current_time = datetime.now(ist_offset)
    return current_time.strftime("%I:%M %p")


@app.post("/new_conversation")
async def handleNewConv(new_conv: NewConv, token: str = Depends(verify_access_token)):
    a = time.time()
    i = Tokens.index(token)
    convs = sessions.get(user[i])
    history = [
        types.Content(role='model', parts=[types.Part(text=getSystemPrompt())]),
        types.Content(role='user', parts=[types.Part(text= f'time {currentTime()}\n{new_conv.prompt}')])
    ]
    text = call_gemini(history)
    if text:
        conv_id = getConvId()
        raw_history = [["model", getSystemPrompt()]]
        raw_history.append(["user", new_conv.prompt])
        raw_history.append(["model", text])
        convs[conv_id] = raw_history
        return {"title": gen_title(new_conv.prompt,text), "text": text, "conv_id": conv_id}


@app.post("/gen_resp")
async def handleChat(chat_request: ChatRequest, token: str = Depends(verify_access_token)):
    a= time.time()
    conv_id = chat_request.conv_id
    i = Tokens.index(token)
    convs = sessions.get(user[i])
    if conv_id not in convs:
        raise HTTPException(status_code=404, detail="Conversation not found")
    # Prepare history
    raw_history = convs[conv_id]
    history = [
        types.Content(role=k[0], parts=[types.Part(text=k[1])]) 
        for k in raw_history
    ]
    history.append(types.Content(role='user', parts=[types.Part(text= f'time {currentTime()}\n{chat_request.prompt}')]))
    # Generate response
    text = call_gemini(history)
    if text:
        raw_history.append(["user", chat_request.prompt])
        raw_history.append(["model", text])
        return {"text": text}