Spaces:
Sleeping
Sleeping
Added endpoints for graph
Browse files
app.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
| 1 |
import io
|
| 2 |
import tempfile
|
|
|
|
|
|
|
|
|
|
| 3 |
import jwt
|
| 4 |
import base64
|
| 5 |
import json
|
|
@@ -8,7 +11,7 @@ from jwt import ExpiredSignatureError, InvalidTokenError
|
|
| 8 |
from starlette import status
|
| 9 |
from functions import *
|
| 10 |
import pandas as pd
|
| 11 |
-
from fastapi import FastAPI, File, UploadFile, HTTPException,Request
|
| 12 |
from pydantic import BaseModel
|
| 13 |
from fastapi.middleware.cors import CORSMiddleware
|
| 14 |
from src.api.speech_api import speech_translator_router
|
|
@@ -19,8 +22,6 @@ from collections import Counter, defaultdict
|
|
| 19 |
from datetime import datetime, timedelta
|
| 20 |
from dateutil.parser import isoparse
|
| 21 |
|
| 22 |
-
|
| 23 |
-
|
| 24 |
nltk.download('punkt_tab')
|
| 25 |
|
| 26 |
app = FastAPI(title="ConversAI", root_path="/api/v1")
|
|
@@ -265,15 +266,15 @@ async def loadPDF(vectorstore: str, pdf: UploadFile = File(...)):
|
|
| 265 |
"output": text,
|
| 266 |
"source": source
|
| 267 |
}
|
| 268 |
-
dct = json.dumps(dct, indent
|
| 269 |
-
fileName = createDataSourceName(sourceName
|
| 270 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 271 |
response = (
|
| 272 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 273 |
-
.insert({"username": username,
|
| 274 |
-
"chatbotName": chatbotName,
|
| 275 |
-
"dataSourceName": fileName,
|
| 276 |
-
"sourceEndpoint": "/loadPDF",
|
| 277 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 278 |
.execute()
|
| 279 |
)
|
|
@@ -282,7 +283,6 @@ async def loadPDF(vectorstore: str, pdf: UploadFile = File(...)):
|
|
| 282 |
}
|
| 283 |
|
| 284 |
|
| 285 |
-
|
| 286 |
@app.post("/loadImagePDF")
|
| 287 |
async def loadImagePDF(vectorstore: str, pdf: UploadFile = File(...)):
|
| 288 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
|
@@ -293,15 +293,15 @@ async def loadImagePDF(vectorstore: str, pdf: UploadFile = File(...)):
|
|
| 293 |
"output": text,
|
| 294 |
"source": source
|
| 295 |
}
|
| 296 |
-
dct = json.dumps(dct, indent
|
| 297 |
-
fileName = createDataSourceName(sourceName
|
| 298 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 299 |
response = (
|
| 300 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 301 |
-
.insert({"username": username,
|
| 302 |
-
"chatbotName": chatbotName,
|
| 303 |
-
"dataSourceName": fileName,
|
| 304 |
-
"sourceEndpoint": "/loadImagePDF",
|
| 305 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 306 |
.execute()
|
| 307 |
)
|
|
@@ -310,7 +310,6 @@ async def loadImagePDF(vectorstore: str, pdf: UploadFile = File(...)):
|
|
| 310 |
}
|
| 311 |
|
| 312 |
|
| 313 |
-
|
| 314 |
class AddText(BaseModel):
|
| 315 |
vectorstore: str
|
| 316 |
text: str
|
|
@@ -324,15 +323,15 @@ async def loadText(addTextConfig: AddText):
|
|
| 324 |
"output": text,
|
| 325 |
"source": "Text"
|
| 326 |
}
|
| 327 |
-
dct = json.dumps(dct, indent
|
| 328 |
-
fileName = createDataSourceName(sourceName
|
| 329 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 330 |
response = (
|
| 331 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 332 |
-
.insert({"username": username,
|
| 333 |
-
"chatbotName": chatbotName,
|
| 334 |
-
"dataSourceName": fileName,
|
| 335 |
-
"sourceEndpoint": "/loadText",
|
| 336 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 337 |
.execute()
|
| 338 |
)
|
|
@@ -366,7 +365,6 @@ async def addQAPairData(addQaPair: AddQAPair):
|
|
| 366 |
}
|
| 367 |
|
| 368 |
|
| 369 |
-
|
| 370 |
class LoadWebsite(BaseModel):
|
| 371 |
vectorstore: str
|
| 372 |
urls: list[str]
|
|
@@ -377,20 +375,20 @@ class LoadWebsite(BaseModel):
|
|
| 377 |
async def loadWebURLs(loadWebsite: LoadWebsite):
|
| 378 |
vectorstore, urls, source = loadWebsite.vectorstore, loadWebsite.urls, loadWebsite.source
|
| 379 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
| 380 |
-
text = extractTextFromUrlList(urls=urls)
|
| 381 |
dct = {
|
| 382 |
"output": text,
|
| 383 |
"source": source
|
| 384 |
}
|
| 385 |
-
dct = json.dumps(dct, indent
|
| 386 |
-
fileName = createDataSourceName(sourceName
|
| 387 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 388 |
response = (
|
| 389 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 390 |
-
.insert({"username": username,
|
| 391 |
-
"chatbotName": chatbotName,
|
| 392 |
-
"dataSourceName": fileName,
|
| 393 |
-
"sourceEndpoint": "/loadWebURLs",
|
| 394 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 395 |
.execute()
|
| 396 |
)
|
|
@@ -399,15 +397,19 @@ async def loadWebURLs(loadWebsite: LoadWebsite):
|
|
| 399 |
}
|
| 400 |
|
| 401 |
|
| 402 |
-
|
| 403 |
@app.post("/answerQuery")
|
| 404 |
-
async def answerQuestion(query: str, vectorstore: str, llmModel: str = "llama3-70b-8192"):
|
| 405 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
| 406 |
output = answerQuery(query=query, vectorstore=vectorstore, llmModel=llmModel)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
response = (
|
| 408 |
supabase.table("ConversAI_ChatHistory")
|
| 409 |
.insert({"username": username, "chatbotName": chatbotName, "llmModel": llmModel, "question": query,
|
| 410 |
-
"response": output["output"]
|
|
|
|
| 411 |
.execute()
|
| 412 |
)
|
| 413 |
return output
|
|
@@ -456,15 +458,15 @@ async def loadYoutubeTranscript(ytTranscript: YtTranscript):
|
|
| 456 |
"output": text,
|
| 457 |
"source": "www.youtube.com"
|
| 458 |
}
|
| 459 |
-
dct = json.dumps(dct, indent
|
| 460 |
-
fileName = createDataSourceName(sourceName
|
| 461 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 462 |
response = (
|
| 463 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 464 |
-
.insert({"username": username,
|
| 465 |
-
"chatbotName": chatbotName,
|
| 466 |
-
"dataSourceName": fileName,
|
| 467 |
-
"sourceEndpoint": "/getYoutubeTranscript",
|
| 468 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 469 |
.execute()
|
| 470 |
)
|
|
@@ -506,7 +508,8 @@ async def chatHistory(vectorstore: str):
|
|
| 506 |
@app.post("/listChatbotSources")
|
| 507 |
async def listChatbotSources(vectorstore: str):
|
| 508 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
| 509 |
-
result = supabase.table("ConversAI_ChatbotDataSources").select("*").eq("username", username).eq("chatbotName",
|
|
|
|
| 510 |
return result
|
| 511 |
|
| 512 |
|
|
@@ -520,14 +523,18 @@ async def trainChatbot(trainChatbotConfig: TrainChatbot):
|
|
| 520 |
vectorstore, UrlSources = trainChatbotConfig.vectorstore, trainChatbotConfig.urls
|
| 521 |
texts = []
|
| 522 |
sources = []
|
| 523 |
-
fileTypes = [supabase.table("ConversAI_ChatbotDataSources").select("sourceEndpoint").eq("sourceContentURL",
|
|
|
|
|
|
|
| 524 |
for source, fileType in zip(UrlSources, fileTypes):
|
| 525 |
if ((fileType == "/loadPDF") | (fileType == "/loadImagePDF")):
|
| 526 |
r = requests.get(source)
|
| 527 |
file = eval(r.content.decode("utf-8"))
|
| 528 |
content = file["output"]
|
| 529 |
fileSource = file["source"]
|
| 530 |
-
texts.append(".".join(
|
|
|
|
|
|
|
| 531 |
sources.append(fileSource)
|
| 532 |
elif fileType == "/loadText":
|
| 533 |
r = requests.get(source)
|
|
@@ -541,9 +548,188 @@ async def trainChatbot(trainChatbotConfig: TrainChatbot):
|
|
| 541 |
file = eval(r.content.decode("utf-8"))
|
| 542 |
content = file["output"]
|
| 543 |
fileSource = file["source"]
|
| 544 |
-
texts.append(".".join(
|
|
|
|
|
|
|
| 545 |
sources.append(fileSource)
|
| 546 |
else:
|
| 547 |
pass
|
| 548 |
texts = [(text, source) for text, source in zip(texts, sources)]
|
| 549 |
-
return addDocuments(texts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import io
|
| 2 |
import tempfile
|
| 3 |
+
from ipaddress import ip_address
|
| 4 |
+
from typing import Optional
|
| 5 |
+
|
| 6 |
import jwt
|
| 7 |
import base64
|
| 8 |
import json
|
|
|
|
| 11 |
from starlette import status
|
| 12 |
from functions import *
|
| 13 |
import pandas as pd
|
| 14 |
+
from fastapi import FastAPI, File, UploadFile, HTTPException, Request, Query
|
| 15 |
from pydantic import BaseModel
|
| 16 |
from fastapi.middleware.cors import CORSMiddleware
|
| 17 |
from src.api.speech_api import speech_translator_router
|
|
|
|
| 22 |
from datetime import datetime, timedelta
|
| 23 |
from dateutil.parser import isoparse
|
| 24 |
|
|
|
|
|
|
|
| 25 |
nltk.download('punkt_tab')
|
| 26 |
|
| 27 |
app = FastAPI(title="ConversAI", root_path="/api/v1")
|
|
|
|
| 266 |
"output": text,
|
| 267 |
"source": source
|
| 268 |
}
|
| 269 |
+
dct = json.dumps(dct, indent=1).encode("utf-8")
|
| 270 |
+
fileName = createDataSourceName(sourceName=source)
|
| 271 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 272 |
response = (
|
| 273 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 274 |
+
.insert({"username": username,
|
| 275 |
+
"chatbotName": chatbotName,
|
| 276 |
+
"dataSourceName": fileName,
|
| 277 |
+
"sourceEndpoint": "/loadPDF",
|
| 278 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 279 |
.execute()
|
| 280 |
)
|
|
|
|
| 283 |
}
|
| 284 |
|
| 285 |
|
|
|
|
| 286 |
@app.post("/loadImagePDF")
|
| 287 |
async def loadImagePDF(vectorstore: str, pdf: UploadFile = File(...)):
|
| 288 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
|
|
|
| 293 |
"output": text,
|
| 294 |
"source": source
|
| 295 |
}
|
| 296 |
+
dct = json.dumps(dct, indent=1).encode("utf-8")
|
| 297 |
+
fileName = createDataSourceName(sourceName=source)
|
| 298 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 299 |
response = (
|
| 300 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 301 |
+
.insert({"username": username,
|
| 302 |
+
"chatbotName": chatbotName,
|
| 303 |
+
"dataSourceName": fileName,
|
| 304 |
+
"sourceEndpoint": "/loadImagePDF",
|
| 305 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 306 |
.execute()
|
| 307 |
)
|
|
|
|
| 310 |
}
|
| 311 |
|
| 312 |
|
|
|
|
| 313 |
class AddText(BaseModel):
|
| 314 |
vectorstore: str
|
| 315 |
text: str
|
|
|
|
| 323 |
"output": text,
|
| 324 |
"source": "Text"
|
| 325 |
}
|
| 326 |
+
dct = json.dumps(dct, indent=1).encode("utf-8")
|
| 327 |
+
fileName = createDataSourceName(sourceName="Text")
|
| 328 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 329 |
response = (
|
| 330 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 331 |
+
.insert({"username": username,
|
| 332 |
+
"chatbotName": chatbotName,
|
| 333 |
+
"dataSourceName": fileName,
|
| 334 |
+
"sourceEndpoint": "/loadText",
|
| 335 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 336 |
.execute()
|
| 337 |
)
|
|
|
|
| 365 |
}
|
| 366 |
|
| 367 |
|
|
|
|
| 368 |
class LoadWebsite(BaseModel):
|
| 369 |
vectorstore: str
|
| 370 |
urls: list[str]
|
|
|
|
| 375 |
async def loadWebURLs(loadWebsite: LoadWebsite):
|
| 376 |
vectorstore, urls, source = loadWebsite.vectorstore, loadWebsite.urls, loadWebsite.source
|
| 377 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
| 378 |
+
text = extractTextFromUrlList(urls=urls)
|
| 379 |
dct = {
|
| 380 |
"output": text,
|
| 381 |
"source": source
|
| 382 |
}
|
| 383 |
+
dct = json.dumps(dct, indent=1).encode("utf-8")
|
| 384 |
+
fileName = createDataSourceName(sourceName=source)
|
| 385 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 386 |
response = (
|
| 387 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 388 |
+
.insert({"username": username,
|
| 389 |
+
"chatbotName": chatbotName,
|
| 390 |
+
"dataSourceName": fileName,
|
| 391 |
+
"sourceEndpoint": "/loadWebURLs",
|
| 392 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 393 |
.execute()
|
| 394 |
)
|
|
|
|
| 397 |
}
|
| 398 |
|
| 399 |
|
|
|
|
| 400 |
@app.post("/answerQuery")
|
| 401 |
+
async def answerQuestion(request: Request, query: str, vectorstore: str, llmModel: str = "llama3-70b-8192"):
|
| 402 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
| 403 |
output = answerQuery(query=query, vectorstore=vectorstore, llmModel=llmModel)
|
| 404 |
+
ip_address = request.client.host
|
| 405 |
+
response_token_count = len(output["output"])
|
| 406 |
+
city = get_ip_info(ip_address)
|
| 407 |
+
|
| 408 |
response = (
|
| 409 |
supabase.table("ConversAI_ChatHistory")
|
| 410 |
.insert({"username": username, "chatbotName": chatbotName, "llmModel": llmModel, "question": query,
|
| 411 |
+
"response": output["output"], "IpAddress": ip_address, "ResponseTokenCount": response_token_count,
|
| 412 |
+
"vectorstore": vectorstore, "City": city})
|
| 413 |
.execute()
|
| 414 |
)
|
| 415 |
return output
|
|
|
|
| 458 |
"output": text,
|
| 459 |
"source": "www.youtube.com"
|
| 460 |
}
|
| 461 |
+
dct = json.dumps(dct, indent=1).encode("utf-8")
|
| 462 |
+
fileName = createDataSourceName(sourceName="youtube")
|
| 463 |
response = supabase.storage.from_("ConversAI").upload(file=dct, path=f"{fileName}_data.json")
|
| 464 |
response = (
|
| 465 |
supabase.table("ConversAI_ChatbotDataSources")
|
| 466 |
+
.insert({"username": username,
|
| 467 |
+
"chatbotName": chatbotName,
|
| 468 |
+
"dataSourceName": fileName,
|
| 469 |
+
"sourceEndpoint": "/getYoutubeTranscript",
|
| 470 |
"sourceContentURL": os.path.join(os.environ["SUPABASE_PUBLIC_BASE_URL"], f"{fileName}_data.json")})
|
| 471 |
.execute()
|
| 472 |
)
|
|
|
|
| 508 |
@app.post("/listChatbotSources")
|
| 509 |
async def listChatbotSources(vectorstore: str):
|
| 510 |
username, chatbotName = vectorstore.split("$")[1], vectorstore.split("$")[2]
|
| 511 |
+
result = supabase.table("ConversAI_ChatbotDataSources").select("*").eq("username", username).eq("chatbotName",
|
| 512 |
+
chatbotName).execute().data
|
| 513 |
return result
|
| 514 |
|
| 515 |
|
|
|
|
| 523 |
vectorstore, UrlSources = trainChatbotConfig.vectorstore, trainChatbotConfig.urls
|
| 524 |
texts = []
|
| 525 |
sources = []
|
| 526 |
+
fileTypes = [supabase.table("ConversAI_ChatbotDataSources").select("sourceEndpoint").eq("sourceContentURL",
|
| 527 |
+
x).execute().data[0][
|
| 528 |
+
"sourceEndpoint"] for x in UrlSources]
|
| 529 |
for source, fileType in zip(UrlSources, fileTypes):
|
| 530 |
if ((fileType == "/loadPDF") | (fileType == "/loadImagePDF")):
|
| 531 |
r = requests.get(source)
|
| 532 |
file = eval(r.content.decode("utf-8"))
|
| 533 |
content = file["output"]
|
| 534 |
fileSource = file["source"]
|
| 535 |
+
texts.append(".".join(
|
| 536 |
+
[base64.b64decode(content[key].encode("utf-8")).decode("utf-8") for key in content.keys()]).replace(
|
| 537 |
+
"\n", " "))
|
| 538 |
sources.append(fileSource)
|
| 539 |
elif fileType == "/loadText":
|
| 540 |
r = requests.get(source)
|
|
|
|
| 548 |
file = eval(r.content.decode("utf-8"))
|
| 549 |
content = file["output"]
|
| 550 |
fileSource = file["source"]
|
| 551 |
+
texts.append(".".join(
|
| 552 |
+
[base64.b64decode(content[key].encode("utf-8")).decode("utf-8") for key in content.keys()]).replace(
|
| 553 |
+
"\n", " "))
|
| 554 |
sources.append(fileSource)
|
| 555 |
else:
|
| 556 |
pass
|
| 557 |
texts = [(text, source) for text, source in zip(texts, sources)]
|
| 558 |
+
return addDocuments(texts=texts, vectorstore=vectorstore)
|
| 559 |
+
|
| 560 |
+
|
| 561 |
+
def get_ip_info(ip: str):
|
| 562 |
+
try:
|
| 563 |
+
response = requests.get(f"https://ipinfo.io/{ip}/json")
|
| 564 |
+
data = response.json()
|
| 565 |
+
return data.get("city", "Unknown")
|
| 566 |
+
except Exception as e:
|
| 567 |
+
return "Unknown"
|
| 568 |
+
|
| 569 |
+
|
| 570 |
+
@app.post("/daily_chat_count")
|
| 571 |
+
async def daily_chat_count(
|
| 572 |
+
start_date: Optional[str] = Query(None, description="Start date in ISO format (YYYY-MM-DD)"),
|
| 573 |
+
end_date: Optional[str] = Query(None, description="End date in ISO format (YYYY-MM-DD)")
|
| 574 |
+
):
|
| 575 |
+
if not start_date or not end_date:
|
| 576 |
+
end_date = datetime.now().astimezone().date()
|
| 577 |
+
start_date = end_date - timedelta(days=7)
|
| 578 |
+
else:
|
| 579 |
+
start_date = isoparse(start_date).date()
|
| 580 |
+
end_date = isoparse(end_date).date()
|
| 581 |
+
|
| 582 |
+
response = supabase.table("ConversAI_ChatHistory").select("*").execute().data
|
| 583 |
+
|
| 584 |
+
dates = [
|
| 585 |
+
isoparse(i["timestamp"]).date()
|
| 586 |
+
for i in response
|
| 587 |
+
if start_date <= isoparse(i["timestamp"]).date() <= end_date
|
| 588 |
+
]
|
| 589 |
+
|
| 590 |
+
date_count = Counter(dates)
|
| 591 |
+
|
| 592 |
+
data = [{"date": date.isoformat(), "count": count} for date, count in date_count.items()]
|
| 593 |
+
|
| 594 |
+
return {"data": data}
|
| 595 |
+
|
| 596 |
+
|
| 597 |
+
@app.post("/daily_active_end_user")
|
| 598 |
+
async def daily_active_end_user(
|
| 599 |
+
start_date: Optional[str] = Query(None, description="Start date in ISO format (YYYY-MM-DD)"),
|
| 600 |
+
end_date: Optional[str] = Query(None, description="End date in ISO format (YYYY-MM-DD)")
|
| 601 |
+
):
|
| 602 |
+
if not start_date or not end_date:
|
| 603 |
+
end_date = datetime.now().astimezone().date()
|
| 604 |
+
start_date = end_date - timedelta(days=7)
|
| 605 |
+
else:
|
| 606 |
+
start_date = isoparse(start_date).date()
|
| 607 |
+
end_date = isoparse(end_date).date()
|
| 608 |
+
|
| 609 |
+
response = supabase.table("ConversAI_ChatHistory").select("*").execute().data
|
| 610 |
+
|
| 611 |
+
ip_by_date = defaultdict(set)
|
| 612 |
+
|
| 613 |
+
for i in response:
|
| 614 |
+
timestamp = isoparse(i["timestamp"])
|
| 615 |
+
ip_address = i["IpAddress"]
|
| 616 |
+
if start_date <= timestamp.date() <= end_date:
|
| 617 |
+
date = timestamp.date()
|
| 618 |
+
ip_by_date[date].add(ip_address)
|
| 619 |
+
|
| 620 |
+
data = [{"date": date.isoformat(), "terminal": len(ips)} for date, ips in ip_by_date.items() if len(ips) > 1]
|
| 621 |
+
|
| 622 |
+
return {"data": data}
|
| 623 |
+
|
| 624 |
+
|
| 625 |
+
@app.post("/average_session_interaction")
|
| 626 |
+
async def average_session_interaction(
|
| 627 |
+
start_date: Optional[str] = Query(None, description="Start date in ISO format (YYYY-MM-DD)"),
|
| 628 |
+
end_date: Optional[str] = Query(None, description="End date in ISO format (YYYY-MM-DD)")
|
| 629 |
+
):
|
| 630 |
+
if not start_date or not end_date:
|
| 631 |
+
end_date = datetime.now().astimezone().date()
|
| 632 |
+
start_date = end_date - timedelta(days=7)
|
| 633 |
+
else:
|
| 634 |
+
start_date = isoparse(start_date).date()
|
| 635 |
+
end_date = isoparse(end_date).date()
|
| 636 |
+
|
| 637 |
+
response = supabase.table("ConversAI_ChatHistory").select("*").execute().data
|
| 638 |
+
|
| 639 |
+
total_messages_by_date = defaultdict(int)
|
| 640 |
+
unique_ips_by_date = defaultdict(set)
|
| 641 |
+
|
| 642 |
+
for i in response:
|
| 643 |
+
timestamp = isoparse(i["timestamp"])
|
| 644 |
+
ip_address = i["IpAddress"]
|
| 645 |
+
if start_date <= timestamp.date() <= end_date:
|
| 646 |
+
date = timestamp.date()
|
| 647 |
+
total_messages_by_date[date] += 1
|
| 648 |
+
unique_ips_by_date[date].add(ip_address)
|
| 649 |
+
|
| 650 |
+
data = []
|
| 651 |
+
for date in sorted(total_messages_by_date.keys()):
|
| 652 |
+
total_messages = total_messages_by_date[date]
|
| 653 |
+
unique_ips = len(unique_ips_by_date[date])
|
| 654 |
+
average_interactions = total_messages / unique_ips if unique_ips > 0 else 0
|
| 655 |
+
data.append({"date": date.isoformat(), "interactions": average_interactions})
|
| 656 |
+
|
| 657 |
+
return {"data": data}
|
| 658 |
+
|
| 659 |
+
|
| 660 |
+
@app.post("/token_usages")
|
| 661 |
+
async def token_usages(
|
| 662 |
+
start_date: Optional[str] = Query(None, description="Start date in ISO format (YYYY-MM-DD)"),
|
| 663 |
+
end_date: Optional[str] = Query(None, description="End date in ISO format (YYYY-MM-DD)")
|
| 664 |
+
):
|
| 665 |
+
if not start_date or not end_date:
|
| 666 |
+
end_date = datetime.now().astimezone().date()
|
| 667 |
+
start_date = end_date - timedelta(days=7)
|
| 668 |
+
else:
|
| 669 |
+
start_date = isoparse(start_date).date()
|
| 670 |
+
end_date = isoparse(end_date).date()
|
| 671 |
+
|
| 672 |
+
response = supabase.table("ConversAI_ChatHistory").select("*").execute().data
|
| 673 |
+
|
| 674 |
+
token_usage_by_date = defaultdict(int)
|
| 675 |
+
|
| 676 |
+
for i in response:
|
| 677 |
+
timestamp = isoparse(i["timestamp"])
|
| 678 |
+
if start_date <= timestamp.date() <= end_date:
|
| 679 |
+
date = timestamp.date()
|
| 680 |
+
response_token_count = i.get("ResponseTokenCount")
|
| 681 |
+
if response_token_count is not None:
|
| 682 |
+
token_usage_by_date[date] += response_token_count
|
| 683 |
+
|
| 684 |
+
data = [{"date": date.isoformat(), "total_tokens": total_tokens} for date, total_tokens in
|
| 685 |
+
token_usage_by_date.items()]
|
| 686 |
+
|
| 687 |
+
return {"data": data}
|
| 688 |
+
|
| 689 |
+
|
| 690 |
+
@app.post("/add_feedback")
|
| 691 |
+
async def add_feedback(request: Request, feedback: str, user_id: str):
|
| 692 |
+
client_ip = request.client.host
|
| 693 |
+
city = get_ip_info(client_ip)
|
| 694 |
+
|
| 695 |
+
response = supabase.table("ConversAI_Feedback").insert(
|
| 696 |
+
{"feedback": feedback, "user_id": user_id, "city": city, "ip": client_ip}).execute()
|
| 697 |
+
|
| 698 |
+
return {"message": "success"}
|
| 699 |
+
|
| 700 |
+
|
| 701 |
+
@app.post("/user_satisfaction_rate")
|
| 702 |
+
async def user_satisfaction_rate(
|
| 703 |
+
start_date: Optional[str] = Query(None, description="Start date in ISO format (YYYY-MM-DD)"),
|
| 704 |
+
end_date: Optional[str] = Query(None, description="End date in ISO format (YYYY-MM-DD)")
|
| 705 |
+
):
|
| 706 |
+
if not start_date or not end_date:
|
| 707 |
+
end_date = datetime.now().astimezone().date()
|
| 708 |
+
start_date = end_date - timedelta(days=7)
|
| 709 |
+
else:
|
| 710 |
+
start_date = isoparse(start_date).date()
|
| 711 |
+
end_date = isoparse(end_date).date()
|
| 712 |
+
|
| 713 |
+
response = supabase.table("ConversAI_Feedback").select("*").execute().data
|
| 714 |
+
|
| 715 |
+
feedback_counts = defaultdict(lambda: {"like": 0, "dislike": 0})
|
| 716 |
+
|
| 717 |
+
for i in response:
|
| 718 |
+
timestamp = isoparse(i["timestamp"])
|
| 719 |
+
if start_date <= timestamp.date() <= end_date:
|
| 720 |
+
date = timestamp.date()
|
| 721 |
+
feedback = i.get("feedback")
|
| 722 |
+
if feedback == "like":
|
| 723 |
+
feedback_counts[date]["like"] += 1
|
| 724 |
+
elif feedback == "dislike":
|
| 725 |
+
feedback_counts[date]["dislike"] += 1
|
| 726 |
+
|
| 727 |
+
data = []
|
| 728 |
+
for date in sorted(feedback_counts.keys()):
|
| 729 |
+
like_count = feedback_counts[date]["like"]
|
| 730 |
+
dislike_count = feedback_counts[date]["dislike"]
|
| 731 |
+
total_feedback = like_count + dislike_count
|
| 732 |
+
satisfaction_rate = (like_count / total_feedback * 100) if total_feedback > 0 else 0
|
| 733 |
+
data.append({"date": date.isoformat(), "rate": satisfaction_rate})
|
| 734 |
+
|
| 735 |
+
return {"data": data}
|