cevheri commited on
Commit
b27b4c3
·
1 Parent(s): b6232be

feat: mongita first implementation

Browse files
.env.sample CHANGED
@@ -7,7 +7,10 @@ SECRET_KEY="1234"
7
  API_KEY="sk-lokumai=="
8
  BASE_URL="http://0.0.0.0:7860"
9
 
10
- STORAGE_TYPE=embedded
11
- # when your are using STORAGE_TYPE=mongodb
 
 
 
 
12
  DB_MONGO_URI=mongodb://localhost:27017
13
- DB_MONGO_DATABASE_NAME=lokumai
 
7
  API_KEY="sk-lokumai=="
8
  BASE_URL="http://0.0.0.0:7860"
9
 
10
+ # mongodb, mongita_memory, mongita_disk
11
+ DB_DATABASE_TYPE=mongita_memory
12
+ # when type is disk
13
+ DB_MONGITA_DB_PATH="./local_dev.db"
14
+
15
+ DB_DATABASE_NAME=lokumai
16
  DB_MONGO_URI=mongodb://localhost:27017
 
app/api/chat_api.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  from typing import List
4
  from fastapi import APIRouter, HTTPException, Depends, Request
 
5
  from app.schema.chat_schema import (
6
  ChatCompletionRequest,
7
  ChatCompletionResponse,
@@ -21,6 +22,13 @@ router = APIRouter(prefix="/v1", tags=["chat"])
21
  service = ChatService()
22
  auth_service = AuthService()
23
 
 
 
 
 
 
 
 
24
 
25
  ################
26
  # chat completion api list
 
2
 
3
  from typing import List
4
  from fastapi import APIRouter, HTTPException, Depends, Request
5
+ from pydantic import BaseModel
6
  from app.schema.chat_schema import (
7
  ChatCompletionRequest,
8
  ChatCompletionResponse,
 
22
  service = ChatService()
23
  auth_service = AuthService()
24
 
25
+ class VersionResponse(BaseModel):
26
+ version: str = "0.0.1"
27
+
28
+ # version api from pyproject.toml
29
+ @router.get("/version", response_model=VersionResponse)
30
+ async def get_version():
31
+ return VersionResponse()
32
 
33
  ################
34
  # chat completion api list
app/config/db.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from pydantic_settings import BaseSettings, SettingsConfigDict
2
 
3
 
@@ -9,12 +10,18 @@ class DBConfig(BaseSettings):
9
  extra="ignore",
10
  )
11
 
 
 
 
 
 
12
  MONGO_USER: str = "root"
13
  MONGO_PASSWORD: str = "rootPass"
14
  MONGO_HOST: str = "localhost"
15
  MONGO_PORT: int = 27017
16
- MONGO_DATABASE_NAME: str = "openai_chatbot_api"
17
- MONGO_URI: str = f"mongodb://{MONGO_USER}:{MONGO_PASSWORD}@{MONGO_HOST}:{MONGO_PORT}/{MONGO_DATABASE_NAME}"
 
18
 
19
  def get_mongo_uri(self) -> str:
20
  return self.MONGO_URI
 
1
+ from typing import Literal, Optional
2
  from pydantic_settings import BaseSettings, SettingsConfigDict
3
 
4
 
 
10
  extra="ignore",
11
  )
12
 
13
+
14
+ DATABASE_TYPE: Literal["mongodb", "mongita_disk", "mongita_memory"] = "mongodb"
15
+ DATABASE_NAME: str = "openai_chatbot_api"
16
+ MONGITA_DB_PATH: Optional[str] = None
17
+
18
  MONGO_USER: str = "root"
19
  MONGO_PASSWORD: str = "rootPass"
20
  MONGO_HOST: str = "localhost"
21
  MONGO_PORT: int = 27017
22
+ MONGO_URI: str = f"mongodb://{MONGO_USER}:{MONGO_PASSWORD}@{MONGO_HOST}:{MONGO_PORT}/{DATABASE_NAME}"
23
+
24
+
25
 
26
  def get_mongo_uri(self) -> str:
27
  return self.MONGO_URI
app/db/client.py CHANGED
@@ -9,7 +9,7 @@ from environs import Env
9
  env = Env()
10
  env.read_env()
11
 
12
- STORAGE_TYPE = env.str("STORAGE_TYPE", "mongodb")
13
 
14
 
15
  class MongoDBClient:
@@ -26,7 +26,7 @@ class MongoDBClient:
26
  def __init__(self):
27
  if self._client is None:
28
  self._client = AsyncIOMotorClient(db_config.get_mongo_uri())
29
- self._db = self._client[db_config.MONGO_DATABASE_NAME]
30
 
31
  @property
32
  def client(self) -> AsyncIOMotorClient:
@@ -41,7 +41,7 @@ class MongoDBClient:
41
  if not self._is_connected:
42
  if self._client is None:
43
  self._client = AsyncIOMotorClient(db_config.get_mongo_uri())
44
- self._db = self._client[db_config.MONGO_DATABASE_NAME]
45
  await self._client.server_info()
46
  self._is_connected = True
47
  logger.info("Connected to MongoDB")
 
9
  env = Env()
10
  env.read_env()
11
 
12
+ DB_DATABASE_TYPE = env.str("DB_DATABASE_TYPE", "mongodb")
13
 
14
 
15
  class MongoDBClient:
 
26
  def __init__(self):
27
  if self._client is None:
28
  self._client = AsyncIOMotorClient(db_config.get_mongo_uri())
29
+ self._db = self._client[db_config.DATABASE_NAME]
30
 
31
  @property
32
  def client(self) -> AsyncIOMotorClient:
 
41
  if not self._is_connected:
42
  if self._client is None:
43
  self._client = AsyncIOMotorClient(db_config.get_mongo_uri())
44
+ self._db = self._client[db_config.DATABASE_NAME]
45
  await self._client.server_info()
46
  self._is_connected = True
47
  logger.info("Connected to MongoDB")
main.py CHANGED
@@ -18,7 +18,7 @@ print(log_config.get_log_level())
18
  env = Env()
19
  env.read_env()
20
 
21
- STORAGE_TYPE = env.str("STORAGE_TYPE", "mongodb")
22
 
23
  # Hugging Face Spaces için özel yapılandırma
24
  IS_HF_SPACE = os.environ.get("SPACE_ID") is not None
@@ -33,13 +33,13 @@ async def lifespan(app: FastAPI):
33
  """
34
  # Startup
35
  logger.info("Starting up application...")
36
- if STORAGE_TYPE == "mongodb":
37
  await mongodb.connect()
38
  yield
39
 
40
  # Shutdown
41
  logger.info("Shutting down application...")
42
- if STORAGE_TYPE == "mongodb":
43
  await mongodb.close()
44
 
45
 
 
18
  env = Env()
19
  env.read_env()
20
 
21
+ DB_DATABASE_TYPE = env.str("DB_DATABASE_TYPE", "mongodb")
22
 
23
  # Hugging Face Spaces için özel yapılandırma
24
  IS_HF_SPACE = os.environ.get("SPACE_ID") is not None
 
33
  """
34
  # Startup
35
  logger.info("Starting up application...")
36
+ if DB_DATABASE_TYPE == "mongodb":
37
  await mongodb.connect()
38
  yield
39
 
40
  # Shutdown
41
  logger.info("Shutting down application...")
42
+ if DB_DATABASE_TYPE == "mongodb":
43
  await mongodb.close()
44
 
45
 
pyproject.toml CHANGED
@@ -10,6 +10,7 @@ dependencies = [
10
  "gradio>=5.30.0",
11
  "httpx>=0.28.1",
12
  "loguru>=0.7.3",
 
13
  "motor>=3.7.1",
14
  "plotly>=6.1.1",
15
  "pydantic>=2.11.4",
@@ -21,4 +22,4 @@ dependencies = [
21
 
22
  # ruff line length
23
  [tool.ruff]
24
- line-length = 145
 
10
  "gradio>=5.30.0",
11
  "httpx>=0.28.1",
12
  "loguru>=0.7.3",
13
+ "mongita>=1.2.0",
14
  "motor>=3.7.1",
15
  "plotly>=6.1.1",
16
  "pydantic>=2.11.4",
 
22
 
23
  # ruff line length
24
  [tool.ruff]
25
+ line-length = 145
resources/mock/chat_api_list_messages.json CHANGED
@@ -1,6 +1,6 @@
1
  [
2
  {
3
- "message_id": "msg_mock-123",
4
  "role": "assistant",
5
  "content": "## Result\n|status|count|\n|---|---|\n|active|100|\n|cancelled|30|\n|pending|40|\n|passive|150|\n\n## Explanation\nThis result represents the number of active, cancelled, pending and passive customers in the year 2025. This is a mock result for the question \"How many customers are active, cancelled, pending and passive in the year 2025?\"\n\n## Query\n```sql\nSELECT status, COUNT(*) FROM customers WHERE year = 2025 GROUP BY status;\n```",
6
  "figure": {"data":[{"alignmentgroup":"True","customdata":[["North"],["North"],["South"]],"hovertemplate":"category=Category A\u003cbr\u003estatus=%{x}\u003cbr\u003ecount=%{y}\u003cbr\u003eregion=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"Category A","marker":{"color":"#636efa","pattern":{"shape":""}},"name":"Category A","offsetgroup":"Category A","orientation":"v","showlegend":true,"textposition":"auto","texttemplate":"%{y}","x":["active","in_review","pending_deletion"],"xaxis":"x","y":{"dtype":"i1","bdata":"Mh4P"},"yaxis":"y","type":"bar"},{"alignmentgroup":"True","customdata":[["South"],["West"]],"hovertemplate":"category=Category B\u003cbr\u003estatus=%{x}\u003cbr\u003ecount=%{y}\u003cbr\u003eregion=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"Category B","marker":{"color":"#EF553B","pattern":{"shape":""}},"name":"Category B","offsetgroup":"Category B","orientation":"v","showlegend":true,"textposition":"auto","texttemplate":"%{y}","x":["passive","newly_added"],"xaxis":"x","y":{"dtype":"i1","bdata":"Rhk="},"yaxis":"y","type":"bar"},{"alignmentgroup":"True","customdata":[["East"]],"hovertemplate":"category=Category C\u003cbr\u003estatus=%{x}\u003cbr\u003ecount=%{y}\u003cbr\u003eregion=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"Category C","marker":{"color":"#00cc96","pattern":{"shape":""}},"name":"Category C","offsetgroup":"Category C","orientation":"v","showlegend":true,"textposition":"auto","texttemplate":"%{y}","x":["archived"],"xaxis":"x","y":{"dtype":"i1","bdata":"Wg=="},"yaxis":"y","type":"bar"}],"layout":{"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Status"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Count"}},"legend":{"title":{"text":"Category"},"tracegroupgap":0},"title":{"text":"Bar Chart: Count by Status and Category","x":0.5},"barmode":"group"}}
 
1
  [
2
  {
3
+ "message_id": "msg_mock-1234",
4
  "role": "assistant",
5
  "content": "## Result\n|status|count|\n|---|---|\n|active|100|\n|cancelled|30|\n|pending|40|\n|passive|150|\n\n## Explanation\nThis result represents the number of active, cancelled, pending and passive customers in the year 2025. This is a mock result for the question \"How many customers are active, cancelled, pending and passive in the year 2025?\"\n\n## Query\n```sql\nSELECT status, COUNT(*) FROM customers WHERE year = 2025 GROUP BY status;\n```",
6
  "figure": {"data":[{"alignmentgroup":"True","customdata":[["North"],["North"],["South"]],"hovertemplate":"category=Category A\u003cbr\u003estatus=%{x}\u003cbr\u003ecount=%{y}\u003cbr\u003eregion=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"Category A","marker":{"color":"#636efa","pattern":{"shape":""}},"name":"Category A","offsetgroup":"Category A","orientation":"v","showlegend":true,"textposition":"auto","texttemplate":"%{y}","x":["active","in_review","pending_deletion"],"xaxis":"x","y":{"dtype":"i1","bdata":"Mh4P"},"yaxis":"y","type":"bar"},{"alignmentgroup":"True","customdata":[["South"],["West"]],"hovertemplate":"category=Category B\u003cbr\u003estatus=%{x}\u003cbr\u003ecount=%{y}\u003cbr\u003eregion=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"Category B","marker":{"color":"#EF553B","pattern":{"shape":""}},"name":"Category B","offsetgroup":"Category B","orientation":"v","showlegend":true,"textposition":"auto","texttemplate":"%{y}","x":["passive","newly_added"],"xaxis":"x","y":{"dtype":"i1","bdata":"Rhk="},"yaxis":"y","type":"bar"},{"alignmentgroup":"True","customdata":[["East"]],"hovertemplate":"category=Category C\u003cbr\u003estatus=%{x}\u003cbr\u003ecount=%{y}\u003cbr\u003eregion=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"Category C","marker":{"color":"#00cc96","pattern":{"shape":""}},"name":"Category C","offsetgroup":"Category C","orientation":"v","showlegend":true,"textposition":"auto","texttemplate":"%{y}","x":["archived"],"xaxis":"x","y":{"dtype":"i1","bdata":"Wg=="},"yaxis":"y","type":"bar"}],"layout":{"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Status"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Count"}},"legend":{"title":{"text":"Category"},"tracegroupgap":0},"title":{"text":"Bar Chart: Count by Status and Category","x":0.5},"barmode":"group"}}
uv.lock CHANGED
@@ -429,6 +429,16 @@ wheels = [
429
  { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
430
  ]
431
 
 
 
 
 
 
 
 
 
 
 
432
  [[package]]
433
  name = "motor"
434
  version = "3.7.1"
@@ -498,6 +508,7 @@ dependencies = [
498
  { name = "gradio" },
499
  { name = "httpx" },
500
  { name = "loguru" },
 
501
  { name = "motor" },
502
  { name = "plotly" },
503
  { name = "pydantic" },
@@ -514,6 +525,7 @@ requires-dist = [
514
  { name = "gradio", specifier = ">=5.30.0" },
515
  { name = "httpx", specifier = ">=0.28.1" },
516
  { name = "loguru", specifier = ">=0.7.3" },
 
517
  { name = "motor", specifier = ">=3.7.1" },
518
  { name = "plotly", specifier = ">=6.1.1" },
519
  { name = "pydantic", specifier = ">=2.11.4" },
@@ -951,6 +963,15 @@ wheels = [
951
  { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
952
  ]
953
 
 
 
 
 
 
 
 
 
 
954
  [[package]]
955
  name = "starlette"
956
  version = "0.46.2"
 
429
  { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
430
  ]
431
 
432
+ [[package]]
433
+ name = "mongita"
434
+ version = "1.2.0"
435
+ source = { registry = "https://pypi.org/simple" }
436
+ dependencies = [
437
+ { name = "pymongo" },
438
+ { name = "sortedcontainers" },
439
+ ]
440
+ sdist = { url = "https://files.pythonhosted.org/packages/a4/b6/9159dca5e74e497b19ab8e68c369f789dc2167d2c8cccb5fbd21377ba040/mongita-1.2.0.tar.gz", hash = "sha256:27487d1deb40d83e4ecb107c3d9d732d369a83cc5f10599ba86fc024e2ce9cda", size = 54582 }
441
+
442
  [[package]]
443
  name = "motor"
444
  version = "3.7.1"
 
508
  { name = "gradio" },
509
  { name = "httpx" },
510
  { name = "loguru" },
511
+ { name = "mongita" },
512
  { name = "motor" },
513
  { name = "plotly" },
514
  { name = "pydantic" },
 
525
  { name = "gradio", specifier = ">=5.30.0" },
526
  { name = "httpx", specifier = ">=0.28.1" },
527
  { name = "loguru", specifier = ">=0.7.3" },
528
+ { name = "mongita", specifier = ">=1.2.0" },
529
  { name = "motor", specifier = ">=3.7.1" },
530
  { name = "plotly", specifier = ">=6.1.1" },
531
  { name = "pydantic", specifier = ">=2.11.4" },
 
963
  { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
964
  ]
965
 
966
+ [[package]]
967
+ name = "sortedcontainers"
968
+ version = "2.4.0"
969
+ source = { registry = "https://pypi.org/simple" }
970
+ sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 }
971
+ wheels = [
972
+ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 },
973
+ ]
974
+
975
  [[package]]
976
  name = "starlette"
977
  version = "0.46.2"