Skip to content

Commit 65b491d

Browse files
committed
refactor: reformat using black
1 parent 95d3a8d commit 65b491d

File tree

19 files changed

+390
-281
lines changed

19 files changed

+390
-281
lines changed

chatbot-api/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"""ChatBot API package"""
1+
"""ChatBot API package"""

chatbot-api/conftest.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ def setup_test_env():
99
"""Automatically set up test environment variables before each test"""
1010
# Load test environment variables
1111
load_dotenv()
12-
12+
1313
# Set up test environment variables
14-
os.environ['OPENAI_API_KEY'] = 'test-api-key'
15-
os.environ['OPENAI_API_BASE'] = 'https://test-api-base.com'
16-
14+
os.environ["OPENAI_API_KEY"] = "test-api-key"
15+
os.environ["OPENAI_API_BASE"] = "https://test-api-base.com"
16+
1717
yield
18-
18+
1919
# Clean up after tests
20-
if 'OPENAI_API_KEY' in os.environ:
21-
del os.environ['OPENAI_API_KEY']
22-
if 'OPENAI_API_BASE' in os.environ:
23-
del os.environ['OPENAI_API_BASE']
20+
if "OPENAI_API_KEY" in os.environ:
21+
del os.environ["OPENAI_API_KEY"]
22+
if "OPENAI_API_BASE" in os.environ:
23+
del os.environ["OPENAI_API_BASE"]

chatbot-api/src/chat/models.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,29 @@
22
from typing import List, Optional, Union, Dict
33
from datetime import datetime
44

5+
56
@dataclass
67
class ImageContent:
78
type: str = "image_url"
89
image_url: Dict[str, str] = None
910

11+
1012
@dataclass
1113
class TextContent:
1214
type: str = "text"
1315
text: str = ""
1416

17+
1518
@dataclass
1619
class Message:
1720
role: str
1821
content: Union[str, List[Union[TextContent, ImageContent]]]
1922
model: Optional[str] = None
2023
timestamp: datetime = datetime.utcnow()
2124

25+
2226
@dataclass
2327
class ChatResponse:
2428
content: str
2529
model: str
26-
timestamp: datetime = datetime.utcnow()
30+
timestamp: datetime = datetime.utcnow()

chatbot-api/src/chat/provider.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,67 +6,71 @@
66

77
logger = logging.getLogger(__name__)
88

9+
910
class AIProvider(Protocol):
1011
"""Protocol for AI providers"""
12+
1113
def generate_response(self, messages: List[Message]) -> ChatResponse: ...
1214
def generate_stream(self, messages: List[Message]) -> AsyncIterator[str]: ...
1315

16+
1417
class OpenAIProvider:
1518
"""OpenAI implementation of AIProvider"""
19+
1620
def __init__(self, api_key: str, api_base: str | None = None):
1721
self.client = OpenAI(api_key=api_key, base_url=api_base)
1822

1923
def _format_message(self, message: Message) -> dict:
2024
"""Format message for OpenAI API"""
2125
if isinstance(message.content, str):
2226
return {"role": message.role, "content": message.content}
23-
27+
2428
# For messages with text and images
2529
formatted_content = []
2630
for item in message.content:
2731
if isinstance(item, TextContent):
2832
formatted_content.append({"type": "text", "text": item.text})
2933
elif isinstance(item, ImageContent):
30-
formatted_content.append({
31-
"type": "image_url",
32-
"image_url": item.image_url
33-
})
34+
formatted_content.append(
35+
{"type": "image_url", "image_url": item.image_url}
36+
)
3437
return {"role": message.role, "content": formatted_content}
3538

3639
def generate_response(self, messages: List[Message]) -> ChatResponse:
3740
"""Generate a response for messages"""
3841
# Use the model from the last message, or default to claude-3-5-sonnet
39-
model = next((m.model for m in reversed(messages) if m.model), "claude-3-5-sonnet")
40-
42+
model = next(
43+
(m.model for m in reversed(messages) if m.model), "claude-3-5-sonnet"
44+
)
45+
4146
formatted_messages = [self._format_message(m) for m in messages]
4247
response = self.client.chat.completions.create(
43-
model=model,
44-
messages=formatted_messages
48+
model=model, messages=formatted_messages
4549
)
46-
50+
4751
return ChatResponse(
4852
content=response.choices[0].message.content,
4953
model=response.model,
50-
timestamp=datetime.utcnow()
54+
timestamp=datetime.utcnow(),
5155
)
5256

5357
async def generate_stream(self, messages: List[Message]) -> AsyncIterator[str]:
5458
"""Stream response for messages"""
5559
try:
5660
# Use the model from the last message, or default to claude-3-5-sonnet
57-
model = next((m.model for m in reversed(messages) if m.model), "claude-3-5-sonnet")
58-
61+
model = next(
62+
(m.model for m in reversed(messages) if m.model), "claude-3-5-sonnet"
63+
)
64+
5965
formatted_messages = [self._format_message(m) for m in messages]
6066
stream = self.client.chat.completions.create(
61-
model=model,
62-
messages=formatted_messages,
63-
stream=True
67+
model=model, messages=formatted_messages, stream=True
6468
)
65-
69+
6670
for chunk in stream:
6771
if chunk.choices[0].delta.content:
6872
content = chunk.choices[0].delta.content
6973
yield content
7074
except Exception as e:
7175
logger.error(f"Error in stream: {str(e)}")
72-
raise
76+
raise

chatbot-api/src/chat/routes.py

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
from fastapi import APIRouter, Depends
22
from fastapi.responses import StreamingResponse
33
from typing import List, Union, Dict
4-
from .schemas import ChatRequestSchema, ChatResponseSchema, MessageSchema, TextContentSchema, ImageContentSchema
4+
from .schemas import (
5+
ChatRequestSchema,
6+
ChatResponseSchema,
7+
MessageSchema,
8+
TextContentSchema,
9+
ImageContentSchema,
10+
)
511
from .service import ChatService
612
from .models import Message, TextContent, ImageContent
713
from datetime import datetime
@@ -12,30 +18,32 @@
1218

1319
router = APIRouter(prefix="/chat", tags=["chat"])
1420

21+
1522
async def get_chat_service() -> ChatService:
1623
# This will be overridden in main.py
1724
raise NotImplementedError("Chat service not configured")
1825

26+
1927
def extract_message_content(message: MessageSchema) -> tuple[str, List[str]]:
2028
"""Extract text and image URLs from a message"""
2129
if isinstance(message.content, str):
2230
return message.content, []
23-
31+
2432
text = ""
2533
images = []
26-
34+
2735
for content in message.content:
2836
if content.type == "text":
2937
text = content.text
3038
elif content.type == "image_url":
3139
images.append(content.image_url.url)
32-
40+
3341
return text, images
3442

43+
3544
@router.post("/", response_model=ChatResponseSchema)
3645
async def chat(
37-
request: ChatRequestSchema,
38-
chat_service: ChatService = Depends(get_chat_service)
46+
request: ChatRequestSchema, chat_service: ChatService = Depends(get_chat_service)
3947
) -> ChatResponseSchema:
4048
# Convert request messages to domain models
4149
messages = []
@@ -44,36 +52,37 @@ async def chat(
4452
content = msg.content
4553
else:
4654
content = [
47-
TextContent(text=c.text) if c.type == "text"
48-
else ImageContent(image_url={"url": c.image_url.url})
55+
(
56+
TextContent(text=c.text)
57+
if c.type == "text"
58+
else ImageContent(image_url={"url": c.image_url.url})
59+
)
4960
for c in msg.content
5061
]
51-
messages.append(Message(
52-
role=msg.role,
53-
content=content,
54-
model=msg.model,
55-
timestamp=msg.timestamp or datetime.utcnow()
56-
))
57-
62+
messages.append(
63+
Message(
64+
role=msg.role,
65+
content=content,
66+
model=msg.model,
67+
timestamp=msg.timestamp or datetime.utcnow(),
68+
)
69+
)
70+
5871
# Extract content from the last message
5972
text, images = extract_message_content(request.messages[-1])
60-
73+
6174
response = await chat_service.process_message(
62-
text=text,
63-
images=images,
64-
conversation_messages=messages
75+
text=text, images=images, conversation_messages=messages
6576
)
66-
77+
6778
return ChatResponseSchema(
68-
reply=response.content,
69-
model=response.model,
70-
timestamp=response.timestamp
79+
reply=response.content, model=response.model, timestamp=response.timestamp
7180
)
7281

82+
7383
@router.post("/stream")
7484
async def stream_chat(
75-
request: ChatRequestSchema,
76-
chat_service: ChatService = Depends(get_chat_service)
85+
request: ChatRequestSchema, chat_service: ChatService = Depends(get_chat_service)
7786
):
7887
# Convert request messages to domain models
7988
messages = []
@@ -82,26 +91,29 @@ async def stream_chat(
8291
content = msg.content
8392
else:
8493
content = [
85-
TextContent(text=c.text) if c.type == "text"
86-
else ImageContent(image_url={"url": c.image_url.url})
94+
(
95+
TextContent(text=c.text)
96+
if c.type == "text"
97+
else ImageContent(image_url={"url": c.image_url.url})
98+
)
8799
for c in msg.content
88100
]
89-
messages.append(Message(
90-
role=msg.role,
91-
content=content,
92-
model=msg.model,
93-
timestamp=msg.timestamp or datetime.utcnow()
94-
))
95-
101+
messages.append(
102+
Message(
103+
role=msg.role,
104+
content=content,
105+
model=msg.model,
106+
timestamp=msg.timestamp or datetime.utcnow(),
107+
)
108+
)
109+
96110
# Extract content from the last message
97111
text, images = extract_message_content(request.messages[-1])
98112

99113
async def generate():
100114
try:
101115
async for chunk in chat_service.stream_response(
102-
text=text,
103-
images=images,
104-
conversation_messages=messages
116+
text=text, images=images, conversation_messages=messages
105117
):
106118
yield f"data: {json.dumps({'content': chunk})}\n\n"
107119
except Exception as e:
@@ -114,6 +126,6 @@ async def generate():
114126
headers={
115127
"Cache-Control": "no-cache",
116128
"Connection": "keep-alive",
117-
"X-Accel-Buffering": "no"
118-
}
119-
)
129+
"X-Accel-Buffering": "no",
130+
},
131+
)

chatbot-api/src/chat/schemas.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,39 @@
22
from typing import List, Optional, Union, Dict
33
from datetime import datetime
44

5+
56
class ImageUrlSchema(BaseModel):
67
url: str
78
model_config = ConfigDict(from_attributes=True)
89

10+
911
class ImageContentSchema(BaseModel):
1012
type: str = "image_url"
1113
image_url: ImageUrlSchema
1214
model_config = ConfigDict(from_attributes=True)
1315

16+
1417
class TextContentSchema(BaseModel):
1518
type: str = "text"
1619
text: str
1720
model_config = ConfigDict(from_attributes=True)
1821

22+
1923
class MessageSchema(BaseModel):
2024
role: str
2125
content: Union[str, List[Union[TextContentSchema, ImageContentSchema]]]
2226
model: Optional[str] = None
2327
timestamp: Optional[datetime] = None
2428
model_config = ConfigDict(from_attributes=True)
2529

30+
2631
class ChatRequestSchema(BaseModel):
2732
messages: List[MessageSchema]
2833
model_config = ConfigDict(from_attributes=True)
2934

35+
3036
class ChatResponseSchema(BaseModel):
3137
reply: str
3238
model: str
3339
timestamp: datetime
34-
model_config = ConfigDict(from_attributes=True)
40+
model_config = ConfigDict(from_attributes=True)

0 commit comments

Comments
 (0)