kamau1 commited on
Commit
d90fef6
Β·
1 Parent(s): 155ccbe

fix: update codebase for Pydantic v2 compatibility (BaseSettings, Config, validators)

Browse files
app/core/config.py CHANGED
@@ -3,9 +3,9 @@ Configuration management for Sema Chat API
3
  Environment-driven settings for flexible model backends
4
  """
5
 
6
- import os
7
  from typing import List, Optional
8
- from pydantic import BaseSettings, Field
 
9
  from dotenv import load_dotenv
10
 
11
  # Load environment variables from .env file
@@ -132,9 +132,10 @@ class Settings(BaseSettings):
132
  system_prompt_code: Optional[str] = Field(default=None, env="SYSTEM_PROMPT_CODE")
133
  system_prompt_creative: Optional[str] = Field(default=None, env="SYSTEM_PROMPT_CREATIVE")
134
 
135
- class Config:
136
- env_file = ".env"
137
- case_sensitive = False
 
138
 
139
  def get_system_prompt(self, prompt_type: str = "default") -> str:
140
  """Get system prompt based on type"""
 
3
  Environment-driven settings for flexible model backends
4
  """
5
 
 
6
  from typing import List, Optional
7
+ from pydantic import Field
8
+ from pydantic_settings import BaseSettings
9
  from dotenv import load_dotenv
10
 
11
  # Load environment variables from .env file
 
132
  system_prompt_code: Optional[str] = Field(default=None, env="SYSTEM_PROMPT_CODE")
133
  system_prompt_creative: Optional[str] = Field(default=None, env="SYSTEM_PROMPT_CREATIVE")
134
 
135
+ model_config = {
136
+ "env_file": ".env",
137
+ "case_sensitive": False
138
+ }
139
 
140
  def get_system_prompt(self, prompt_type: str = "default") -> str:
141
  """Get system prompt based on type"""
app/models/schemas.py CHANGED
@@ -2,21 +2,21 @@
2
  Pydantic models for request/response validation
3
  """
4
 
5
- from typing import List, Optional, Dict, Any, Union
6
- from pydantic import BaseModel, Field, validator
7
  from datetime import datetime
8
- import uuid
9
 
10
 
11
  class ChatMessage(BaseModel):
12
  """Individual chat message model"""
13
-
14
  role: str = Field(..., description="Message role: 'user' or 'assistant'")
15
  content: str = Field(..., description="Message content")
16
  timestamp: datetime = Field(default_factory=datetime.utcnow, description="Message timestamp")
17
  metadata: Optional[Dict[str, Any]] = Field(default=None, description="Additional message metadata")
18
-
19
- @validator('role')
 
20
  def validate_role(cls, v):
21
  if v not in ['user', 'assistant', 'system']:
22
  raise ValueError('Role must be user, assistant, or system')
@@ -25,7 +25,7 @@ class ChatMessage(BaseModel):
25
 
26
  class ChatRequest(BaseModel):
27
  """Chat request model"""
28
-
29
  message: str = Field(
30
  ...,
31
  description="User message",
@@ -63,7 +63,7 @@ class ChatRequest(BaseModel):
63
 
64
  class ChatResponse(BaseModel):
65
  """Chat response model"""
66
-
67
  message: str = Field(..., description="Assistant response message")
68
  session_id: str = Field(..., description="Session identifier")
69
  message_id: str = Field(..., description="Unique message identifier")
@@ -72,9 +72,9 @@ class ChatResponse(BaseModel):
72
  generation_time: float = Field(..., description="Time taken to generate response (seconds)")
73
  token_count: Optional[int] = Field(default=None, description="Number of tokens in response")
74
  finish_reason: Optional[str] = Field(default=None, description="Reason generation finished")
75
-
76
- class Config:
77
- json_schema_extra = {
78
  "example": {
79
  "message": "Hello! I'm doing well, thank you for asking. How can I help you today?",
80
  "session_id": "user-123-session",
@@ -86,11 +86,12 @@ class ChatResponse(BaseModel):
86
  "finish_reason": "stop"
87
  }
88
  }
 
89
 
90
 
91
  class StreamChunk(BaseModel):
92
  """Streaming response chunk model"""
93
-
94
  content: str = Field(..., description="Chunk content")
95
  session_id: str = Field(..., description="Session identifier")
96
  message_id: str = Field(..., description="Message identifier")
@@ -101,15 +102,15 @@ class StreamChunk(BaseModel):
101
 
102
  class ConversationHistory(BaseModel):
103
  """Conversation history model"""
104
-
105
  session_id: str = Field(..., description="Session identifier")
106
  messages: List[ChatMessage] = Field(..., description="List of messages in conversation")
107
  created_at: datetime = Field(default_factory=datetime.utcnow, description="Session creation time")
108
  updated_at: datetime = Field(default_factory=datetime.utcnow, description="Last update time")
109
  message_count: int = Field(..., description="Total number of messages")
110
-
111
- class Config:
112
- json_schema_extra = {
113
  "example": {
114
  "session_id": "user-123-session",
115
  "messages": [
@@ -129,11 +130,12 @@ class ConversationHistory(BaseModel):
129
  "message_count": 2
130
  }
131
  }
 
132
 
133
 
134
  class SessionInfo(BaseModel):
135
  """Session information model"""
136
-
137
  session_id: str = Field(..., description="Session identifier")
138
  created_at: datetime = Field(..., description="Session creation time")
139
  updated_at: datetime = Field(..., description="Last activity time")
@@ -144,7 +146,7 @@ class SessionInfo(BaseModel):
144
 
145
  class HealthResponse(BaseModel):
146
  """Health check response model"""
147
-
148
  status: str = Field(..., description="API health status")
149
  version: str = Field(..., description="API version")
150
  model_type: str = Field(..., description="Current model backend type")
@@ -153,9 +155,9 @@ class HealthResponse(BaseModel):
153
  uptime: float = Field(..., description="API uptime in seconds")
154
  active_sessions: int = Field(..., description="Number of active chat sessions")
155
  timestamp: datetime = Field(default_factory=datetime.utcnow, description="Health check timestamp")
156
-
157
- class Config:
158
- json_schema_extra = {
159
  "example": {
160
  "status": "healthy",
161
  "version": "1.0.0",
@@ -167,19 +169,20 @@ class HealthResponse(BaseModel):
167
  "timestamp": "2024-01-15T10:30:00Z"
168
  }
169
  }
 
170
 
171
 
172
  class ErrorResponse(BaseModel):
173
  """Error response model"""
174
-
175
  error: str = Field(..., description="Error type")
176
  message: str = Field(..., description="Error message")
177
  details: Optional[Dict[str, Any]] = Field(default=None, description="Additional error details")
178
  timestamp: datetime = Field(default_factory=datetime.utcnow, description="Error timestamp")
179
  request_id: Optional[str] = Field(default=None, description="Request identifier for debugging")
180
-
181
- class Config:
182
- json_schema_extra = {
183
  "example": {
184
  "error": "validation_error",
185
  "message": "Message content is required",
@@ -188,19 +191,20 @@ class ErrorResponse(BaseModel):
188
  "request_id": "req-123-456"
189
  }
190
  }
 
191
 
192
 
193
  class ModelInfo(BaseModel):
194
  """Model information model"""
195
-
196
  name: str = Field(..., description="Model name")
197
  type: str = Field(..., description="Model backend type")
198
  loaded: bool = Field(..., description="Whether model is loaded")
199
  parameters: Optional[Dict[str, Any]] = Field(default=None, description="Model parameters")
200
  capabilities: List[str] = Field(default=[], description="Model capabilities")
201
-
202
- class Config:
203
- json_schema_extra = {
204
  "example": {
205
  "name": "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
206
  "type": "local",
@@ -213,3 +217,4 @@ class ModelInfo(BaseModel):
213
  "capabilities": ["chat", "instruction_following", "streaming"]
214
  }
215
  }
 
 
2
  Pydantic models for request/response validation
3
  """
4
 
5
+ from typing import List, Optional, Dict, Any
6
+ from pydantic import BaseModel, Field, field_validator, ConfigDict
7
  from datetime import datetime
 
8
 
9
 
10
  class ChatMessage(BaseModel):
11
  """Individual chat message model"""
12
+
13
  role: str = Field(..., description="Message role: 'user' or 'assistant'")
14
  content: str = Field(..., description="Message content")
15
  timestamp: datetime = Field(default_factory=datetime.utcnow, description="Message timestamp")
16
  metadata: Optional[Dict[str, Any]] = Field(default=None, description="Additional message metadata")
17
+
18
+ @field_validator('role')
19
+ @classmethod
20
  def validate_role(cls, v):
21
  if v not in ['user', 'assistant', 'system']:
22
  raise ValueError('Role must be user, assistant, or system')
 
25
 
26
  class ChatRequest(BaseModel):
27
  """Chat request model"""
28
+
29
  message: str = Field(
30
  ...,
31
  description="User message",
 
63
 
64
  class ChatResponse(BaseModel):
65
  """Chat response model"""
66
+
67
  message: str = Field(..., description="Assistant response message")
68
  session_id: str = Field(..., description="Session identifier")
69
  message_id: str = Field(..., description="Unique message identifier")
 
72
  generation_time: float = Field(..., description="Time taken to generate response (seconds)")
73
  token_count: Optional[int] = Field(default=None, description="Number of tokens in response")
74
  finish_reason: Optional[str] = Field(default=None, description="Reason generation finished")
75
+
76
+ model_config = ConfigDict(
77
+ json_schema_extra={
78
  "example": {
79
  "message": "Hello! I'm doing well, thank you for asking. How can I help you today?",
80
  "session_id": "user-123-session",
 
86
  "finish_reason": "stop"
87
  }
88
  }
89
+ )
90
 
91
 
92
  class StreamChunk(BaseModel):
93
  """Streaming response chunk model"""
94
+
95
  content: str = Field(..., description="Chunk content")
96
  session_id: str = Field(..., description="Session identifier")
97
  message_id: str = Field(..., description="Message identifier")
 
102
 
103
  class ConversationHistory(BaseModel):
104
  """Conversation history model"""
105
+
106
  session_id: str = Field(..., description="Session identifier")
107
  messages: List[ChatMessage] = Field(..., description="List of messages in conversation")
108
  created_at: datetime = Field(default_factory=datetime.utcnow, description="Session creation time")
109
  updated_at: datetime = Field(default_factory=datetime.utcnow, description="Last update time")
110
  message_count: int = Field(..., description="Total number of messages")
111
+
112
+ model_config = ConfigDict(
113
+ json_schema_extra={
114
  "example": {
115
  "session_id": "user-123-session",
116
  "messages": [
 
130
  "message_count": 2
131
  }
132
  }
133
+ )
134
 
135
 
136
  class SessionInfo(BaseModel):
137
  """Session information model"""
138
+
139
  session_id: str = Field(..., description="Session identifier")
140
  created_at: datetime = Field(..., description="Session creation time")
141
  updated_at: datetime = Field(..., description="Last activity time")
 
146
 
147
  class HealthResponse(BaseModel):
148
  """Health check response model"""
149
+
150
  status: str = Field(..., description="API health status")
151
  version: str = Field(..., description="API version")
152
  model_type: str = Field(..., description="Current model backend type")
 
155
  uptime: float = Field(..., description="API uptime in seconds")
156
  active_sessions: int = Field(..., description="Number of active chat sessions")
157
  timestamp: datetime = Field(default_factory=datetime.utcnow, description="Health check timestamp")
158
+
159
+ model_config = ConfigDict(
160
+ json_schema_extra={
161
  "example": {
162
  "status": "healthy",
163
  "version": "1.0.0",
 
169
  "timestamp": "2024-01-15T10:30:00Z"
170
  }
171
  }
172
+ )
173
 
174
 
175
  class ErrorResponse(BaseModel):
176
  """Error response model"""
177
+
178
  error: str = Field(..., description="Error type")
179
  message: str = Field(..., description="Error message")
180
  details: Optional[Dict[str, Any]] = Field(default=None, description="Additional error details")
181
  timestamp: datetime = Field(default_factory=datetime.utcnow, description="Error timestamp")
182
  request_id: Optional[str] = Field(default=None, description="Request identifier for debugging")
183
+
184
+ model_config = ConfigDict(
185
+ json_schema_extra={
186
  "example": {
187
  "error": "validation_error",
188
  "message": "Message content is required",
 
191
  "request_id": "req-123-456"
192
  }
193
  }
194
+ )
195
 
196
 
197
  class ModelInfo(BaseModel):
198
  """Model information model"""
199
+
200
  name: str = Field(..., description="Model name")
201
  type: str = Field(..., description="Model backend type")
202
  loaded: bool = Field(..., description="Whether model is loaded")
203
  parameters: Optional[Dict[str, Any]] = Field(default=None, description="Model parameters")
204
  capabilities: List[str] = Field(default=[], description="Model capabilities")
205
+
206
+ model_config = ConfigDict(
207
+ json_schema_extra={
208
  "example": {
209
  "name": "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
210
  "type": "local",
 
217
  "capabilities": ["chat", "instruction_following", "streaming"]
218
  }
219
  }
220
+ )
fix_deployment.md ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # πŸ”§ Quick Fix for HuggingFace Deployment
2
+
3
+ ## ❌ **Issue Identified**
4
+ The build failed due to **Pydantic v2 compatibility issues**:
5
+ - `BaseSettings` moved to `pydantic-settings` package
6
+ - `Config` class syntax changed to `model_config`
7
+ - `@validator` changed to `@field_validator`
8
+
9
+ ## βœ… **Fixes Applied**
10
+
11
+ ### 1. Updated requirements.txt
12
+ ```diff
13
+ + pydantic-settings
14
+ ```
15
+
16
+ ### 2. Fixed app/core/config.py
17
+ ```diff
18
+ - from pydantic import BaseSettings, Field
19
+ + from pydantic import Field
20
+ + from pydantic_settings import BaseSettings
21
+
22
+ - class Config:
23
+ - env_file = ".env"
24
+ - case_sensitive = False
25
+ + model_config = {
26
+ + "env_file": ".env",
27
+ + "case_sensitive": False
28
+ + }
29
+ ```
30
+
31
+ ### 3. Fixed app/models/schemas.py
32
+ ```diff
33
+ - from pydantic import BaseModel, Field, validator
34
+ + from pydantic import BaseModel, Field, field_validator, ConfigDict
35
+
36
+ - @validator('role')
37
+ - def validate_role(cls, v):
38
+ + @field_validator('role')
39
+ + @classmethod
40
+ + def validate_role(cls, v):
41
+
42
+ - class Config:
43
+ - json_schema_extra = {...}
44
+ + model_config = ConfigDict(
45
+ + json_schema_extra={...}
46
+ + )
47
+ ```
48
+
49
+ ## πŸš€ **Quick Deployment Fix**
50
+
51
+ ### Option 1: Update Your Existing Space
52
+ 1. Go to your HuggingFace Space: https://huggingface.co/spaces/sematech/sema-chat
53
+ 2. Click "Files" tab
54
+ 3. Update these files with the fixed versions:
55
+ - `requirements.txt`
56
+ - `app/core/config.py`
57
+ - `app/models/schemas.py`
58
+
59
+ ### Option 2: Re-run Setup Script
60
+ ```bash
61
+ cd backend/sema-chat
62
+ ./setup_huggingface.sh
63
+ ```
64
+ Then push the updated files to your Space.
65
+
66
+ ### Option 3: Manual Git Update
67
+ ```bash
68
+ # Clone your space
69
+ git clone https://huggingface.co/spaces/sematech/sema-chat
70
+ cd sema-chat
71
+
72
+ # Copy fixed files
73
+ cp /path/to/sema/backend/sema-chat/requirements.txt .
74
+ cp /path/to/sema/backend/sema-chat/app/core/config.py app/core/
75
+ cp /path/to/sema/backend/sema-chat/app/models/schemas.py app/models/
76
+
77
+ # Commit and push
78
+ git add .
79
+ git commit -m "Fix Pydantic v2 compatibility issues
80
+
81
+ - Add pydantic-settings dependency
82
+ - Update BaseSettings import
83
+ - Fix Config class syntax
84
+ - Update validator decorators"
85
+ git push
86
+ ```
87
+
88
+ ## 🎯 **Environment Variables for Gemma**
89
+
90
+ Make sure these are set in your Space settings:
91
+ ```
92
+ MODEL_TYPE=local
93
+ MODEL_NAME=google/gemma-2b-it
94
+ DEVICE=cpu
95
+ TEMPERATURE=0.7
96
+ MAX_NEW_TOKENS=256
97
+ DEBUG=false
98
+ ENVIRONMENT=production
99
+ ```
100
+
101
+ **Alternative (API-based):**
102
+ ```
103
+ MODEL_TYPE=google
104
+ MODEL_NAME=gemma-2-9b-it
105
+ GOOGLE_API_KEY=your_google_api_key_here
106
+ DEBUG=false
107
+ ENVIRONMENT=production
108
+ ```
109
+
110
+ ## πŸ§ͺ **Test After Fix**
111
+
112
+ Once the Space rebuilds successfully:
113
+ ```bash
114
+ # Health check
115
+ curl https://sematech-sema-chat.hf.space/health
116
+
117
+ # Chat test
118
+ curl -X POST "https://sematech-sema-chat.hf.space/api/v1/chat" \
119
+ -H "Content-Type: application/json" \
120
+ -d '{"message": "Hello! Can you introduce yourself?", "session_id": "test"}'
121
+ ```
122
+
123
+ ## πŸ“‹ **Build Status**
124
+ - ❌ **Before**: Pydantic import errors
125
+ - βœ… **After**: Should build successfully with Pydantic v2
126
+
127
+ The fixes ensure compatibility with the latest Pydantic version while maintaining all functionality.
128
+
129
+ ---
130
+
131
+ **Your Space should now deploy successfully! πŸš€**
requirements.txt CHANGED
@@ -1,6 +1,7 @@
1
  fastapi
2
  uvicorn
3
  pydantic
 
4
  python-multipart
5
  websockets
6
  sse-starlette
@@ -23,6 +24,5 @@ openai
23
  anthropic
24
 
25
  # Utilities
26
- uuid
27
  asyncio-mqtt
28
  redis
 
1
  fastapi
2
  uvicorn
3
  pydantic
4
+ pydantic-settings
5
  python-multipart
6
  websockets
7
  sse-starlette
 
24
  anthropic
25
 
26
  # Utilities
 
27
  asyncio-mqtt
28
  redis