Enhance smoking tracking API with new features and improvements

- Added a new API endpoint `GET /api/v1/smoke/home` to consolidate core modules for the home dashboard, reducing the need for multiple requests.
- Updated the `smoke` routes to include the new home endpoint and improved user profile management with the addition of a `quit_date` field.
- Enhanced the algorithm for calculating daily targets and next smoke suggestions, ensuring accurate future time handling and user-specific recommendations.
- Improved API documentation to reflect new endpoints, response formats, and detailed field descriptions for better clarity and usability.
- Refactored user authentication handling in various handlers to streamline the process and ensure consistent error responses.
This commit is contained in:
nepiedg
2026-01-29 17:16:35 +00:00
parent 3154365ab2
commit 9200600b1c
21 changed files with 703 additions and 178 deletions
@@ -44,12 +44,12 @@ func NewSmokeAINextSmokeService(db *gorm.DB, cfg config.AIConfig) *SmokeAINextSm
}
type aiNextSmokeInput struct {
AsOf string `json:"as_of"`
PlanDate string `json:"plan_date"`
MinNotBeforeAt string `json:"min_not_before_at"`
AsOf string `json:"as_of"`
PlanDate string `json:"plan_date"`
MinNotBeforeAt string `json:"min_not_before_at"`
DefaultSuggestion NextSmokeSuggestion `json:"default_suggestion"`
Profile *adviceUserProfile `json:"profile,omitempty"`
Recent3Days []recentDaySnapshot `json:"recent_3_days"`
Profile *adviceUserProfile `json:"profile,omitempty"`
Recent3Days []recentDaySnapshot `json:"recent_3_days"`
}
type aiNextSmokeOutput struct {
@@ -75,14 +75,14 @@ type recentDayNode struct {
}
type AINextSmokeSuggestion struct {
PlanDate string `json:"plan_date"`
NotBeforeAt string `json:"not_before_at"`
SuggestedAt string `json:"suggested_at"`
TimeNodes []string `json:"time_nodes"`
Advice string `json:"advice"`
PromptVersion string `json:"prompt_version"`
Model string `json:"model,omitempty"`
Provider string `json:"provider,omitempty"`
PlanDate string `json:"plan_date"`
NotBeforeAt string `json:"not_before_at"`
SuggestedAt string `json:"suggested_at"`
TimeNodes []string `json:"time_nodes"`
Advice string `json:"advice"`
PromptVersion string `json:"prompt_version"`
Model string `json:"model,omitempty"`
Provider string `json:"provider,omitempty"`
}
func (s *SmokeAINextSmokeService) GetOrGenerate(ctx context.Context, user *usermodel.User, asOf time.Time, planDate time.Time, promptVersion string, defaultSuggestion NextSmokeSuggestion) (AINextSmokeSuggestion, error) {
@@ -122,12 +122,12 @@ func (s *SmokeAINextSmokeService) GetOrGenerate(ctx context.Context, user *userm
minNotBefore := s.computeMinNotBefore(asOf, planDate, defaultSuggestion, profile)
input := aiNextSmokeInput{
AsOf: asOf.In(time.Local).Format(time.RFC3339),
PlanDate: planDate.Format("2006-01-02"),
MinNotBeforeAt: minNotBefore.In(time.Local).Format(time.RFC3339),
DefaultSuggestion: defaultSuggestion,
Profile: profile,
Recent3Days: recent,
AsOf: asOf.In(time.Local).Format(time.RFC3339),
PlanDate: planDate.Format("2006-01-02"),
MinNotBeforeAt: minNotBefore.In(time.Local).Format(time.RFC3339),
DefaultSuggestion: defaultSuggestion,
Profile: profile,
Recent3Days: recent,
}
inputJSON, _ := json.Marshal(input)
@@ -402,7 +402,7 @@ func (s *SmokeAINextSmokeService) loadRecent3Days(ctx context.Context, uid int,
}
snap := ensure(day)
isResisted := l.Level == 0 && l.Num == 0
isResisted := l.Num == 0
if isResisted {
snap.ResistedCount++
} else if l.Num > 0 {