cevheri commited on
Commit
bcd6d73
·
1 Parent(s): a17e5a6

chore: format, improve logging, remove deprecated code

Browse files
.dockerignore CHANGED
@@ -1,6 +1,5 @@
1
  .git/
2
  .github/
3
- .vscode/
4
  .venv/
5
  __pycache__/
6
  dist/
 
1
  .git/
2
  .github/
 
3
  .venv/
4
  __pycache__/
5
  dist/
app/agent/chat_agent_client.py CHANGED
@@ -9,6 +9,6 @@ class ChatAgentClient:
9
  # TODO implement the logic to process the chat
10
  agent_name = self.agent_name
11
  return AssistantChatAgentResponse(
12
- message=f"Here is the {agent_name} Processed message: This is a placeholder response for the user-question",
13
  figure=None, # Placeholder for any figure data if needed
14
  )
 
9
  # TODO implement the logic to process the chat
10
  agent_name = self.agent_name
11
  return AssistantChatAgentResponse(
12
+ message=f"Here is the {agent_name} Processed message: This is a placeholder response for the user-question typeOfTheRequest:{type(user_chat_agent_request)}",
13
  figure=None, # Placeholder for any figure data if needed
14
  )
app/core/api_response.py CHANGED
@@ -1,5 +1,5 @@
1
  from functools import wraps
2
- import re
3
  from fastapi import HTTPException, Request, status
4
  from loguru import logger
5
  import os
@@ -10,55 +10,18 @@ from environs import Env
10
  env = Env()
11
  env.read_env()
12
 
13
- USE_MOCK = env.bool("USE_MOCK", True)
14
  MOCK_DIR = env.str("MOCK_DIR", "resources/mock")
15
 
16
  # Deprecated code. because we are using mongomock-motor for database_type=embedded
17
- # TODO: remove this code after we switch to real database
18
-
19
-
20
- def url_to_filename(url: str, method: str) -> str:
21
- """
22
- Convert API URL to mock filename.
23
- Example:
24
- - Input: GET "/v1/chat/completions" -> "chat_completions_GET.json"
25
- - Input: GET "/v1/chat/completions/{completion_id}" -> "chat_completions_id_GET.json"
26
- - Input: GET "/v1/chat/completions/123/messages" -> "chat_completions_id_messages_GET.json"
27
- """
28
- logger.trace(f"BEGIN: url: {url} method: {method}")
29
- # Remove version prefix and leading/trailing slashes
30
- path = url.strip("/")
31
- if path.startswith("v1/"):
32
- path = path[3:]
33
-
34
- # Replace path parameters with descriptive names
35
- path = path.replace("{completion_id}", "id")
36
- path = path.replace("{message_id}", "id")
37
-
38
- logger.trace(f"replaced path: {path}")
39
-
40
- # Convert to filename format
41
- filename = path.replace("/", "_")
42
- logger.trace(f"filename: {filename}")
43
-
44
- # convert conversations_1 to conversations with dynamic id
45
- final_filename = re.sub(r"[_][^/]+$", "_id", filename)
46
- logger.trace(f"final_filename: {final_filename}")
47
-
48
- # Add method suffix
49
- result = f"{final_filename}_{method}"
50
- logger.trace(f"END: result: {result}")
51
- return result
52
 
53
 
 
54
  def get_mock_response(url_path: str, python_module_name: str, python_method_name: str) -> Dict:
55
  """Get mock response from JSON file."""
56
  logger.trace(f"BEGIN: url_path: {url_path} python_module_name: {python_module_name} python_method_name: {python_method_name}")
57
- filename = None
58
  file_path = None
59
  try:
60
- # Convert to filename
61
- # filename = url_to_filename(url_path, method)
62
  filename = python_module_name + "_" + python_method_name
63
  filename = filename.replace(".", "_")
64
  filename = filename.replace("__", "_")
@@ -67,7 +30,7 @@ def get_mock_response(url_path: str, python_module_name: str, python_method_name
67
  filename = filename.replace(" ", "_")
68
  filename = filename.replace("-", "_")
69
  filename = filename.replace("app_api_", "")
70
-
71
  # Load mock response
72
  file_path = os.path.join(MOCK_DIR, f"{filename}.json")
73
 
@@ -89,7 +52,7 @@ def get_mock_response(url_path: str, python_module_name: str, python_method_name
89
 
90
 
91
  def api_response():
92
- """Decorator to handle mock/real API responses."""
93
 
94
  def decorator(func):
95
  logger.trace(f"BEGIN: decorator: {func}")
 
1
  from functools import wraps
2
+ from warnings import deprecated
3
  from fastapi import HTTPException, Request, status
4
  from loguru import logger
5
  import os
 
10
  env = Env()
11
  env.read_env()
12
 
13
+ USE_MOCK = env.bool("USE_MOCK", False)
14
  MOCK_DIR = env.str("MOCK_DIR", "resources/mock")
15
 
16
  # Deprecated code. because we are using mongomock-motor for database_type=embedded
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
 
19
+ @deprecated("This function is deprecated. Use database_type=embedded with mongomock-motor instead.")
20
  def get_mock_response(url_path: str, python_module_name: str, python_method_name: str) -> Dict:
21
  """Get mock response from JSON file."""
22
  logger.trace(f"BEGIN: url_path: {url_path} python_module_name: {python_module_name} python_method_name: {python_method_name}")
 
23
  file_path = None
24
  try:
 
 
25
  filename = python_module_name + "_" + python_method_name
26
  filename = filename.replace(".", "_")
27
  filename = filename.replace("__", "_")
 
30
  filename = filename.replace(" ", "_")
31
  filename = filename.replace("-", "_")
32
  filename = filename.replace("app_api_", "")
33
+ logger.trace(f"FileName : {filename}")
34
  # Load mock response
35
  file_path = os.path.join(MOCK_DIR, f"{filename}.json")
36
 
 
52
 
53
 
54
  def api_response():
55
+ """Decorator to handle API request and response"""
56
 
57
  def decorator(func):
58
  logger.trace(f"BEGIN: decorator: {func}")
app/mapper/chat_mapper.py CHANGED
@@ -1,4 +1,4 @@
1
- import datetime
2
  from app.mapper.base_mapper import BaseMapper
3
  from app.model.chat_model import ChatCompletion, ChatMessageModel
4
  from app.schema.chat_schema import ChatCompletionResponse, ChatCompletionRequest, ChatMessageResponse, ChoiceResponse
 
1
+ from datetime import datetime
2
  from app.mapper.base_mapper import BaseMapper
3
  from app.model.chat_model import ChatCompletion, ChatMessageModel
4
  from app.schema.chat_schema import ChatCompletionResponse, ChatCompletionRequest, ChatMessageResponse, ChoiceResponse
app/model/chat_model.py CHANGED
@@ -5,51 +5,6 @@ from pydantic import BaseModel, Field
5
  from datetime import datetime
6
  from typing import List, Optional, Any
7
 
8
- # Chat completion payload example
9
- # {
10
- # "model": "gpt-4o",
11
- # "messages": [
12
- # {
13
- # "role": "system",
14
- # "content": "You are a travel assistant with expertise in creating personalized travel itineraries. Provide detailed, practical, and concise recommendations, including specific locations, activities, and tips based on the user's preferences. Always consider budget, travel dates, and any special requests."
15
- # },
16
- # {
17
- # "role": "user",
18
- # "content": "I'm planning a 5-day trip to Italy in June 2025 with a moderate budget. I love history, food, and scenic views. Where should I go, and what should I do?"
19
- # },
20
- # {
21
- # "role": "assistant",
22
- # "content": "For a 5-day trip to Italy with a focus on history, food, and scenic views on a moderate budget, I recommend visiting Rome and Florence. Here's a suggested itinerary:\n\n**Day 1-3: Rome**\n- **Day 1**: Visit the Colosseum (book skip-the-line tickets online for ~€16) and Roman Forum for a dive into ancient history. Enjoy dinner at a trattoria in Trastevere, like Osteria da Zi Umberto (~€15-20 per person).\n- **Day 2**: Explore the Pantheon (free entry) and Vatican Museums (Sistine Chapel, ~€20). Take an evening stroll at Piazza Navona. Try gelato at Gelateria del Teatro (~€3).\n- **Day 3**: Visit the Capitoline Museums (€15) and take a scenic walk along the Tiber River. Enjoy carbonara at Roscioli (~€12).\n\n**Day 4-5: Florence**\n- **Day 4**: Take a morning train from Rome to Florence (~€30, 1.5 hours). Visit the Uffizi Gallery (book ahead, ~€20) and stroll Ponte Vecchio for views. Dine at Trattoria Mario for affordable Tuscan dishes (~€10-15).\n- **Day 5**: Explore the Florence Cathedral (Duomo, free entry; dome climb ~€20) and enjoy views from Piazzale Michelangelo (free). Try a lampredotto sandwich at a local food stall (~€5).\n\n**Tips**: Book accommodations like budget hotels or Airbnb (~€60-100/night). Use regional trains for cost savings. June weather is warm, so pack light clothing and book tickets early to avoid crowds."
23
- # },
24
- # {
25
- # "role": "user",
26
- # "content": "That sounds great! Can you suggest a specific hotel in Rome and any food markets to visit in Florence?"
27
- # },
28
- # {
29
- # "role": "assistant",
30
- # "content": "**Rome Hotel**: Consider **Hotel Artemide**, a centrally located 4-star hotel with rates around €80-100 per night on a moderate budget. It's near Termini Station and within walking distance of major sites like the Trevi Fountain. Book directly for potential deals.\n\n**Florence Food Markets**:\n- **Mercato Centrale**: A vibrant indoor market with food stalls offering fresh pasta, pizza, and local cheeses. Try a plate of fresh tortellini (~€8) or focaccia. Open daily, great for lunch.\n- **Sant'Ambrogio Market**: Less touristy, with fresh produce and local specialties like porchetta sandwiches (~€5). It's perfect for an authentic experience, located near Santa Croce. Open mornings until 2 PM.\n\n**Tip**: In Florence, pair market visits with a stop at a nearby café for espresso (~€1.50) to soak in the local vibe."
31
- # },
32
- # {
33
- # "role": "user",
34
- # "content": "What about transportation between cities and within Florence?"
35
- # },
36
- # {
37
- # "role": "assistant",
38
- # "content": "**Between Cities**: Take a high-speed train (Italo or Trenitalia) from Rome to Florence. Book in advance for tickets around €25-35 one-way (1.5 hours). Trains depart from Roma Termini and arrive at Firenze Santa Maria Novella. Check schedules on trenitalia.com or italo.it.\n\n**Within Florence**: Florence is compact and walkable, so you won't need much public transport. For longer distances (e.g., to Piazzale Michelangelo), use ATAF buses (~€1.50 per ride, buy tickets at tabaccherie). Alternatively, rent a bike (~€10/day) for a scenic way to explore. Taxis are pricier (~€10-15 for short trips), so stick to walking or buses for budget travel.",
39
- # "figure": {
40
- # "data": {},
41
- # "layout": {}
42
- # }
43
- # }
44
- # ],
45
- # "temperature": 0.8,
46
- # "max_tokens": 500,
47
- # "top_p": 1.0,
48
- # "frequency_penalty": 0.2,
49
- # "presence_penalty": 0.1
50
- # "stream": false
51
- # }
52
-
53
 
54
  class ChatMessageModel(BaseModel):
55
  """
 
5
  from datetime import datetime
6
  from typing import List, Optional, Any
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  class ChatMessageModel(BaseModel):
10
  """
app/repository/chat_repository.py CHANGED
@@ -163,7 +163,7 @@ class ChatRepository:
163
  return final_entity
164
  except Exception as e:
165
  logger.error(f"Error parsing ChatCompletion from DB for id {completion_id}: {e}", exc_info=True)
166
- return None # Parse hatası durumunda None döndür
167
  else:
168
  logger.info(f"Chat completion with ID {completion_id} not found in DB.")
169
  return None
 
163
  return final_entity
164
  except Exception as e:
165
  logger.error(f"Error parsing ChatCompletion from DB for id {completion_id}: {e}", exc_info=True)
166
+ return None
167
  else:
168
  logger.info(f"Chat completion with ID {completion_id} not found in DB.")
169
  return None
app/schema/chat_schema.py CHANGED
@@ -46,7 +46,6 @@ class ChoiceResponse(BaseModel):
46
  )
47
  index: Optional[int] = Field(None, description="The index of the choice in the list of choices.")
48
  message: Optional[ChatMessageResponse] = Field(None, description="The message to use for the chat completion")
49
- # logprobs: str = None # not implemented yet
50
 
51
 
52
  class ChatCompletionResponse(BaseModel):
@@ -60,7 +59,7 @@ class ChatCompletionResponse(BaseModel):
60
  model: Optional[str] = Field(None, description="The model used for the chat completion")
61
  # not implemented yet
62
  # service_tier: Optional[ServiceTier] = ServiceTier.AUTO
63
- # system_fingerprint: Optional[StrictStr] = Field(default=None, description="This fingerprint represents the backend configuration that the model runs with. Can be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism. ")
64
  # object: StrictStr = Field(description="The object type, which is always `chat.completion`.")
65
  # usage: Optional[CompletionUsage] = None
66
 
 
46
  )
47
  index: Optional[int] = Field(None, description="The index of the choice in the list of choices.")
48
  message: Optional[ChatMessageResponse] = Field(None, description="The message to use for the chat completion")
 
49
 
50
 
51
  class ChatCompletionResponse(BaseModel):
 
59
  model: Optional[str] = Field(None, description="The model used for the chat completion")
60
  # not implemented yet
61
  # service_tier: Optional[ServiceTier] = ServiceTier.AUTO
62
+ # system_fingerprint: Optional[StrictStr] = Field(default=None, description=This fingerprint represents the backend configuration that the model runs with. Can be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism.)
63
  # object: StrictStr = Field(description="The object type, which is always `chat.completion`.")
64
  # usage: Optional[CompletionUsage] = None
65
 
app/security/auth_service.py CHANGED
@@ -12,7 +12,7 @@ api_key_header = APIKeyHeader(
12
  name="Authorization",
13
  scheme_name="ApiKeyAuth",
14
  description="API key in the format: sk-{username}-{base64_encoded_data}",
15
- auto_error=False, # API key olmadığında otomatik hata vermesini engelle
16
  )
17
 
18
 
@@ -51,8 +51,6 @@ class AuthService:
51
  status_code=status.HTTP_401_UNAUTHORIZED,
52
  detail=f"Invalid API key data format: {str(e)}",
53
  )
54
-
55
- # Debug için JSON verilerini logla
56
  json_data = {
57
  "username": data["username"],
58
  "created_at": data["created_at"],
 
12
  name="Authorization",
13
  scheme_name="ApiKeyAuth",
14
  description="API key in the format: sk-{username}-{base64_encoded_data}",
15
+ auto_error=False,
16
  )
17
 
18
 
 
51
  status_code=status.HTTP_401_UNAUTHORIZED,
52
  detail=f"Invalid API key data format: {str(e)}",
53
  )
 
 
54
  json_data = {
55
  "username": data["username"],
56
  "created_at": data["created_at"],
app/service/chat_service.py CHANGED
@@ -124,12 +124,12 @@ class ChatService:
124
  else:
125
  logger.info("Update existing chat completion with new user request message")
126
 
127
- logger.debug(f"before update. current db entity messsage count: {len(current_db_entity.messages)}")
128
  current_db_entity.messages.append(last_user_message_model)
129
- logger.debug(f"after update. current db entity messsage count: {len(current_db_entity.messages)}")
130
  current_db_entity.last_updated_date = datetime.datetime.now()
131
  final_entity = await self.chat_repository.update(current_db_entity)
132
- logger.debug(f"after update. final entity messsage count: {len(final_entity.messages)}")
133
 
134
  # Convert model to response
135
  result = self.chat_mapper.to_schema(final_entity, convert_last_message=True)
 
124
  else:
125
  logger.info("Update existing chat completion with new user request message")
126
 
127
+ logger.trace(f"before update. current db entity messages count: {len(current_db_entity.messages)}")
128
  current_db_entity.messages.append(last_user_message_model)
129
+ logger.trace(f"after update. current db entity messages count: {len(current_db_entity.messages)}")
130
  current_db_entity.last_updated_date = datetime.datetime.now()
131
  final_entity = await self.chat_repository.update(current_db_entity)
132
+ logger.trace(f"after update. final entity messages count: {len(final_entity.messages)}")
133
 
134
  # Convert model to response
135
  result = self.chat_mapper.to_schema(final_entity, convert_last_message=True)
gradio_chatbot.py CHANGED
@@ -13,7 +13,7 @@ import plotly.graph_objects as go
13
  env = environs.Env()
14
  env.read_env()
15
 
16
- # Hugging Face Spaces için özel yapılandırma
17
  IS_HF_SPACE = os.environ.get("SPACE_ID") is not None
18
  SPACE_URL = "https://lokumai-openai-openapi-template.hf.space" if IS_HF_SPACE else "http://localhost:7860"
19
 
 
13
  env = environs.Env()
14
  env.read_env()
15
 
16
+ # special handling for Hugging Face Space
17
  IS_HF_SPACE = os.environ.get("SPACE_ID") is not None
18
  SPACE_URL = "https://lokumai-openai-openapi-template.hf.space" if IS_HF_SPACE else "http://localhost:7860"
19
 
main.py CHANGED
@@ -21,7 +21,7 @@ env.read_env()
21
 
22
  DB_DATABASE_TYPE = env.str("DB_DATABASE_TYPE", "mongodb")
23
 
24
- # Hugging Face Spaces için özel yapılandırma
25
  IS_HF_SPACE = os.environ.get("SPACE_ID") is not None
26
  SPACE_URL = "https://lokumai-openai-openapi-template.hf.space" if IS_HF_SPACE else "http://localhost:7860"
27
 
 
21
 
22
  DB_DATABASE_TYPE = env.str("DB_DATABASE_TYPE", "mongodb")
23
 
24
+ # special handling for Hugging Face Space
25
  IS_HF_SPACE = os.environ.get("SPACE_ID") is not None
26
  SPACE_URL = "https://lokumai-openai-openapi-template.hf.space" if IS_HF_SPACE else "http://localhost:7860"
27
 
resources/mock/message.md CHANGED
@@ -1,15 +1,15 @@
1
  ## Result
2
- |status|count|
3
- |---|---|
4
- |active|100|
5
- |cancelled|30|
6
- |pending|40|
7
- |passive|150|
8
 
9
  ## Explanation
10
  This 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?"
11
 
12
  ## Query
13
- ```sql
14
  SELECT status, COUNT(*) FROM customers WHERE year = 2025 GROUP BY status;
15
  ```
 
1
  ## Result
2
+ | status | count |
3
+ |-----------|-------|
4
+ | active | 100 |
5
+ | cancelled | 30 |
6
+ | pending | 40 |
7
+ | passive | 150 |
8
 
9
  ## Explanation
10
  This 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?"
11
 
12
  ## Query
13
+ ``sql
14
  SELECT status, COUNT(*) FROM customers WHERE year = 2025 GROUP BY status;
15
  ```
run.sh CHANGED
@@ -1,18 +1,18 @@
1
  #!/bin/bash
2
 
3
- # Önce eski uygulamayı durdur
4
  echo "Stopping existing application..."
5
  pkill -f "uvicorn main:app"
6
 
7
- # 2 saniye bekle
8
  sleep 2
9
 
10
- # FastAPI uygulamasını başlat (Gradio entegre edilmiş)
11
  echo "Starting application..."
12
  uv run uvicorn main:app --host 0.0.0.0 --port 7860 --reload
13
 
14
- # Ctrl+C ile durdurma işlemini yakala
15
  trap "echo 'Stopping application...'; pkill -f 'uvicorn main:app'; exit" INT
16
 
17
- # Uygulamanın çalışmasını bekle
18
  wait
 
1
  #!/bin/bash
2
 
3
+ # stop existing application if running
4
  echo "Stopping existing application..."
5
  pkill -f "uvicorn main:app"
6
 
7
+ # wait for the process to stop
8
  sleep 2
9
 
10
+ # start FastAPI application with uvicorn integrated Gradio Application
11
  echo "Starting application..."
12
  uv run uvicorn main:app --host 0.0.0.0 --port 7860 --reload
13
 
14
+ # catch SIGINT (Ctrl+C) to stop the application gracefully
15
  trap "echo 'Stopping application...'; pkill -f 'uvicorn main:app'; exit" INT
16
 
17
+ # wait for the application to run
18
  wait
scripts/api_key_genenerator.py CHANGED
@@ -24,7 +24,7 @@ from loguru import logger
24
  logger.add("logs/api_key_generator.log")
25
 
26
 
27
- def generate_api_key(username: str, secret_key: str) -> str:
28
  """
29
  Generates an API key for the given username using a secret key.
30
 
@@ -39,7 +39,6 @@ def generate_api_key(username: str, secret_key: str) -> str:
39
  timestamp = int(datetime.now().timestamp())
40
  data = {"username": username, "created_at": timestamp}
41
 
42
- # Debug için JSON verilerini logla
43
  json_data = {"username": username, "created_at": timestamp}
44
  json_str = json.dumps(json_data)
45
  logger.debug(f"JSON data for signature: {json_str}")
 
24
  logger.add("logs/api_key_generator.log")
25
 
26
 
27
+ def generate_api_key(username: str, secret_key: str) -> tuple[str, int]:
28
  """
29
  Generates an API key for the given username using a secret key.
30
 
 
39
  timestamp = int(datetime.now().timestamp())
40
  data = {"username": username, "created_at": timestamp}
41
 
 
42
  json_data = {"username": username, "created_at": timestamp}
43
  json_str = json.dumps(json_data)
44
  logger.debug(f"JSON data for signature: {json_str}")